Fortinet Ansible Module Documentation - DEPRECATED

These Ansible “base code” modules have been superseded by the new Ansible Galaxy Collections for FortiOS and FortiManager, and are no longer included in Ansible as of version 2.10.

Redhat has removed all vendor/partner modules from the Ansible Base Code, and moved everyone to Ansible Galaxy Collections.

Active maintenance and development for these “base code” modules has ended, and the new collections are to be used going forward, which is the new active project from Fortinet Engineering.

FortiManager - DEPRECATED

These Ansible “base code” modules have been superseded by the new Ansible Galaxy Collections for FortiOS and FortiManager, and are no longer included in Ansible as of version 2.10.

Redhat has removed all vendor/partner modules from the Ansible Base Code, and moved everyone to Ansible Galaxy Collections.

Active maintenance and development for these “base code” modules has ended, and the new collections are to be used going forward, which is the new active project from Fortinet Engineering.

These Ansible “base code” modules have been superseded by the new Ansible Galaxy Collections for FortiOS and FortiManager, and are no longer included in Ansible as of version 2.10.

Redhat has removed all vendor/partner modules from the Ansible Base Code, and moved everyone to Ansible Galaxy Collections.

Active maintenance and development for these “base code” modules has ended, and the new collections are to be used going forward, which is the new active project from Fortinet Engineering.

Introduction

Beginning in Q1 of 2019 all up-to-date FortiManager modules now utilize a connection-plugin. Existing installations must convert going forward.

  • This requires modification to existing playbooks and inventory files that used the previous “connection: local” versions of FortiManager Plugins.
    • Follow the upgrade path defined below to utilize the new plugin.
  • All updated modules, module_utils, and plugin will be included in Ansible 2.8 when it is released.

Pre-Requisites

  • Minimum Ansible Version: 2.7+
  • Minimum Python Version: 2.7+
    • Works with Python 3.x
  • Minimum FortiManager Version: 6.0+
  • FortiManager account with rpc read/write enabled via CLI
  • A licensed FortiManager appliance or VM.

Fresh Installation

Step 1 - Auto Installation Method

After about 05-16-2019, the most recent versions of FortiManager ansible components will be available from a simple software package manager update or install of Ansible.

After install, run the following command:

ansible --version

If the version is below 2.8, proceed to step 2.

If the version is 2.8+, skip to step 3.

Step 2 (Optional) - Manual Installation Method

Summary
  • Until about 05-16-2019, the most recent versions of FortiManager ansible components must be manually installed to an existing Ansible 2.7+ installation.
  • Fortinet may make updates to Ansible components in-between Ansible release dates, and they can be installed in-between Ansible release schedules, manually.
  • These most-recent versions are located on the official FNDN github repo here: https://github.com/ftntcorecse/fndn_ansible
Steps
  • First, make sure Ansible is already installed, and shows version 2.7+.
  • The plugin and module_utils need to be copied to their correct locations. On Ubuntu running Python 2.7, the paths are:
/usr/lib/python2.7/dist-packages/ansible/plugins/httpapi/
/usr/lib/python2.7/dist-packages/ansible/module_utils/network/fortimanager/
  • If you’re unsure where to find this path on your own system, run this command:
find /usr -name "ansible"

Step 3 - Inventory File

The following variables must be added to the hosts file entries that correspond to the FortiManager hosts:

  • ansible_host=<ip/host>
    • Which FortiManager to connect to.
  • ansible_network_os=fortimanager
    • Tells Ansible which httpapi plugin to search for
  • ansible_user=<fmgr_username>
  • ansible_password=<fmgr_password>
  • ansible_become=no
  • ansible_become_method=disable
  • ansible_httpapi_use_ssl=true
  • ansible_httpapi_validate_certs=false
    • Switch to True if using in production!
  • ansible_httpapi_timeout=300
    • Sometimes it takes a while for FortiManager to process large requests or scripts. A large timeout is preferred.
    • In seconds.

These parameters can be added on the same line, or nested as shown in the code block below:

[FortiManager]
10.7.220.35 ansible_host=10.7.220.35

[FortiManagerHA]
10.7.220.36 ansible_host=10.7.220.36

[fmgr_api:children]
FortiManager
FortiManagerHA

[fmgr_api:vars]
ansible_network_os=fortimanager
ansible_user=ansible
ansible_password=fortinet
ansible_become=no
ansible_become_method=disable
ansible_httpapi_use_ssl=true
ansible_httpapi_validate_certs=false
ansible_httpapi_timeout=300

Step 4 - Playbook Test

Ansible should be ready to test now. Copy the following code block into a file named “test_fmgr.yml”:

---
- name: FMGR CONNECTION GET SYS STATUS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
  - name: TEST FMGR CONNECTION GET SYS STATUS
    fmgr_query:
      adom: "root"
      object: "custom"
      custom_endpoint: "/sys/status"

… and then run it with the following command:

ansible-playbook test_fmgr.yml -vvvv

If successful, it should report OK with Green Text and show various information about the target FortiManager.

If not successful, double check the hosts file, username/password combo, and that RPC read/write has been enabled for the FortiManager user. The -vvvv verbose mode should indicate where the issue lies.

Upgrade to Connection Plugin

Because all new modules are converted to use the connection plugin, the old method of using pyFMG and connection:local in playbooks is deprecated.

All playbooks must be converted to use the new plugin, and a few additions to the inventory file are required.

Step 1 - Inventory File

The following variables must be added to the hosts file entries that correspond to the FortiManager hosts:

  • ansible_host=<ip/host>
    • Which FortiManager to connect to.
  • ansible_network_os=fortimanager
    • Tells Ansible which httpapi plugin to search for
  • ansible_user=<fmgr_username>
  • ansible_password=<fmgr_password>
  • ansible_become=no
  • ansible_become_method=disable
  • ansible_httpapi_use_ssl=true
  • ansible_httpapi_validate_certs=false
    • Switch to True if using in production!
  • ansible_httpapi_timeout=300
    • Sometimes it takes a while for FortiManager to process large requests or scripts. A large timeout is preferred.
    • In seconds.

These parameters can be added on the same line, or nested as shown in the code block below:

[FortiManager]
10.7.220.35 ansible_host=10.7.220.35

[FortiManagerHA]
10.7.220.36 ansible_host=10.7.220.36

[fmgr_api:children]
FortiManager
FortiManagerHA

[fmgr_api:vars]
ansible_network_os=fortimanager
ansible_user=ansible
ansible_password=fortinet
ansible_become=no
ansible_become_method=disable
ansible_httpapi_use_ssl=true
ansible_httpapi_validate_certs=false
ansible_httpapi_timeout=300

Because the host, username, and password have all been added to the connection/host level they must be removed from playbooks.

Step 2 - Playbook Conversion

Previous playbooks might look like this:

---
- name: CONFIG FGT HOSTNAME AND INTERFACE
  hosts: FortiManager
  connection: local
  gather_facts: False

  tasks:

  - name: CHANGE HOSTNAME
    fmgr_device_config:
      host: "{{ inventory_hostname }}"
      username: "{{ username }}"
      password: "{{ password }}"
      device_hostname: "ansible-fgt01"
      device_unique_name: "FGT1"
      adom: "ansible"
  • The host, username, and password lines from each task need to be deleted.
  • The heading attribute “connection: local” must be changed to “connection: httpapi”

Converted version of the above playbook:

---
- name: CONFIG FGT HOSTNAME AND INTERFACE
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: CHANGE HOSTNAME
    fmgr_device_config:
      device_hostname: "ansible-fgt01"
      device_unique_name: "FGT1"
      adom: "ansible"

Step 3a - Auto Installation Method

After about 05-16-2019, the most recent versions of FortiManager ansible components will be available from a simple software package manager update or install of Ansible.

Step 2 (Optional) - Manual Installation Method

Summary
  • Until about 05-16-2019, the most recent versions of FortiManager ansible components must be manually installed to an existing Ansible 2.7+ installation.
  • Fortinet may make updates to Ansible components in-between Ansible release dates, and they can be installed in-between Ansible release schedules, manually.
  • These most-recent versions are located on the official FNDN github repo here: https://github.com/ftntcorecse/fndn_ansible
Steps
  • First, make sure Ansible is already installed, and shows version 2.7+.
  • The plugin and module_utils need to be copied to their correct locations. On Ubuntu running Python 2.7, the paths are:
/usr/lib/python2.7/dist-packages/ansible/plugins/httpapi/
/usr/lib/python2.7/dist-packages/ansible/module_utils/network/fortimanager/
  • If you’re unsure where to find this path on your own system, run this command:
find /usr -name "ansible"

- ... and the path under a python dist-packages should present itself.

Step 4 - Playbook Test

After modifying the hosts inventory file, and either manually or automatically installing the latest FortiManager Ansible components, the converted playbooks from Step 2 should now run.

For a sample status check, copy the following code block into a file named “test_fmgr.yml”:

---
- name: FMGR CONNECTION GET SYS STATUS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
  - name: TEST FMGR CONNECTION GET SYS STATUS
    fmgr_query:
      adom: "root"
      object: "custom"
      custom_endpoint: "/sys/status"

… and then run it with the following command:

ansible-playbook test_fmgr.yml -vvvv

If successful, it should report OK with Green Text and show various information about the target FortiManager.

If not successful, double check the hosts file, username/password combo, and that RPC read/write has been enabled for the FortiManager user. The -vvvv verbose mode should indicate where the issue lies.

Using Ansible Vault to Hide Logins

There are many ways to implement Ansible Vault. Feel free to use any method desired. If no previous experience with Ansible Vault exists, we recommend starting with this method:

The procedure is simple:

  • Use ‘ansible-vault encrypt string’ on ansible host to create a vault string.
  • Replace vault string in HOSTS or Variables file, for the username/password or both.
fortimanager:
  ansible_user: "ansible"
  ansible_host: "10.7.220.35"
  ansible_password: !vault |
    $ANSIBLE_VAULT;1.1;AES256
    61366437333436393062623438393663366138633265363930313763383964313130643134383839
    3630663661626365366334646661303338313866373032330a636165373833366166616465373830
    34356466653464313134313664613435356238666139623165623132306538336565376265356633
    6362396137306466630a666562393637353863626436376132643464366661323734363830383164
    6366
  • Add a reference to the variable file/vault file from the playbook itself:
---
- name: Create and Delete security profile in FMG
  hosts: FortiManager
  connection: httpapi
  gather_facts: False
  vars_files:
    - group_vars/vault.yml
  • And then run playbooks with –ask-vault-pass, or setup a password file to provide it.

It is recommended to keep vault secret variables in their own files, so the un-encrypted variables could be read by peers.

Additional Ansible Vault tutorials, references, and alternative implementation methods:

Appendix

Enabling FortiManager user for RPC Read/Write via FMGR CLI

config system admin user
  edit <username>
  set rpc read-write
  next
end

Modules

fmgr_device

Metadata

Name: fmgr_device

Description: Add or remove a device or list of devices from FortiManager Device Manager using JSON RPC API.

Author(s):

  • Luke Weighall (github: @lweighall)
  • Andrew Welsh (github: @Ghilli3)
  • Jim Huber (github: @p4r4n0y1ng)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Luke Weighall

Module Github Link

Parameters
adom
  • Description: The ADOM the configuration should belong to.
  • Required: True
  • default: root
blind_add
  • Description: When adding a device, module will check if it exists, and skip if it does.

    If enabled, this option will stop the module from checking if it already exists, and blindly add the device.

  • Required: False

  • default: disable

  • choices: [‘enable’, ‘disable’]

device_ip
  • Description: The IP of the device being added to FortiManager. Supports both IPv4 and IPv6.
  • Required: False
device_password
  • Description: The password of the device being added to FortiManager.
  • Required: False
device_serial
  • Description: The serial number of the device being added to FortiManager.
  • Required: False
device_unique_name
  • Description: The desired “friendly” name of the device being added to FortiManager.
  • Required: False
device_username
  • Description: The username of the device being added to FortiManager.
  • Required: False
mode
  • Description: The desired mode of the specified object.
  • Required: False
  • default: add
  • choices: [‘add’, ‘delete’]
Functions
  • discover_device
def discover_device(fmgr, paramgram):
    """
    This method is used to discover devices before adding them to FMGR

    :param fmgr: The fmgr object instance from fmgr_utils.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict

    :return: The response from the FortiManager
    :rtype: dict
    """

    datagram = {
        "odd_request_form": "True",
        "device": {"adm_usr": paramgram["device_username"],
                   "adm_pass": paramgram["device_password"],
                   "ip": paramgram["device_ip"]}
    }

    url = '/dvm/cmd/discover/device/'

    response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
    return response
  • add_device
def add_device(fmgr, paramgram):
    """
    This method is used to add devices to the FMGR

    :param fmgr: The fmgr object instance from fmgr_utils.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict

    :return: The response from the FortiManager
    :rtype: dict
    """

    datagram = {
        "adom": paramgram["adom"],
        "flags": ["create_task", "nonblocking"],
        "odd_request_form": "True",
        "device": {"adm_usr": paramgram["device_username"], "adm_pass": paramgram["device_password"],
                   "ip": paramgram["device_ip"], "name": paramgram["device_unique_name"],
                   "sn": paramgram["device_serial"], "mgmt_mode": "fmgfaz", "flags": 24}
    }

    url = '/dvm/cmd/add/device/'
    response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
    return response
  • delete_device
def delete_device(fmgr, paramgram):
    """
    This method deletes a device from the FMGR

    :param fmgr: The fmgr object instance from fmgr_utils.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict

    :return: The response from the FortiManager
    :rtype: dict
    """
    datagram = {
        "adom": paramgram["adom"],
        "flags": ["create_task", "nonblocking"],
        "device": paramgram["device_unique_name"],
    }

    url = '/dvm/cmd/del/device/'
    response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
    return response
  • get_device
def get_device(fmgr, paramgram):
    """
    This method attempts to find the firewall on FortiManager to see if it already exists.

    :param fmgr: The fmgr object instance from fmgr_utils.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict

    :return: The response from the FortiManager
    :rtype: dict
    """
    datagram = {
        "adom": paramgram["adom"],
        "filter": ["name", "==", paramgram["device_unique_name"]],
    }

    url = '/dvmdb/adom/{adom}/device/{name}'.format(adom=paramgram["adom"],
                                                    name=paramgram["device_unique_name"])
    response = fmgr.process_request(url, datagram, FMGRMethods.GET)
    return response
  • main
def main():
    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        mode=dict(choices=["add", "delete"], type="str", default="add"),
        blind_add=dict(choices=["enable", "disable"], type="str", default="disable"),
        device_ip=dict(required=False, type="str"),
        device_username=dict(required=False, type="str"),
        device_password=dict(required=False, type="str", no_log=True),
        device_unique_name=dict(required=True, type="str"),
        device_serial=dict(required=False, type="str")
    )

    # BUILD MODULE OBJECT SO WE CAN BUILD THE PARAMGRAM
    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )

    # BUILD THE PARAMGRAM
    paramgram = {
        "device_ip": module.params["device_ip"],
        "device_username": module.params["device_username"],
        "device_password": module.params["device_password"],
        "device_unique_name": module.params["device_unique_name"],
        "device_serial": module.params["device_serial"],
        "adom": module.params["adom"],
        "mode": module.params["mode"]
    }

    # INSERT THE PARAMGRAM INTO THE MODULE SO WHEN WE PASS IT TO MOD_UTILS.FortiManagerHandler IT HAS THAT INFO
    module.paramgram = paramgram

    # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION
    results = DEFAULT_RESULT_OBJ
    try:
        if paramgram["mode"] == "add":
            # CHECK IF DEVICE EXISTS
            if module.params["blind_add"] == "disable":
                exists_results = get_device(fmgr, paramgram)
                fmgr.govern_response(module=module, results=exists_results, good_codes=(0, -3), changed=False,
                                     ansible_facts=fmgr.construct_ansible_facts(exists_results,
                                                                                module.params, paramgram))

            discover_results = discover_device(fmgr, paramgram)
            fmgr.govern_response(module=module, results=discover_results, stop_on_success=False,
                                 ansible_facts=fmgr.construct_ansible_facts(discover_results,
                                                                            module.params, paramgram))

            if discover_results[0] == 0:
                results = add_device(fmgr, paramgram)
                fmgr.govern_response(module=module, results=discover_results, stop_on_success=True,
                                     changed_if_success=True,
                                     ansible_facts=fmgr.construct_ansible_facts(discover_results,
                                                                                module.params, paramgram))

        if paramgram["mode"] == "delete":
            results = delete_device(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function

__metaclass__ = type

ANSIBLE_METADATA = {
    "metadata_version": "1.1",
    "status": ["preview"],
    "supported_by": "community"
}

DOCUMENTATION = '''
---
module: fmgr_device
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author:
    - Luke Weighall (@lweighall)
    - Andrew Welsh (@Ghilli3)
    - Jim Huber (@p4r4n0y1ng)
short_description: Add or remove device from FortiManager.
description:
  - Add or remove a device or list of devices from FortiManager Device Manager using JSON RPC API.

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: true
    default: root

  mode:
    description:
      - The desired mode of the specified object.
    required: false
    default: add
    choices: ["add", "delete"]

  blind_add:
    description:
      - When adding a device, module will check if it exists, and skip if it does.
      - If enabled, this option will stop the module from checking if it already exists, and blindly add the device.
    required: false
    default: "disable"
    choices: ["enable", "disable"]

  device_username:
    description:
      - The username of the device being added to FortiManager.
    required: false

  device_password:
    description:
      - The password of the device being added to FortiManager.
    required: false

  device_ip:
    description:
      - The IP of the device being added to FortiManager. Supports both IPv4 and IPv6.
    required: false

  device_unique_name:
    description:
      - The desired "friendly" name of the device being added to FortiManager.
    required: false

  device_serial:
    description:
      - The serial number of the device being added to FortiManager.
    required: false
'''

EXAMPLES = '''
- name: DISCOVER AND ADD DEVICE FGT1
  fmgr_device:
    adom: "root"
    device_username: "admin"
    device_password: "admin"
    device_ip: "10.10.24.201"
    device_unique_name: "FGT1"
    device_serial: "FGVM000000117994"
    mode: "add"
    blind_add: "enable"

- name: DISCOVER AND ADD DEVICE FGT2
  fmgr_device:
    adom: "root"
    device_username: "admin"
    device_password: "admin"
    device_ip: "10.10.24.202"
    device_unique_name: "FGT2"
    device_serial: "FGVM000000117992"
    mode: "delete"
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import FMGRMethods
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG


def discover_device(fmgr, paramgram):
    """
    This method is used to discover devices before adding them to FMGR

    :param fmgr: The fmgr object instance from fmgr_utils.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict

    :return: The response from the FortiManager
    :rtype: dict
    """

    datagram = {
        "odd_request_form": "True",
        "device": {"adm_usr": paramgram["device_username"],
                   "adm_pass": paramgram["device_password"],
                   "ip": paramgram["device_ip"]}
    }

    url = '/dvm/cmd/discover/device/'

    response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
    return response


def add_device(fmgr, paramgram):
    """
    This method is used to add devices to the FMGR

    :param fmgr: The fmgr object instance from fmgr_utils.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict

    :return: The response from the FortiManager
    :rtype: dict
    """

    datagram = {
        "adom": paramgram["adom"],
        "flags": ["create_task", "nonblocking"],
        "odd_request_form": "True",
        "device": {"adm_usr": paramgram["device_username"], "adm_pass": paramgram["device_password"],
                   "ip": paramgram["device_ip"], "name": paramgram["device_unique_name"],
                   "sn": paramgram["device_serial"], "mgmt_mode": "fmgfaz", "flags": 24}
    }

    url = '/dvm/cmd/add/device/'
    response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
    return response


def delete_device(fmgr, paramgram):
    """
    This method deletes a device from the FMGR

    :param fmgr: The fmgr object instance from fmgr_utils.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict

    :return: The response from the FortiManager
    :rtype: dict
    """
    datagram = {
        "adom": paramgram["adom"],
        "flags": ["create_task", "nonblocking"],
        "device": paramgram["device_unique_name"],
    }

    url = '/dvm/cmd/del/device/'
    response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
    return response


def get_device(fmgr, paramgram):
    """
    This method attempts to find the firewall on FortiManager to see if it already exists.

    :param fmgr: The fmgr object instance from fmgr_utils.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict

    :return: The response from the FortiManager
    :rtype: dict
    """
    datagram = {
        "adom": paramgram["adom"],
        "filter": ["name", "==", paramgram["device_unique_name"]],
    }

    url = '/dvmdb/adom/{adom}/device/{name}'.format(adom=paramgram["adom"],
                                                    name=paramgram["device_unique_name"])
    response = fmgr.process_request(url, datagram, FMGRMethods.GET)
    return response


def main():
    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        mode=dict(choices=["add", "delete"], type="str", default="add"),
        blind_add=dict(choices=["enable", "disable"], type="str", default="disable"),
        device_ip=dict(required=False, type="str"),
        device_username=dict(required=False, type="str"),
        device_password=dict(required=False, type="str", no_log=True),
        device_unique_name=dict(required=True, type="str"),
        device_serial=dict(required=False, type="str")
    )

    # BUILD MODULE OBJECT SO WE CAN BUILD THE PARAMGRAM
    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )

    # BUILD THE PARAMGRAM
    paramgram = {
        "device_ip": module.params["device_ip"],
        "device_username": module.params["device_username"],
        "device_password": module.params["device_password"],
        "device_unique_name": module.params["device_unique_name"],
        "device_serial": module.params["device_serial"],
        "adom": module.params["adom"],
        "mode": module.params["mode"]
    }

    # INSERT THE PARAMGRAM INTO THE MODULE SO WHEN WE PASS IT TO MOD_UTILS.FortiManagerHandler IT HAS THAT INFO
    module.paramgram = paramgram

    # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION
    results = DEFAULT_RESULT_OBJ
    try:
        if paramgram["mode"] == "add":
            # CHECK IF DEVICE EXISTS
            if module.params["blind_add"] == "disable":
                exists_results = get_device(fmgr, paramgram)
                fmgr.govern_response(module=module, results=exists_results, good_codes=(0, -3), changed=False,
                                     ansible_facts=fmgr.construct_ansible_facts(exists_results,
                                                                                module.params, paramgram))

            discover_results = discover_device(fmgr, paramgram)
            fmgr.govern_response(module=module, results=discover_results, stop_on_success=False,
                                 ansible_facts=fmgr.construct_ansible_facts(discover_results,
                                                                            module.params, paramgram))

            if discover_results[0] == 0:
                results = add_device(fmgr, paramgram)
                fmgr.govern_response(module=module, results=discover_results, stop_on_success=True,
                                     changed_if_success=True,
                                     ansible_facts=fmgr.construct_ansible_facts(discover_results,
                                                                                module.params, paramgram))

        if paramgram["mode"] == "delete":
            results = delete_device(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_device_config

Metadata

Name: fmgr_device_config

Description: Edit device configurations from FortiManager Device Manager using JSON RPC API.

Author(s):

  • Luke Weighall (github: @lweighall)
  • Andrew Welsh (github: @Ghilli3)
  • Jim Huber (github: @p4r4n0y1ng)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Luke Weighall

Module Github Link

Parameters
adom
  • Description: The ADOM the configuration should belong to.
  • Required: False
  • default: root
device_hostname
  • Description: The device’s new hostname.
  • Required: False
device_unique_name
  • Description: The unique device’s name that you are editing. A.K.A. Friendly name of the device in FortiManager.
  • Required: True
install_config
  • Description: Tells FMGR to attempt to install the config after making it.
  • Required: False
  • default: disable
interface
  • Description: The interface/port number you are editing.
  • Required: False
interface_allow_access
  • Description: Specify what protocols are allowed on the interface, comma-separated list (see examples).
  • Required: False
interface_ip
  • Description: The IP and subnet of the interface/port you are editing.
  • Required: False
Functions
  • update_device_hostname
def update_device_hostname(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    datagram = {
        "hostname": paramgram["device_hostname"]
    }

    url = "pm/config/device/{device_name}/global/system/global".format(device_name=paramgram["device_unique_name"])
    response = fmgr.process_request(url, datagram, FMGRMethods.UPDATE)
    return response
  • update_device_interface
def update_device_interface(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    access_list = list()
    allow_access_list = paramgram["interface_allow_access"].replace(' ', '')
    access_list = allow_access_list.split(',')

    datagram = {
        "allowaccess": access_list,
        "ip": paramgram["interface_ip"]
    }

    url = "/pm/config/device/{device_name}/global/system/interface" \
          "/{interface}".format(device_name=paramgram["device_unique_name"], interface=paramgram["interface"])
    response = fmgr.process_request(url, datagram, FMGRMethods.UPDATE)
    return response
  • exec_config
def exec_config(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    datagram = {
        "scope": {
            "name": paramgram["device_unique_name"]
        },
        "adom": paramgram["adom"],
        "flags": "none"
    }

    url = "/securityconsole/install/device"
    response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
    return response
  • main
def main():
    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        device_unique_name=dict(required=True, type="str"),
        device_hostname=dict(required=False, type="str"),
        interface=dict(required=False, type="str"),
        interface_ip=dict(required=False, type="str"),
        interface_allow_access=dict(required=False, type="str"),
        install_config=dict(required=False, type="str", default="disable"),
    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    paramgram = {
        "device_unique_name": module.params["device_unique_name"],
        "device_hostname": module.params["device_hostname"],
        "interface": module.params["interface"],
        "interface_ip": module.params["interface_ip"],
        "interface_allow_access": module.params["interface_allow_access"],
        "install_config": module.params["install_config"],
        "adom": module.params["adom"]
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION
    results = DEFAULT_RESULT_OBJ
    try:
        if paramgram["device_hostname"] is not None:
            results = update_device_hostname(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

        if paramgram["interface_ip"] is not None or paramgram["interface_allow_access"] is not None:
            results = update_device_interface(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

        if paramgram["install_config"] == "enable":
            results = exec_config(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {
    "metadata_version": "1.1",
    "status": ["preview"],
    "supported_by": "community"
}

DOCUMENTATION = '''
---
module: fmgr_device_config
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author:
    - Luke Weighall (@lweighall)
    - Andrew Welsh (@Ghilli3)
    - Jim Huber (@p4r4n0y1ng)
short_description: Edit device configurations
description:
  - Edit device configurations from FortiManager Device Manager using JSON RPC API.

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: false
    default: root

  device_unique_name:
    description:
      - The unique device's name that you are editing. A.K.A. Friendly name of the device in FortiManager.
    required: True

  device_hostname:
    description:
      - The device's new hostname.
    required: false

  install_config:
    description:
      - Tells FMGR to attempt to install the config after making it.
    required: false
    default: disable

  interface:
    description:
      - The interface/port number you are editing.
    required: false

  interface_ip:
    description:
      - The IP and subnet of the interface/port you are editing.
    required: false

  interface_allow_access:
    description:
      - Specify what protocols are allowed on the interface, comma-separated list (see examples).
    required: false
'''

EXAMPLES = '''
- name: CHANGE HOSTNAME
  fmgr_device_config:
    device_hostname: "ChangedbyAnsible"
    device_unique_name: "FGT1"

- name: EDIT INTERFACE INFORMATION
  fmgr_device_config:
    adom: "root"
    device_unique_name: "FGT2"
    interface: "port3"
    interface_ip: "10.1.1.1/24"
    interface_allow_access: "ping, telnet, https"

- name: INSTALL CONFIG
  fmgr_device_config:
    adom: "root"
    device_unique_name: "FGT1"
    install_config: "enable"
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
from ansible.module_utils.network.fortimanager.common import FMGRMethods


def update_device_hostname(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    datagram = {
        "hostname": paramgram["device_hostname"]
    }

    url = "pm/config/device/{device_name}/global/system/global".format(device_name=paramgram["device_unique_name"])
    response = fmgr.process_request(url, datagram, FMGRMethods.UPDATE)
    return response


def update_device_interface(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    access_list = list()
    allow_access_list = paramgram["interface_allow_access"].replace(' ', '')
    access_list = allow_access_list.split(',')

    datagram = {
        "allowaccess": access_list,
        "ip": paramgram["interface_ip"]
    }

    url = "/pm/config/device/{device_name}/global/system/interface" \
          "/{interface}".format(device_name=paramgram["device_unique_name"], interface=paramgram["interface"])
    response = fmgr.process_request(url, datagram, FMGRMethods.UPDATE)
    return response


def exec_config(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    datagram = {
        "scope": {
            "name": paramgram["device_unique_name"]
        },
        "adom": paramgram["adom"],
        "flags": "none"
    }

    url = "/securityconsole/install/device"
    response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
    return response


def main():
    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        device_unique_name=dict(required=True, type="str"),
        device_hostname=dict(required=False, type="str"),
        interface=dict(required=False, type="str"),
        interface_ip=dict(required=False, type="str"),
        interface_allow_access=dict(required=False, type="str"),
        install_config=dict(required=False, type="str", default="disable"),
    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    paramgram = {
        "device_unique_name": module.params["device_unique_name"],
        "device_hostname": module.params["device_hostname"],
        "interface": module.params["interface"],
        "interface_ip": module.params["interface_ip"],
        "interface_allow_access": module.params["interface_allow_access"],
        "install_config": module.params["install_config"],
        "adom": module.params["adom"]
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION
    results = DEFAULT_RESULT_OBJ
    try:
        if paramgram["device_hostname"] is not None:
            results = update_device_hostname(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

        if paramgram["interface_ip"] is not None or paramgram["interface_allow_access"] is not None:
            results = update_device_interface(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

        if paramgram["install_config"] == "enable":
            results = exec_config(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_device_group

Metadata

Name: fmgr_device_group

Description: Add or edit device groups and assign devices to device groups FortiManager Device Manager using JSON RPC API.

Author(s):

  • Luke Weighall (github: @lweighall)
  • Andrew Welsh (github: @Ghilli3)
  • Jim Huber (github: @p4r4n0y1ng)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Luke Weighall

Module Github Link

Parameters
adom
  • Description: The ADOM the configuration should belong to.
  • Required: False
  • default: root
grp_desc
  • Description: The description of the device group.
  • Required: False
grp_members
  • Description: A comma separated list of device names or device groups to be added as members to the device group.

    If Group Members are defined, and mode=”delete”, only group members will be removed.

    If you want to delete a group itself, you must omit this parameter from the task in playbook.

  • Required: False

grp_name
  • Description: The name of the device group.
  • Required: False
mode
  • Description: Sets one of three modes for managing the object.

    Allows use of soft-adds instead of overwriting existing values

  • Required: False

  • default: add

  • choices: [‘add’, ‘set’, ‘delete’, ‘update’]

vdom
  • Description: The VDOM of the Fortigate you want to add, must match the device in FMGR. Usually root.
  • Required: False
  • default: root
Functions
  • get_groups
def get_groups(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    datagram = {
        "method": "get"
    }

    url = '/dvmdb/adom/{adom}/group'.format(adom=paramgram["adom"])
    response = fmgr.process_request(url, datagram, FMGRMethods.GET)
    return response
  • add_device_group
def add_device_group(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ
    url = ""
    mode = paramgram["mode"]

    datagram = {
        "name": paramgram["grp_name"],
        "desc": paramgram["grp_desc"],
        "os_type": "fos"
    }

    url = '/dvmdb/adom/{adom}/group'.format(adom=paramgram["adom"])

    # IF MODE = SET -- USE THE 'SET' API CALL MODE
    if mode == "set":
        response = fmgr.process_request(url, datagram, FMGRMethods.SET)
    # IF MODE = UPDATE -- USER THE 'UPDATE' API CALL MODE
    elif mode == "update":
        response = fmgr.process_request(url, datagram, FMGRMethods.UPDATE)
    # IF MODE = ADD  -- USE THE 'ADD' API CALL MODE
    elif mode == "add":
        response = fmgr.process_request(url, datagram, FMGRMethods.ADD)

    return response
  • delete_device_group
def delete_device_group(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ
    url = ""

    datagram = {
        "adom": paramgram["adom"],
        "name": paramgram["grp_name"]
    }

    url = '/dvmdb/adom/{adom}/group/{grp_name}'.format(adom=paramgram["adom"], grp_name=paramgram["grp_name"])
    response = fmgr.process_request(url, datagram, FMGRMethods.DELETE)
    return response
  • add_group_member
def add_group_member(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ
    url = ""
    device_member_list = paramgram["grp_members"].replace(' ', '')
    device_member_list = device_member_list.split(',')

    for dev_name in device_member_list:
        datagram = {'name': dev_name, 'vdom': paramgram["vdom"]}

        url = '/dvmdb/adom/{adom}/group/{grp_name}/object member'.format(adom=paramgram["adom"],
                                                                         grp_name=paramgram["grp_name"])
        response = fmgr.process_request(url, datagram, FMGRMethods.ADD)

    return response
  • delete_group_member
def delete_group_member(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ
    url = ""
    device_member_list = paramgram["grp_members"].replace(' ', '')
    device_member_list = device_member_list.split(',')

    for dev_name in device_member_list:
        datagram = {'name': dev_name, 'vdom': paramgram["vdom"]}

        url = '/dvmdb/adom/{adom}/group/{grp_name}/object member'.format(adom=paramgram["adom"],
                                                                         grp_name=paramgram["grp_name"])
        response = fmgr.process_request(url, datagram, FMGRMethods.DELETE)

    return response
  • main
def main():
    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        vdom=dict(required=False, type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),
        grp_desc=dict(required=False, type="str"),
        grp_name=dict(required=True, type="str"),
        grp_members=dict(required=False, type="str"),
    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    paramgram = {
        "mode": module.params["mode"],
        "grp_name": module.params["grp_name"],
        "grp_desc": module.params["grp_desc"],
        "grp_members": module.params["grp_members"],
        "adom": module.params["adom"],
        "vdom": module.params["vdom"]
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION
    results = DEFAULT_RESULT_OBJ
    try:
        # PROCESS THE GROUP ADDS FIRST
        if paramgram["grp_name"] is not None and paramgram["mode"] in ["add", "set", "update"]:
            # add device group
            results = add_device_group(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

        # PROCESS THE GROUP MEMBER ADDS
        if paramgram["grp_members"] is not None and paramgram["mode"] in ["add", "set", "update"]:
            # assign devices to device group
            results = add_group_member(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

        # PROCESS THE GROUP MEMBER DELETES
        if paramgram["grp_members"] is not None and paramgram["mode"] == "delete":
            # remove devices grom a group
            results = delete_group_member(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

        # PROCESS THE GROUP DELETES, ONLY IF GRP_MEMBERS IS NOT NULL TOO
        if paramgram["grp_name"] is not None and paramgram["mode"] == "delete" and paramgram["grp_members"] is None:
            # delete device group
            results = delete_device_group(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {
    "metadata_version": "1.1",
    "status": ["preview"],
    "supported_by": "community"
}

DOCUMENTATION = '''
---
module: fmgr_device_group
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author:
    - Luke Weighall (@lweighall)
    - Andrew Welsh (@Ghilli3)
    - Jim Huber (@p4r4n0y1ng)
short_description: Alter FortiManager device groups.
description:
  - Add or edit device groups and assign devices to device groups FortiManager Device Manager using JSON RPC API.

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: false
    default: root

  vdom:
    description:
      - The VDOM of the Fortigate you want to add, must match the device in FMGR. Usually root.
    required: false
    default: root

  mode:
    description:
      - Sets one of three modes for managing the object.
      - Allows use of soft-adds instead of overwriting existing values
    choices: ['add', 'set', 'delete', 'update']
    required: false
    default: add

  grp_name:
    description:
      - The name of the device group.
    required: false

  grp_desc:
    description:
      - The description of the device group.
    required: false

  grp_members:
    description:
      - A comma separated list of device names or device groups to be added as members to the device group.
      - If Group Members are defined, and mode="delete", only group members will be removed.
      - If you want to delete a group itself, you must omit this parameter from the task in playbook.
    required: false

'''


EXAMPLES = '''
- name: CREATE DEVICE GROUP
  fmgr_device_group:
    grp_name: "TestGroup"
    grp_desc: "CreatedbyAnsible"
    adom: "ansible"
    mode: "add"

- name: CREATE DEVICE GROUP 2
  fmgr_device_group:
    grp_name: "AnsibleGroup"
    grp_desc: "CreatedbyAnsible"
    adom: "ansible"
    mode: "add"

- name: ADD DEVICES TO DEVICE GROUP
  fmgr_device_group:
    mode: "add"
    grp_name: "TestGroup"
    grp_members: "FGT1,FGT2"
    adom: "ansible"
    vdom: "root"

- name: REMOVE DEVICES TO DEVICE GROUP
  fmgr_device_group:
    mode: "delete"
    grp_name: "TestGroup"
    grp_members: "FGT1,FGT2"
    adom: "ansible"

- name: DELETE DEVICE GROUP
  fmgr_device_group:
    grp_name: "AnsibleGroup"
    grp_desc: "CreatedbyAnsible"
    mode: "delete"
    adom: "ansible"
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import FMGRMethods
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG


def get_groups(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    datagram = {
        "method": "get"
    }

    url = '/dvmdb/adom/{adom}/group'.format(adom=paramgram["adom"])
    response = fmgr.process_request(url, datagram, FMGRMethods.GET)
    return response


def add_device_group(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ
    url = ""
    mode = paramgram["mode"]

    datagram = {
        "name": paramgram["grp_name"],
        "desc": paramgram["grp_desc"],
        "os_type": "fos"
    }

    url = '/dvmdb/adom/{adom}/group'.format(adom=paramgram["adom"])

    # IF MODE = SET -- USE THE 'SET' API CALL MODE
    if mode == "set":
        response = fmgr.process_request(url, datagram, FMGRMethods.SET)
    # IF MODE = UPDATE -- USER THE 'UPDATE' API CALL MODE
    elif mode == "update":
        response = fmgr.process_request(url, datagram, FMGRMethods.UPDATE)
    # IF MODE = ADD  -- USE THE 'ADD' API CALL MODE
    elif mode == "add":
        response = fmgr.process_request(url, datagram, FMGRMethods.ADD)

    return response


def delete_device_group(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ
    url = ""

    datagram = {
        "adom": paramgram["adom"],
        "name": paramgram["grp_name"]
    }

    url = '/dvmdb/adom/{adom}/group/{grp_name}'.format(adom=paramgram["adom"], grp_name=paramgram["grp_name"])
    response = fmgr.process_request(url, datagram, FMGRMethods.DELETE)
    return response


def add_group_member(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ
    url = ""
    device_member_list = paramgram["grp_members"].replace(' ', '')
    device_member_list = device_member_list.split(',')

    for dev_name in device_member_list:
        datagram = {'name': dev_name, 'vdom': paramgram["vdom"]}

        url = '/dvmdb/adom/{adom}/group/{grp_name}/object member'.format(adom=paramgram["adom"],
                                                                         grp_name=paramgram["grp_name"])
        response = fmgr.process_request(url, datagram, FMGRMethods.ADD)

    return response


def delete_group_member(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ
    url = ""
    device_member_list = paramgram["grp_members"].replace(' ', '')
    device_member_list = device_member_list.split(',')

    for dev_name in device_member_list:
        datagram = {'name': dev_name, 'vdom': paramgram["vdom"]}

        url = '/dvmdb/adom/{adom}/group/{grp_name}/object member'.format(adom=paramgram["adom"],
                                                                         grp_name=paramgram["grp_name"])
        response = fmgr.process_request(url, datagram, FMGRMethods.DELETE)

    return response


def main():
    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        vdom=dict(required=False, type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),
        grp_desc=dict(required=False, type="str"),
        grp_name=dict(required=True, type="str"),
        grp_members=dict(required=False, type="str"),
    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    paramgram = {
        "mode": module.params["mode"],
        "grp_name": module.params["grp_name"],
        "grp_desc": module.params["grp_desc"],
        "grp_members": module.params["grp_members"],
        "adom": module.params["adom"],
        "vdom": module.params["vdom"]
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION
    results = DEFAULT_RESULT_OBJ
    try:
        # PROCESS THE GROUP ADDS FIRST
        if paramgram["grp_name"] is not None and paramgram["mode"] in ["add", "set", "update"]:
            # add device group
            results = add_device_group(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

        # PROCESS THE GROUP MEMBER ADDS
        if paramgram["grp_members"] is not None and paramgram["mode"] in ["add", "set", "update"]:
            # assign devices to device group
            results = add_group_member(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

        # PROCESS THE GROUP MEMBER DELETES
        if paramgram["grp_members"] is not None and paramgram["mode"] == "delete":
            # remove devices grom a group
            results = delete_group_member(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

        # PROCESS THE GROUP DELETES, ONLY IF GRP_MEMBERS IS NOT NULL TOO
        if paramgram["grp_name"] is not None and paramgram["mode"] == "delete" and paramgram["grp_members"] is None:
            # delete device group
            results = delete_device_group(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_device_provision_template

Metadata

Name: fmgr_device_provision_template

Description: Allows the editing and assignment of device provisioning templates in FortiManager.

Author(s):

  • Luke Weighall (github: @lweighall)
  • Andrew Welsh (github: @Ghilli3)
  • Jim Huber (github: @p4r4n0y1ng)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Luke Weighall

Module Github Link

Parameters
admin_enable_fortiguard
  • Description: Enables FortiGuard security updates to their default settings.
  • Required: False
  • choices: [‘none’, ‘direct’, ‘this-fmg’]
admin_fortianalyzer_target
  • Description: Configures faz target.
  • Required: False
admin_fortiguard_target
  • Description: Configures fortiguard target.

    admin_enable_fortiguard must be set to “direct”.

  • Required: False

admin_gui_theme
  • Description: Changes the admin gui theme.
  • Required: False
  • choices: [‘green’, ‘red’, ‘blue’, ‘melongene’, ‘mariner’]
admin_http_port
  • Description: Non-SSL admin gui port number.
  • Required: False
admin_https_port
  • Description: SSL admin gui port number.
  • Required: False
admin_https_redirect
  • Description: Enables or disables https redirect from http.
  • Required: False
  • choices: [‘enable’, ‘disable’]
admin_language
  • Description: Sets the admin gui language.
  • Required: False
  • choices: [‘english’, ‘simch’, ‘japanese’, ‘korean’, ‘spanish’, ‘trach’, ‘french’, ‘portuguese’]
admin_switch_controller
  • Description: Enables or disables the switch controller.
  • Required: False
  • choices: [‘enable’, ‘disable’]
admin_timeout
  • Description: Admin timeout in minutes.
  • Required: False
adom
  • Description: The ADOM the configuration should belong to.
  • Required: True
delete_provisioning_template
  • Description: If specified, all other options are ignored. The specified provisioning template will be deleted.
  • Required: False
device_unique_name
  • Description: The unique device’s name that you are editing.
  • Required: True
dns_primary_ipv4
  • Description: primary ipv4 dns forwarder.
  • Required: False
dns_secondary_ipv4
  • Description: secondary ipv4 dns forwarder.
  • Required: False
dns_suffix
  • Description: Sets the local dns domain suffix.
  • Required: False
mode
  • Description: Sets one of three modes for managing the object.

    Allows use of soft-adds instead of overwriting existing values.

  • Required: False

  • default: add

  • choices: [‘add’, ‘set’, ‘delete’, ‘update’]

ntp_auth
  • Description: Enables or disables ntp authentication.
  • Required: False
  • choices: [‘enable’, ‘disable’]
ntp_auth_pwd
  • Description: Sets the ntp auth password.
  • Required: False
ntp_server
  • Description: Only used with custom ntp_type – specifies IP of server to sync to – comma separated ip addresses for multiples.
  • Required: False
ntp_status
  • Description: Enables or disables ntp.
  • Required: False
  • choices: [‘enable’, ‘disable’]
ntp_sync_interval
  • Description: Sets the interval in minutes for ntp sync.
  • Required: False
ntp_type
  • Description: Enables fortiguard servers or custom servers are the ntp source.
  • Required: False
  • choices: [‘fortiguard’, ‘custom’]
ntp_v3
  • Description: Enables or disables ntpv3 (default is ntpv4).
  • Required: False
  • choices: [‘enable’, ‘disable’]
provision_targets
  • Description: The friendly names of devices in FortiManager to assign the provisioning template to. Comma separated list.
  • Required: True
provisioning_template
  • Description: The provisioning template you want to apply (default = default).
  • Required: True
smtp_conn_sec
  • Description: defines the ssl level for smtp.
  • Required: False
  • choices: [‘none’, ‘starttls’, ‘smtps’]
smtp_password
  • Description: SMTP password.
  • Required: False
smtp_port
  • Description: SMTP port number.
  • Required: False
smtp_replyto
  • Description: SMTP reply to address.
  • Required: False
smtp_server
  • Description: SMTP server ipv4 address.
  • Required: False
smtp_source_ipv4
  • Description: SMTP source ip address.
  • Required: False
smtp_username
  • Description: SMTP auth username.
  • Required: False
smtp_validate_cert
  • Description: Enables or disables valid certificate checking for smtp.
  • Required: False
  • choices: [‘enable’, ‘disable’]
snmp_status
  • Description: Enables or disables SNMP globally.
  • Required: False
  • choices: [‘enable’, ‘disable’]
snmp_v2c_id
  • Description: Primary key for the snmp community. this must be unique!
  • Required: False
snmp_v2c_name
  • Description: Specifies the v2c community name.
  • Required: False
snmp_v2c_query_hosts_ipv4
  • Description: IPv4 addresses or subnets that are allowed to query SNMP v2c, comma separated (“10.7.220.59 255.255.255.0, 10.7.220.0 255.255.255.0”).
  • Required: False
snmp_v2c_query_port
  • Description: Sets the snmp v2c community query port.
  • Required: False
snmp_v2c_query_status
  • Description: Enables or disables the v2c community specified for queries.
  • Required: False
  • choices: [‘enable’, ‘disable’]
snmp_v2c_status
  • Description: Enables or disables the v2c community specified.
  • Required: False
  • choices: [‘enable’, ‘disable’]
snmp_v2c_trap_hosts_ipv4
  • Description: IPv4 addresses of the hosts that should get SNMP v2c traps, comma separated, must include mask (“10.7.220.59 255.255.255.255, 10.7.220.60 255.255.255.255”).
  • Required: False
snmp_v2c_trap_port
  • Description: Sets the snmp v2c community trap port.
  • Required: False
snmp_v2c_trap_src_ipv4
  • Description: Source ip the traps should come from IPv4.
  • Required: False
snmp_v2c_trap_status
  • Description: Enables or disables the v2c community specified for traps.
  • Required: False
  • choices: [‘enable’, ‘disable’]
snmpv3_auth_proto
  • Description: SNMPv3 auth protocol.
  • Required: False
  • choices: [‘md5’, ‘sha’]
snmpv3_auth_pwd
  • Description: SNMPv3 auth pwd __ currently not encrypted! ensure this file is locked down permissions wise!
  • Required: False
snmpv3_name
  • Description: SNMPv3 user name.
  • Required: False
snmpv3_notify_hosts
  • Description: List of ipv4 hosts to send snmpv3 traps to. Comma separated IPv4 list.
  • Required: False
snmpv3_priv_proto
  • Description: SNMPv3 priv protocol.
  • Required: False
  • choices: [‘aes’, ‘des’, ‘aes256’, ‘aes256cisco’]
snmpv3_priv_pwd
  • Description: SNMPv3 priv pwd currently not encrypted! ensure this file is locked down permissions wise!
  • Required: False
snmpv3_queries
  • Description: Allow snmpv3_queries.
  • Required: False
  • choices: [‘enable’, ‘disable’]
snmpv3_query_port
  • Description: SNMPv3 query port.
  • Required: False
snmpv3_security_level
  • Description: SNMPv3 security level.
  • Required: False
  • choices: [‘no-auth-no-priv’, ‘auth-no-priv’, ‘auth-priv’]
snmpv3_source_ip
  • Description: SNMPv3 source ipv4 address for traps.
  • Required: False
snmpv3_status
  • Description: SNMPv3 user is enabled or disabled.
  • Required: False
  • choices: [‘enable’, ‘disable’]
snmpv3_trap_rport
  • Description: SNMPv3 trap remote port.
  • Required: False
snmpv3_trap_status
  • Description: SNMPv3 traps is enabled or disabled.
  • Required: False
  • choices: [‘enable’, ‘disable’]
syslog_certificate
  • Description: Certificate used to communicate with Syslog server if encryption on.
  • Required: False
syslog_enc_algorithm
  • Description: Enable/disable reliable syslogging with TLS encryption.

    choice | high | SSL communication with high encryption algorithms.

    choice | low | SSL communication with low encryption algorithms.

    choice | disable | Disable SSL communication.

    choice | high-medium | SSL communication with high and medium encryption algorithms.

  • Required: False

  • default: disable

  • choices: [‘high’, ‘low’, ‘disable’, ‘high-medium’]

syslog_facility
  • Description: Remote syslog facility.

    choice | kernel | Kernel messages.

    choice | user | Random user-level messages.

    choice | mail | Mail system.

    choice | daemon | System daemons.

    choice | auth | Security/authorization messages.

    choice | syslog | Messages generated internally by syslog.

    choice | lpr | Line printer subsystem.

    choice | news | Network news subsystem.

    choice | uucp | Network news subsystem.

    choice | cron | Clock daemon.

    choice | authpriv | Security/authorization messages (private).

    choice | ftp | FTP daemon.

    choice | ntp | NTP daemon.

    choice | audit | Log audit.

    choice | alert | Log alert.

    choice | clock | Clock daemon.

    choice | local0 | Reserved for local use.

    choice | local1 | Reserved for local use.

    choice | local2 | Reserved for local use.

    choice | local3 | Reserved for local use.

    choice | local4 | Reserved for local use.

    choice | local5 | Reserved for local use.

    choice | local6 | Reserved for local use.

    choice | local7 | Reserved for local use.

  • Required: False

  • default: syslog

  • choices: [‘kernel’, ‘user’, ‘mail’, ‘daemon’, ‘auth’, ‘syslog’, ‘lpr’, ‘news’, ‘uucp’, ‘cron’, ‘authpriv’, ‘ftp’, ‘ntp’, ‘audit’, ‘alert’, ‘clock’, ‘local0’, ‘local1’, ‘local2’, ‘local3’, ‘local4’, ‘local5’, ‘local6’, ‘local7’]

syslog_filter
  • Description: Sets the logging level for syslog.
  • Required: False
  • choices: [‘emergency’, ‘alert’, ‘critical’, ‘error’, ‘warning’, ‘notification’, ‘information’, ‘debug’]
syslog_mode
  • Description: Remote syslog logging over UDP/Reliable TCP.

    choice | udp | Enable syslogging over UDP.

    choice | legacy-reliable | Enable legacy reliable syslogging by RFC3195 (Reliable Delivery for Syslog).

    choice | reliable | Enable reliable syslogging by RFC6587 (Transmission of Syslog Messages over TCP).

  • Required: False

  • default: udp

  • choices: [‘udp’, ‘legacy-reliable’, ‘reliable’]

syslog_port
  • Description: Syslog port that will be set.
  • Required: False
syslog_server
  • Description: Server the syslogs will be sent to.
  • Required: False
syslog_status
  • Description: Enables or disables syslogs.
  • Required: False
  • choices: [‘enable’, ‘disable’]
Functions
  • get_devprof
def get_devprof(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    response = DEFAULT_RESULT_OBJ
    datagram = {}

    url = "/pm/devprof/adom/{adom}/{name}".format(adom=paramgram["adom"], name=paramgram["provisioning_template"])
    response = fmgr.process_request(url, datagram, FMGRMethods.GET)

    return response
  • set_devprof
def set_devprof(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    response = DEFAULT_RESULT_OBJ
    if paramgram["mode"] in ['set', 'add', 'update']:
        datagram = {
            "name": paramgram["provisioning_template"],
            "type": "devprof",
            "description": "CreatedByAnsible",
        }
        url = "/pm/devprof/adom/{adom}".format(adom=paramgram["adom"])

    elif paramgram["mode"] == "delete":
        datagram = {}

        url = "/pm/devprof/adom/{adom}/{name}".format(adom=paramgram["adom"],
                                                      name=paramgram["delete_provisioning_template"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response
  • get_devprof_scope
def get_devprof_scope(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    response = DEFAULT_RESULT_OBJ
    datagram = {
        "name": paramgram["provisioning_template"],
        "type": "devprof",
        "description": "CreatedByAnsible",
    }

    url = "/pm/devprof/adom/{adom}".format(adom=paramgram["adom"])
    response = fmgr.process_request(url, datagram, FMGRMethods.GET)

    return response
  • set_devprof_scope
def set_devprof_scope(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    response = DEFAULT_RESULT_OBJ
    if paramgram["mode"] in ['set', 'add', 'update']:
        datagram = {
            "name": paramgram["provisioning_template"],
            "type": "devprof",
            "description": "CreatedByAnsible",
        }

        targets = []
        for target in paramgram["provision_targets"].split(","):
            # split the host on the space to get the mask out
            new_target = {"name": target.strip()}
            targets.append(new_target)

        datagram["scope member"] = targets

        url = "/pm/devprof/adom/{adom}".format(adom=paramgram["adom"])

    elif paramgram["mode"] == "delete":
        datagram = {
            "name": paramgram["provisioning_template"],
            "type": "devprof",
            "description": "CreatedByAnsible",
            "scope member": paramgram["targets_to_add"]
        }

        url = "/pm/devprof/adom/{adom}".format(adom=paramgram["adom"])

    response = fmgr.process_request(url, datagram, FMGRMethods.SET)
    return response
  • set_devprof_snmp
def set_devprof_snmp(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    paramgram["mode"] = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    datagram = {
        "status": paramgram["snmp_status"]
    }
    url = "/pm/config/adom/{adom}/devprof/" \
          "{provisioning_template}/system/snmp/sysinfo".format(adom=adom,
                                                               provisioning_template=paramgram["provisioning_template"])

    response = fmgr.process_request(url, datagram, FMGRMethods.SET)
    return response
  • set_devprof_snmp_v2c
def set_devprof_snmp_v2c(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    paramgram["mode"] = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    if paramgram["mode"] in ['set', 'add', 'update']:
        datagram = {
            "query-v2c-port": paramgram["snmp_v2c_query_port"],
            "trap-v2c-rport": paramgram["snmp_v2c_trap_port"],
            "status": paramgram["snmp_v2c_status"],
            "trap-v2c-status": paramgram["snmp_v2c_trap_status"],
            "query-v2c-status": paramgram["snmp_v2c_query_status"],
            "name": paramgram["snmp_v2c_name"],
            "id": paramgram["snmp_v2c_id"],
            "meta fields": dict(),
            "hosts": list(),
            "events": 411578417151,
            "query-v1-status": 0,
            "query-v1-port": 161,
            "trap-v1-status": 0,
            "trap-v1-lport": 162,
            "trap-v1-rport": 162,
            "trap-v2c-lport": 162,
        }

        # BUILD THE HOST STRINGS
        id_counter = 1
        if paramgram["snmp_v2c_trap_hosts_ipv4"] or paramgram["snmp_v2c_query_hosts_ipv4"]:
            hosts = []
            if paramgram["snmp_v2c_query_hosts_ipv4"]:
                for ipv4_host in paramgram["snmp_v2c_query_hosts_ipv4"].strip().split(","):
                    # split the host on the space to get the mask out
                    new_ipv4_host = {"ha-direct": "enable",
                                     "host-type": "query",
                                     "id": id_counter,
                                     "ip": ipv4_host.strip().split(),
                                     "meta fields": {},
                                     "source-ip": "0.0.0.0"}
                    hosts.append(new_ipv4_host)
                    id_counter += 1

            if paramgram["snmp_v2c_trap_hosts_ipv4"]:
                for ipv4_host in paramgram["snmp_v2c_trap_hosts_ipv4"].strip().split(","):
                    # split the host on the space to get the mask out
                    new_ipv4_host = {"ha-direct": "enable",
                                     "host-type": "trap",
                                     "id": id_counter,
                                     "ip": ipv4_host.strip().split(),
                                     "meta fields": {},
                                     "source-ip": paramgram["snmp_v2c_trap_src_ipv4"]}
                    hosts.append(new_ipv4_host)
                    id_counter += 1
            datagram["hosts"] = hosts

        url = "/pm/config/adom/{adom}/devprof/" \
              "{provisioning_template}/system/snmp/community".format(adom=adom,
                                                                     provisioning_template=paramgram[
                                                                         "provisioning_template"])
    elif paramgram["mode"] == "delete":
        datagram = {
            "confirm": 1
        }

        url = "/pm/config/adom/{adom}/" \
              "devprof/{provisioning_template}/" \
              "system/snmp/community/{snmp_v2c_id}".format(adom=adom,
                                                           provisioning_template=paramgram["provisioning_template"],
                                                           snmp_v2c_id=paramgram["snmp_v2c_id"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response
  • set_devprof_snmp_v3
def set_devprof_snmp_v3(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    paramgram["mode"] = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    if paramgram["mode"] in ['set', 'add', 'update']:
        datagram = {}
        datagram["auth-pwd"] = paramgram["snmpv3_auth_pwd"]
        datagram["priv-pwd"] = paramgram["snmpv3_priv_pwd"]
        datagram["trap-rport"] = paramgram["snmpv3_trap_rport"]
        datagram["query-port"] = paramgram["snmpv3_query_port"]
        datagram["name"] = paramgram["snmpv3_name"]
        datagram["notify-hosts"] = paramgram["snmpv3_notify_hosts"].strip().split(",")
        datagram["events"] = 1647387997183
        datagram["trap-lport"] = 162

        datagram["source-ip"] = paramgram["snmpv3_source_ip"]
        datagram["ha-direct"] = 0

        url = "/pm/config/adom/{adom}/" \
              "devprof/{provisioning_template}/" \
              "system/snmp/user".format(adom=adom,
                                        provisioning_template=paramgram["provisioning_template"])
    elif paramgram["mode"] == "delete":
        datagram = {
            "confirm": 1
        }

        url = "/pm/config/adom/{adom}/devprof/" \
              "{provisioning_template}/system/snmp" \
              "/user/{snmpv3_name}".format(adom=adom,
                                           provisioning_template=paramgram["provisioning_template"],
                                           snmpv3_name=paramgram["snmpv3_name"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response
  • set_devprof_syslog
def set_devprof_syslog(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    paramgram["mode"] = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ

    datagram = {
        "status": paramgram["syslog_status"],
        "port": paramgram["syslog_port"],
        "server": paramgram["syslog_server"],
        "mode": paramgram["syslog_mode"],
        "facility": paramgram["syslog_facility"]
    }

    if paramgram["mode"] in ['set', 'add', 'update']:
        if paramgram["syslog_enc_algorithm"] in ["high", "low", "high-medium"] \
                and paramgram["syslog_certificate"] is not None:
            datagram["certificate"] = paramgram["certificate"]
            datagram["enc-algorithm"] = paramgram["syslog_enc_algorithm"]

        url = "/pm/config/adom/{adom}/" \
              "devprof/{provisioning_template}/" \
              "log/syslogd/setting".format(adom=adom,
                                           provisioning_template=paramgram["provisioning_template"])
    elif paramgram["mode"] == "delete":
        url = "/pm/config/adom/{adom}/" \
              "devprof/{provisioning_template}/" \
              "log/syslogd/setting".format(adom=adom,
                                           provisioning_template=paramgram["provisioning_template"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response
  • set_devprof_syslog_filter
def set_devprof_syslog_filter(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    paramgram["mode"] = paramgram["mode"]
    adom = paramgram["adom"]
    datagram = {
        "severity": paramgram["syslog_filter"]
    }
    response = DEFAULT_RESULT_OBJ

    url = "/pm/config/adom/{adom}" \
          "/devprof/{provisioning_template}" \
          "/log/syslogd/filter".format(adom=adom,
                                       provisioning_template=paramgram["provisioning_template"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response
  • set_devprof_ntp
def set_devprof_ntp(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    paramgram["mode"] = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ

    # IF SET TO FORTIGUARD, BUILD A STRING SPECIFIC TO THAT
    if paramgram["ntp_type"] == "fortiguard":
        datagram = {}
        if paramgram["ntp_status"] == "enable":
            datagram["ntpsync"] = 1
        if paramgram["ntp_status"] == "disable":
            datagram["ntpsync"] = 0
        if paramgram["ntp_sync_interval"] is None:
            datagram["syncinterval"] = 1
        else:
            datagram["syncinterval"] = paramgram["ntp_sync_interval"]

        datagram["type"] = 0

    # IF THE NTP TYPE IS CUSTOM BUILD THE SERVER LIST
    if paramgram["ntp_type"] == "custom":
        id_counter = 0
        key_counter = 0
        ntpservers = []
        datagram = {}
        if paramgram["ntp_status"] == "enable":
            datagram["ntpsync"] = 1
        if paramgram["ntp_status"] == "disable":
            datagram["ntpsync"] = 0
        try:
            datagram["syncinterval"] = paramgram["ntp_sync_interval"]
        except BaseException:
            datagram["syncinterval"] = 1
        datagram["type"] = 1

        for server in paramgram["ntp_server"].strip().split(","):
            id_counter += 1
            server_fields = dict()

            key_counter += 1
            if paramgram["ntp_auth"] == "enable":
                server_fields["authentication"] = 1
                server_fields["key"] = paramgram["ntp_auth_pwd"]
                server_fields["key-id"] = key_counter
            else:
                server_fields["authentication"] = 0
                server_fields["key"] = ""
                server_fields["key-id"] = key_counter

            if paramgram["ntp_v3"] == "enable":
                server_fields["ntp_v3"] = 1
            else:
                server_fields["ntp_v3"] = 0

            # split the host on the space to get the mask out
            new_ntp_server = {"authentication": server_fields["authentication"],
                              "id": id_counter, "key": server_fields["key"],
                              "key-id": id_counter, "ntpv3": server_fields["ntp_v3"],
                              "server": server}
            ntpservers.append(new_ntp_server)
        datagram["ntpserver"] = ntpservers

    url = "/pm/config/adom/{adom}" \
          "/devprof/{provisioning_template}" \
          "/system/ntp".format(adom=adom,
                               provisioning_template=paramgram["provisioning_template"])
    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response
  • set_devprof_admin
def set_devprof_admin(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    paramgram["mode"] = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    datagram = {
        "admin-https-redirect": paramgram["admin_https_redirect"],
        "admin-port": paramgram["admin_http_port"],
        "admin-sport": paramgram["admin_https_port"],
        "admintimeout": paramgram["admin_timeout"],
        "language": paramgram["admin_language"],
        "gui-theme": paramgram["admin_gui_theme"],
        "switch-controller": paramgram["admin_switch_controller"],
    }
    url = "/pm/config/adom/{adom}" \
          "/devprof/{provisioning_template}" \
          "/system/global".format(adom=adom,
                                  provisioning_template=paramgram["provisioning_template"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response
  • set_devprof_smtp
def set_devprof_smtp(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    paramgram["mode"] = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    datagram = {
        "port": paramgram["smtp_port"],
        "reply-to": paramgram["smtp_replyto"],
        "server": paramgram["smtp_server"],
        "source-ip": paramgram["smtp_source_ipv4"]
    }

    if paramgram["smtp_username"]:
        datagram["authenticate"] = 1
        datagram["username"] = paramgram["smtp_username"]
        datagram["password"] = paramgram["smtp_password"]

    if paramgram["smtp_conn_sec"] == "none":
        datagram["security"] = 0
    if paramgram["smtp_conn_sec"] == "starttls":
        datagram["security"] = 1
    if paramgram["smtp_conn_sec"] == "smtps":
        datagram["security"] = 2

    if paramgram["smtp_validate_cert"] == "enable":
        datagram["validate-server"] = 1
    else:
        datagram["validate-server"] = 0

    url = "/pm/config/adom/{adom}" \
          "/devprof/{provisioning_template}" \
          "/system/email-server".format(adom=adom,
                                        provisioning_template=paramgram["provisioning_template"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response
  • set_devprof_dns
def set_devprof_dns(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    paramgram["mode"] = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    datagram = {
        "domain": paramgram["dns_suffix"],
        "primary": paramgram["dns_primary_ipv4"],
        "secondary": paramgram["dns_secondary_ipv4"],
    }
    url = "/pm/config/adom/{adom}" \
          "/devprof/{provisioning_template}" \
          "/system/dns".format(adom=adom,
                               provisioning_template=paramgram["provisioning_template"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response
  • set_devprof_toggle_fg
def set_devprof_toggle_fg(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    paramgram["mode"] = paramgram["mode"]
    adom = paramgram["adom"]
    response = DEFAULT_RESULT_OBJ
    datagram = {}
    if paramgram["admin_enable_fortiguard"] in ["direct", "this-fmg"]:
        datagram["include-default-servers"] = "enable"
    elif paramgram["admin_enable_fortiguard"] == "none":
        datagram["include-default-servers"] = "disable"

    datagram["server-list"] = list()

    url = "/pm/config/adom/{adom}" \
          "/devprof/{provisioning_template}" \
          "/system/central-management".format(adom=adom,
                                              provisioning_template=paramgram["provisioning_template"])
    response = fmgr.process_request(url, datagram, FMGRMethods.SET)

    return response
  • set_devprof_fg
def set_devprof_fg(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    paramgram["mode"] = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    datagram = {
        "target": paramgram["admin_enable_fortiguard"],
        "target-ip": None
    }

    if paramgram["mode"] in ['set', 'add', 'update']:
        if paramgram["admin_fortiguard_target"] is not None and datagram["target"] == "direct":
            datagram["target-ip"] = paramgram["admin_fortiguard_target"]

    url = "/pm/config/adom/{adom}" \
          "/devprof/{provisioning_template}" \
          "/device/profile/fortiguard".format(adom=adom,
                                              provisioning_template=paramgram["provisioning_template"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response
  • set_devprof_faz
def set_devprof_faz(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    paramgram["mode"] = paramgram["mode"]
    adom = paramgram["adom"]
    response = DEFAULT_RESULT_OBJ
    datagram = {
        "target-ip": paramgram["admin_fortianalyzer_target"],
        "target": "others",
    }
    url = "/pm/config/adom/{adom}" \
          "/devprof/{provisioning_template}" \
          "/device/profile/fortianalyzer".format(adom=adom,
                                                 provisioning_template=paramgram["provisioning_template"])
    if paramgram["mode"] == "delete":
        datagram["hastarget"] = "False"

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response
  • main
def main():
    argument_spec = dict(
        adom=dict(required=False, type="str"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        provisioning_template=dict(required=False, type="str"),
        provision_targets=dict(required=False, type="str"),

        device_unique_name=dict(required=False, type="str"),
        snmp_status=dict(required=False, type="str", choices=["enable", "disable"]),
        snmp_v2c_query_port=dict(required=False, type="int"),
        snmp_v2c_trap_port=dict(required=False, type="int"),
        snmp_v2c_status=dict(required=False, type="str", choices=["enable", "disable"]),
        snmp_v2c_trap_status=dict(required=False, type="str", choices=["enable", "disable"]),
        snmp_v2c_query_status=dict(required=False, type="str", choices=["enable", "disable"]),
        snmp_v2c_name=dict(required=False, type="str", no_log=True),
        snmp_v2c_id=dict(required=False, type="int"),
        snmp_v2c_trap_src_ipv4=dict(required=False, type="str"),
        snmp_v2c_trap_hosts_ipv4=dict(required=False, type="str"),
        snmp_v2c_query_hosts_ipv4=dict(required=False, type="str"),

        snmpv3_auth_proto=dict(required=False, type="str", choices=["md5", "sha"]),
        snmpv3_auth_pwd=dict(required=False, type="str", no_log=True),
        snmpv3_name=dict(required=False, type="str"),
        snmpv3_notify_hosts=dict(required=False, type="str"),
        snmpv3_priv_proto=dict(required=False, type="str", choices=["aes", "des", "aes256", "aes256cisco"]),
        snmpv3_priv_pwd=dict(required=False, type="str", no_log=True),
        snmpv3_queries=dict(required=False, type="str", choices=["enable", "disable"]),
        snmpv3_query_port=dict(required=False, type="int"),
        snmpv3_security_level=dict(required=False, type="str",
                                   choices=["no-auth-no-priv", "auth-no-priv", "auth-priv"]),
        snmpv3_source_ip=dict(required=False, type="str"),
        snmpv3_status=dict(required=False, type="str", choices=["enable", "disable"]),
        snmpv3_trap_rport=dict(required=False, type="int"),
        snmpv3_trap_status=dict(required=False, type="str", choices=["enable", "disable"]),

        syslog_port=dict(required=False, type="int"),
        syslog_server=dict(required=False, type="str"),
        syslog_mode=dict(required=False, type="str", choices=["udp", "legacy-reliable", "reliable"], default="udp"),
        syslog_status=dict(required=False, type="str", choices=["enable", "disable"]),
        syslog_filter=dict(required=False, type="str", choices=["emergency", "alert", "critical", "error",
                                                                "warning", "notification", "information", "debug"]),
        syslog_enc_algorithm=dict(required=False, type="str", choices=["high", "low", "disable", "high-medium"],
                                  default="disable"),
        syslog_facility=dict(required=False, type="str", choices=["kernel", "user", "mail", "daemon", "auth",
                                                                  "syslog", "lpr", "news", "uucp", "cron", "authpriv",
                                                                  "ftp", "ntp", "audit", "alert", "clock", "local0",
                                                                  "local1", "local2", "local3", "local4", "local5",
                                                                  "local6", "local7"], default="syslog"),
        syslog_certificate=dict(required=False, type="str"),

        ntp_status=dict(required=False, type="str", choices=["enable", "disable"]),
        ntp_sync_interval=dict(required=False, type="int"),
        ntp_type=dict(required=False, type="str", choices=["fortiguard", "custom"]),
        ntp_server=dict(required=False, type="str"),
        ntp_auth=dict(required=False, type="str", choices=["enable", "disable"]),
        ntp_auth_pwd=dict(required=False, type="str", no_log=True),
        ntp_v3=dict(required=False, type="str", choices=["enable", "disable"]),

        admin_https_redirect=dict(required=False, type="str", choices=["enable", "disable"]),
        admin_https_port=dict(required=False, type="int"),
        admin_http_port=dict(required=False, type="int"),
        admin_timeout=dict(required=False, type="int"),
        admin_language=dict(required=False, type="str",
                            choices=["english", "simch", "japanese", "korean",
                                     "spanish", "trach", "french", "portuguese"]),
        admin_switch_controller=dict(required=False, type="str", choices=["enable", "disable"]),
        admin_gui_theme=dict(required=False, type="str", choices=["green", "red", "blue", "melongene", "mariner"]),
        admin_enable_fortiguard=dict(required=False, type="str", choices=["none", "direct", "this-fmg"]),
        admin_fortianalyzer_target=dict(required=False, type="str"),
        admin_fortiguard_target=dict(required=False, type="str"),

        smtp_username=dict(required=False, type="str"),
        smtp_password=dict(required=False, type="str", no_log=True),
        smtp_port=dict(required=False, type="int"),
        smtp_replyto=dict(required=False, type="str"),
        smtp_conn_sec=dict(required=False, type="str", choices=["none", "starttls", "smtps"]),
        smtp_server=dict(required=False, type="str"),
        smtp_source_ipv4=dict(required=False, type="str"),
        smtp_validate_cert=dict(required=False, type="str", choices=["enable", "disable"]),

        dns_suffix=dict(required=False, type="str"),
        dns_primary_ipv4=dict(required=False, type="str"),
        dns_secondary_ipv4=dict(required=False, type="str"),
        delete_provisioning_template=dict(required=False, type="str")
    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    paramgram = {
        "adom": module.params["adom"],
        "mode": module.params["mode"],
        "provision_targets": module.params["provision_targets"],
        "provisioning_template": module.params["provisioning_template"],

        "snmp_status": module.params["snmp_status"],
        "snmp_v2c_query_port": module.params["snmp_v2c_query_port"],
        "snmp_v2c_trap_port": module.params["snmp_v2c_trap_port"],
        "snmp_v2c_status": module.params["snmp_v2c_status"],
        "snmp_v2c_trap_status": module.params["snmp_v2c_trap_status"],
        "snmp_v2c_query_status": module.params["snmp_v2c_query_status"],
        "snmp_v2c_name": module.params["snmp_v2c_name"],
        "snmp_v2c_id": module.params["snmp_v2c_id"],
        "snmp_v2c_trap_src_ipv4": module.params["snmp_v2c_trap_src_ipv4"],
        "snmp_v2c_trap_hosts_ipv4": module.params["snmp_v2c_trap_hosts_ipv4"],
        "snmp_v2c_query_hosts_ipv4": module.params["snmp_v2c_query_hosts_ipv4"],

        "snmpv3_auth_proto": module.params["snmpv3_auth_proto"],
        "snmpv3_auth_pwd": module.params["snmpv3_auth_pwd"],
        "snmpv3_name": module.params["snmpv3_name"],
        "snmpv3_notify_hosts": module.params["snmpv3_notify_hosts"],
        "snmpv3_priv_proto": module.params["snmpv3_priv_proto"],
        "snmpv3_priv_pwd": module.params["snmpv3_priv_pwd"],
        "snmpv3_queries": module.params["snmpv3_queries"],
        "snmpv3_query_port": module.params["snmpv3_query_port"],
        "snmpv3_security_level": module.params["snmpv3_security_level"],
        "snmpv3_source_ip": module.params["snmpv3_source_ip"],
        "snmpv3_status": module.params["snmpv3_status"],
        "snmpv3_trap_rport": module.params["snmpv3_trap_rport"],
        "snmpv3_trap_status": module.params["snmpv3_trap_status"],

        "syslog_port": module.params["syslog_port"],
        "syslog_server": module.params["syslog_server"],
        "syslog_mode": module.params["syslog_mode"],
        "syslog_status": module.params["syslog_status"],
        "syslog_filter": module.params["syslog_filter"],
        "syslog_facility": module.params["syslog_facility"],
        "syslog_enc_algorithm": module.params["syslog_enc_algorithm"],
        "syslog_certificate": module.params["syslog_certificate"],

        "ntp_status": module.params["ntp_status"],
        "ntp_sync_interval": module.params["ntp_sync_interval"],
        "ntp_type": module.params["ntp_type"],
        "ntp_server": module.params["ntp_server"],
        "ntp_auth": module.params["ntp_auth"],
        "ntp_auth_pwd": module.params["ntp_auth_pwd"],
        "ntp_v3": module.params["ntp_v3"],

        "admin_https_redirect": module.params["admin_https_redirect"],
        "admin_https_port": module.params["admin_https_port"],
        "admin_http_port": module.params["admin_http_port"],
        "admin_timeout": module.params["admin_timeout"],
        "admin_language": module.params["admin_language"],
        "admin_switch_controller": module.params["admin_switch_controller"],
        "admin_gui_theme": module.params["admin_gui_theme"],
        "admin_enable_fortiguard": module.params["admin_enable_fortiguard"],
        "admin_fortianalyzer_target": module.params["admin_fortianalyzer_target"],
        "admin_fortiguard_target": module.params["admin_fortiguard_target"],

        "smtp_username": module.params["smtp_username"],
        "smtp_password": module.params["smtp_password"],
        "smtp_port": module.params["smtp_port"],
        "smtp_replyto": module.params["smtp_replyto"],
        "smtp_conn_sec": module.params["smtp_conn_sec"],
        "smtp_server": module.params["smtp_server"],
        "smtp_source_ipv4": module.params["smtp_source_ipv4"],
        "smtp_validate_cert": module.params["smtp_validate_cert"],

        "dns_suffix": module.params["dns_suffix"],
        "dns_primary_ipv4": module.params["dns_primary_ipv4"],
        "dns_secondary_ipv4": module.params["dns_secondary_ipv4"],
        "delete_provisioning_template": module.params["delete_provisioning_template"]
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    results = DEFAULT_RESULT_OBJ
    try:
        # CHECK IF WE ARE DELETING AN ENTIRE TEMPLATE. IF THAT'S THE CASE DO IT FIRST AND IGNORE THE REST.
        if paramgram["delete_provisioning_template"] is not None:
            results = set_devprof(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0, -10, -1],
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram),
                                 stop_on_success=True)
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # CHECK TO SEE IF THE DEVPROF TEMPLATE EXISTS
        devprof = get_devprof(fmgr, paramgram)
        if devprof[0] != 0:
            results = set_devprof(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0, -2], stop_on_success=False,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # PROCESS THE SNMP SETTINGS IF THE SNMP_STATUS VARIABLE IS SET
        if paramgram["snmp_status"] is not None:
            results = set_devprof_snmp(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

        # PROCESS THE SNMP V2C COMMUNITY SETTINGS IF THEY ARE ALL HERE
        if all(v is not None for v in (paramgram["snmp_v2c_query_port"], paramgram["snmp_v2c_trap_port"],
                                       paramgram["snmp_v2c_status"], paramgram["snmp_v2c_trap_status"],
                                       paramgram["snmp_v2c_query_status"], paramgram["snmp_v2c_name"],
                                       paramgram["snmp_v2c_id"])):
            results = set_devprof_snmp_v2c(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0, -10033], stop_on_success=True,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

        # PROCESS THE SNMPV3 USER IF THERE
        if all(v is not None for v in (
                [paramgram["snmpv3_auth_proto"], paramgram["snmpv3_auth_pwd"], paramgram["snmpv3_name"],
                 paramgram["snmpv3_notify_hosts"], paramgram["snmpv3_priv_proto"],
                 paramgram["snmpv3_priv_pwd"],
                 paramgram["snmpv3_queries"],
                 paramgram["snmpv3_query_port"], paramgram["snmpv3_security_level"],
                 paramgram["snmpv3_source_ip"],
                 paramgram["snmpv3_status"], paramgram["snmpv3_trap_rport"], paramgram["snmpv3_trap_status"]])):

            results = set_devprof_snmp_v3(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0, -10033, -10000, -3],
                                 stop_on_success=True,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # PROCESS THE SYSLOG SETTINGS IF THE ALL THE NEEDED SYSLOG VARIABLES ARE PRESENT
        if all(v is not None for v in [paramgram["syslog_port"], paramgram["syslog_mode"],
                                       paramgram["syslog_server"], paramgram["syslog_status"]]):
            # enable syslog in the devprof template
            results = set_devprof_syslog(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0, -10033, -10000, -3],
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # IF THE SYSLOG FILTER IS PRESENT THEN RUN THAT
        if paramgram["syslog_filter"] is not None:
            results = set_devprof_syslog_filter(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0],
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # PROCESS NTP OPTIONS
        if paramgram["ntp_status"]:
            # VALIDATE INPUT
            if paramgram["ntp_type"] == "custom" and paramgram["ntp_server"] is None:
                module.exit_json(msg="You requested custom NTP type but did not provide ntp_server parameter.")
            if paramgram["ntp_auth"] == "enable" and paramgram["ntp_auth_pwd"] is None:
                module.exit_json(
                    msg="You requested NTP Authentication but did not provide ntp_auth_pwd parameter.")

            results = set_devprof_ntp(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0],
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)
    try:
        # PROCESS THE ADMIN OPTIONS
        if any(v is not None for v in (
                paramgram["admin_https_redirect"], paramgram["admin_https_port"], paramgram["admin_http_port"],
                paramgram["admin_timeout"],
                paramgram["admin_language"], paramgram["admin_switch_controller"],
                paramgram["admin_gui_theme"])):

            results = set_devprof_admin(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # PROCESS FORTIGUARD OPTIONS
        if paramgram["admin_enable_fortiguard"] is not None:

            results = set_devprof_toggle_fg(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
            results = set_devprof_fg(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # PROCESS THE SMTP OPTIONS
        if all(v is not None for v in (
                paramgram["smtp_username"], paramgram["smtp_password"], paramgram["smtp_port"],
                paramgram["smtp_replyto"],
                paramgram["smtp_conn_sec"], paramgram["smtp_server"],
                paramgram["smtp_source_ipv4"], paramgram["smtp_validate_cert"])):

            results = set_devprof_smtp(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # PROCESS THE DNS OPTIONS
        if any(v is not None for v in
               (paramgram["dns_suffix"], paramgram["dns_primary_ipv4"], paramgram["dns_secondary_ipv4"])):
            results = set_devprof_dns(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # PROCESS THE admin_fortianalyzer_target OPTIONS
        if paramgram["admin_fortianalyzer_target"] is not None:

            results = set_devprof_faz(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # PROCESS THE PROVISIONING TEMPLATE TARGET PARAMETER
        if paramgram["provision_targets"] is not None:
            if paramgram["mode"] != "delete":
                results = set_devprof_scope(fmgr, paramgram)
                fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False,
                                     ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

            if paramgram["mode"] == "delete":
                # WE NEED TO FIGURE OUT WHAT'S THERE FIRST, BEFORE WE CAN RUN THIS
                targets_to_add = list()
                try:
                    current_scope = get_devprof_scope(fmgr, paramgram)
                    targets_to_remove = paramgram["provision_targets"].strip().split(",")
                    targets = current_scope[1][1]["scope member"]
                    for target in targets:
                        if target["name"] not in targets_to_remove:
                            target_append = {"name": target["name"]}
                            targets_to_add.append(target_append)
                except BaseException:
                    pass
                paramgram["targets_to_add"] = targets_to_add
                results = set_devprof_scope(fmgr, paramgram)
                fmgr.govern_response(module=module, results=results, good_codes=[0, -10033, -10000, -3],
                                     ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function

__metaclass__ = type

ANSIBLE_METADATA = {
    "metadata_version": "1.1",
    "status": ["preview"],
    "supported_by": "community"
}

DOCUMENTATION = '''
---
module: fmgr_device_provision_template
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author:
    - Luke Weighall (@lweighall)
    - Andrew Welsh (@Ghilli3)
    - Jim Huber (@p4r4n0y1ng)
short_description: Manages Device Provisioning Templates in FortiManager.
description:
    - Allows the editing and assignment of device provisioning templates in FortiManager.

options:
  adom:
    description:
     - The ADOM the configuration should belong to.
    required: true

  mode:
    description:
      - Sets one of three modes for managing the object.
      - Allows use of soft-adds instead of overwriting existing values.
    choices: ['add', 'set', 'delete', 'update']
    required: false
    default: add

  device_unique_name:
    description:
     - The unique device's name that you are editing.
    required: True

  provisioning_template:
    description:
     - The provisioning template you want to apply (default = default).
    required: True

  provision_targets:
    description:
     - The friendly names of devices in FortiManager to assign the provisioning template to. Comma separated list.
    required: True

  snmp_status:
    description:
     - Enables or disables SNMP globally.
    required: False
    choices: ["enable", "disable"]

  snmp_v2c_query_port:
    description:
     - Sets the snmp v2c community query port.
    required: False

  snmp_v2c_trap_port:
    description:
     - Sets the snmp v2c community trap port.
    required: False

  snmp_v2c_status:
    description:
     - Enables or disables the v2c community specified.
    required: False
    choices: ["enable", "disable"]

  snmp_v2c_trap_status:
    description:
     - Enables or disables the v2c community specified for traps.
    required: False
    choices: ["enable", "disable"]

  snmp_v2c_query_status:
    description:
     - Enables or disables the v2c community specified for queries.
    required: False
    choices: ["enable", "disable"]

  snmp_v2c_name:
    description:
     - Specifies the v2c community name.
    required: False

  snmp_v2c_id:
    description:
     - Primary key for the snmp community. this must be unique!
    required: False

  snmp_v2c_trap_src_ipv4:
    description:
     - Source ip the traps should come from IPv4.
    required: False

  snmp_v2c_trap_hosts_ipv4:
    description: >
       - IPv4 addresses of the hosts that should get SNMP v2c traps, comma separated, must include mask
       ("10.7.220.59 255.255.255.255, 10.7.220.60 255.255.255.255").
    required: False

  snmp_v2c_query_hosts_ipv4:
    description: >
       - IPv4 addresses or subnets that are allowed to query SNMP v2c, comma separated
       ("10.7.220.59 255.255.255.0, 10.7.220.0 255.255.255.0").
    required: False

  snmpv3_auth_proto:
    description:
        - SNMPv3 auth protocol.
    required: False
    choices: ["md5", "sha"]

  snmpv3_auth_pwd:
    description:
        - SNMPv3 auth pwd __ currently not encrypted! ensure this file is locked down permissions wise!
    required: False

  snmpv3_name:
    description:
      - SNMPv3 user name.
    required: False

  snmpv3_notify_hosts:
    description:
      - List of ipv4 hosts to send snmpv3 traps to. Comma separated IPv4 list.
    required: False

  snmpv3_priv_proto:
    description:
      - SNMPv3 priv protocol.
    required: False
    choices: ["aes", "des", "aes256", "aes256cisco"]

  snmpv3_priv_pwd:
    description:
     - SNMPv3 priv pwd currently not encrypted! ensure this file is locked down permissions wise!
    required: False

  snmpv3_queries:
    description:
     - Allow snmpv3_queries.
    required: False
    choices: ["enable", "disable"]

  snmpv3_query_port:
    description:
     - SNMPv3 query port.
    required: False

  snmpv3_security_level:
    description:
     - SNMPv3 security level.
    required: False
    choices: ["no-auth-no-priv", "auth-no-priv", "auth-priv"]

  snmpv3_source_ip:
    description:
     - SNMPv3 source ipv4 address for traps.
    required: False

  snmpv3_status:
    description:
     - SNMPv3 user is enabled or disabled.
    required: False
    choices: ["enable", "disable"]

  snmpv3_trap_rport:
    description:
     - SNMPv3 trap remote port.
    required: False

  snmpv3_trap_status:
    description:
     - SNMPv3 traps is enabled or disabled.
    required: False
    choices: ["enable", "disable"]

  syslog_port:
    description:
     - Syslog port that will be set.
    required: False

  syslog_server:
    description:
     - Server the syslogs will be sent to.
    required: False

  syslog_status:
    description:
     - Enables or disables syslogs.
    required: False
    choices: ["enable", "disable"]

  syslog_mode:
    description:
     - Remote syslog logging over UDP/Reliable TCP.
     - choice | udp | Enable syslogging over UDP.
     - choice | legacy-reliable | Enable legacy reliable syslogging by RFC3195 (Reliable Delivery for Syslog).
     - choice | reliable | Enable reliable syslogging by RFC6587 (Transmission of Syslog Messages over TCP).
    required: false
    choices: ["udp", "legacy-reliable", "reliable"]
    default: "udp"

  syslog_filter:
    description:
     - Sets the logging level for syslog.
    required: False
    choices: ["emergency", "alert", "critical", "error", "warning", "notification", "information", "debug"]

  syslog_facility:
    description:
     - Remote syslog facility.
     - choice | kernel | Kernel messages.
     - choice | user | Random user-level messages.
     - choice | mail | Mail system.
     - choice | daemon | System daemons.
     - choice | auth | Security/authorization messages.
     - choice | syslog | Messages generated internally by syslog.
     - choice | lpr | Line printer subsystem.
     - choice | news | Network news subsystem.
     - choice | uucp | Network news subsystem.
     - choice | cron | Clock daemon.
     - choice | authpriv | Security/authorization messages (private).
     - choice | ftp | FTP daemon.
     - choice | ntp | NTP daemon.
     - choice | audit | Log audit.
     - choice | alert | Log alert.
     - choice | clock | Clock daemon.
     - choice | local0 | Reserved for local use.
     - choice | local1 | Reserved for local use.
     - choice | local2 | Reserved for local use.
     - choice | local3 | Reserved for local use.
     - choice | local4 | Reserved for local use.
     - choice | local5 | Reserved for local use.
     - choice | local6 | Reserved for local use.
     - choice | local7 | Reserved for local use.
    required: false
    choices: ["kernel", "user", "mail", "daemon", "auth", "syslog",
        "lpr", "news", "uucp", "cron", "authpriv", "ftp", "ntp", "audit",
        "alert", "clock", "local0", "local1", "local2", "local3", "local4", "local5", "local6", "local7"]
    default: "syslog"

  syslog_enc_algorithm:
    description:
     - Enable/disable reliable syslogging with TLS encryption.
     - choice | high | SSL communication with high encryption algorithms.
     - choice | low | SSL communication with low encryption algorithms.
     - choice | disable | Disable SSL communication.
     - choice | high-medium | SSL communication with high and medium encryption algorithms.
    required: false
    choices: ["high", "low", "disable", "high-medium"]
    default: "disable"

  syslog_certificate:
    description:
     - Certificate used to communicate with Syslog server if encryption on.
    required: false

  ntp_status:
    description:
      - Enables or disables ntp.
    required: False
    choices: ["enable", "disable"]

  ntp_sync_interval:
    description:
     - Sets the interval in minutes for ntp sync.
    required: False

  ntp_type:
    description:
     - Enables fortiguard servers or custom servers are the ntp source.
    required: False
    choices: ["fortiguard", "custom"]

  ntp_server:
    description:
     - Only used with custom ntp_type -- specifies IP of server to sync to -- comma separated ip addresses for multiples.
    required: False

  ntp_auth:
    description:
     - Enables or disables ntp authentication.
    required: False
    choices: ["enable", "disable"]

  ntp_auth_pwd:
    description:
     - Sets the ntp auth password.
    required: False

  ntp_v3:
    description:
     - Enables or disables ntpv3 (default is ntpv4).
    required: False
    choices: ["enable", "disable"]

  admin_https_redirect:
    description:
     - Enables or disables https redirect from http.
    required: False
    choices: ["enable", "disable"]

  admin_https_port:
    description:
     - SSL admin gui port number.
    required: False

  admin_http_port:
    description:
     - Non-SSL admin gui port number.
    required: False

  admin_timeout:
    description:
     - Admin timeout in minutes.
    required: False

  admin_language:
    description:
     - Sets the admin gui language.
    required: False
    choices: ["english", "simch", "japanese", "korean", "spanish", "trach", "french", "portuguese"]

  admin_switch_controller:
    description:
     - Enables or disables the switch controller.
    required: False
    choices: ["enable", "disable"]

  admin_gui_theme:
    description:
     - Changes the admin gui theme.
    required: False
    choices: ["green", "red", "blue", "melongene", "mariner"]

  admin_enable_fortiguard:
    description:
     - Enables FortiGuard security updates to their default settings.
    required: False
    choices: ["none", "direct", "this-fmg"]

  admin_fortianalyzer_target:
    description:
     - Configures faz target.
    required: False

  admin_fortiguard_target:
    description:
     - Configures fortiguard target.
     - admin_enable_fortiguard must be set to "direct".
    required: False

  smtp_username:
    description:
     - SMTP auth username.
    required: False

  smtp_password:
    description:
     - SMTP password.
    required: False

  smtp_port:
    description:
     - SMTP port number.
    required: False

  smtp_replyto:
    description:
     - SMTP reply to address.
    required: False

  smtp_conn_sec:
    description:
     - defines the ssl level for smtp.
    required: False
    choices: ["none", "starttls", "smtps"]

  smtp_server:
    description:
     - SMTP server ipv4 address.
    required: False

  smtp_source_ipv4:
    description:
     - SMTP source ip address.
    required: False

  smtp_validate_cert:
    description:
     - Enables or disables valid certificate checking for smtp.
    required: False
    choices: ["enable", "disable"]

  dns_suffix:
    description:
     - Sets the local dns domain suffix.
    required: False

  dns_primary_ipv4:
    description:
     - primary ipv4 dns forwarder.
    required: False

  dns_secondary_ipv4:
    description:
     - secondary ipv4 dns forwarder.
    required: False

  delete_provisioning_template:
    description:
     -  If specified, all other options are ignored. The specified provisioning template will be deleted.
    required: False

'''


EXAMPLES = '''
- name: SET SNMP SYSTEM INFO
  fmgr_device_provision_template:
    provisioning_template: "default"
    snmp_status: "enable"
    mode: "set"

- name: SET SNMP SYSTEM INFO ANSIBLE ADOM
  fmgr_device_provision_template:
    provisioning_template: "default"
    snmp_status: "enable"
    mode: "set"
    adom: "ansible"

- name: SET SNMP SYSTEM INFO different template (SNMPv2)
  fmgr_device_provision_template:
    provisioning_template: "ansibleTest"
    snmp_status: "enable"
    mode: "set"
    adom: "ansible"
    snmp_v2c_query_port: "162"
    snmp_v2c_trap_port: "161"
    snmp_v2c_status: "enable"
    snmp_v2c_trap_status: "enable"
    snmp_v2c_query_status: "enable"
    snmp_v2c_name: "ansibleV2c"
    snmp_v2c_id: "1"
    snmp_v2c_trap_src_ipv4: "10.7.220.41"
    snmp_v2c_trap_hosts_ipv4: "10.7.220.59 255.255.255.255, 10.7.220.60 255.255.255.255"
    snmp_v2c_query_hosts_ipv4: "10.7.220.59 255.255.255.255, 10.7.220.0 255.255.255.0"

- name: SET SNMP SYSTEM INFO different template (SNMPv3)
  fmgr_device_provision_template:
    provisioning_template: "ansibleTest"
    snmp_status: "enable"
    mode: "set"
    adom: "ansible"
    snmpv3_auth_proto: "sha"
    snmpv3_auth_pwd: "fortinet"
    snmpv3_name: "ansibleSNMPv3"
    snmpv3_notify_hosts: "10.7.220.59,10.7.220.60"
    snmpv3_priv_proto: "aes256"
    snmpv3_priv_pwd: "fortinet"
    snmpv3_queries: "enable"
    snmpv3_query_port: "161"
    snmpv3_security_level: "auth_priv"
    snmpv3_source_ip: "0.0.0.0"
    snmpv3_status: "enable"
    snmpv3_trap_rport: "162"
    snmpv3_trap_status: "enable"

- name: SET SYSLOG INFO
  fmgr_device_provision_template:
    provisioning_template: "ansibleTest"
    mode: "set"
    adom: "ansible"
    syslog_server: "10.7.220.59"
    syslog_port: "514"
    syslog_mode: "disable"
    syslog_status: "enable"
    syslog_filter: "information"

- name: SET NTP TO FORTIGUARD
  fmgr_device_provision_template:
    provisioning_template: "ansibleTest"
    mode: "set"
    adom: "ansible"
    ntp_status: "enable"
    ntp_sync_interval: "60"
    type: "fortiguard"

- name: SET NTP TO CUSTOM SERVER
  fmgr_device_provision_template:
    provisioning_template: "ansibleTest"
    mode: "set"
    adom: "ansible"
    ntp_status: "enable"
    ntp_sync_interval: "60"
    ntp_type: "custom"
    ntp_server: "10.7.220.32,10.7.220.1"
    ntp_auth: "enable"
    ntp_auth_pwd: "fortinet"
    ntp_v3: "disable"

- name: SET ADMIN GLOBAL SETTINGS
  fmgr_device_provision_template:
    provisioning_template: "ansibleTest"
    mode: "set"
    adom: "ansible"
    admin_https_redirect: "enable"
    admin_https_port: "4433"
    admin_http_port: "8080"
    admin_timeout: "30"
    admin_language: "english"
    admin_switch_controller: "enable"
    admin_gui_theme: "blue"
    admin_enable_fortiguard: "direct"
    admin_fortiguard_target: "10.7.220.128"
    admin_fortianalyzer_target: "10.7.220.61"

- name: SET CUSTOM SMTP SERVER
  fmgr_device_provision_template:
    provisioning_template: "ansibleTest"
    mode: "set"
    adom: "ansible"
    smtp_username: "ansible"
    smtp_password: "fortinet"
    smtp_port: "25"
    smtp_replyto: "ansible@do-not-reply.com"
    smtp_conn_sec: "starttls"
    smtp_server: "10.7.220.32"
    smtp_source_ipv4: "0.0.0.0"
    smtp_validate_cert: "disable"

- name: SET DNS SERVERS
  fmgr_device_provision_template:
    provisioning_template: "ansibleTest"
    mode: "set"
    adom: "ansible"
    dns_suffix: "ansible.local"
    dns_primary_ipv4: "8.8.8.8"
    dns_secondary_ipv4: "4.4.4.4"

- name: SET PROVISIONING TEMPLATE DEVICE TARGETS IN FORTIMANAGER
  fmgr_device_provision_template:
    provisioning_template: "ansibleTest"
    mode: "set"
    adom: "ansible"
    provision_targets: "FGT1, FGT2"

- name: DELETE ENTIRE PROVISIONING TEMPLATE
  fmgr_device_provision_template:
    delete_provisioning_template: "ansibleTest"
    mode: "delete"
    adom: "ansible"

'''
RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import FMGRMethods
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG


def get_devprof(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    response = DEFAULT_RESULT_OBJ
    datagram = {}

    url = "/pm/devprof/adom/{adom}/{name}".format(adom=paramgram["adom"], name=paramgram["provisioning_template"])
    response = fmgr.process_request(url, datagram, FMGRMethods.GET)

    return response


def set_devprof(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    response = DEFAULT_RESULT_OBJ
    if paramgram["mode"] in ['set', 'add', 'update']:
        datagram = {
            "name": paramgram["provisioning_template"],
            "type": "devprof",
            "description": "CreatedByAnsible",
        }
        url = "/pm/devprof/adom/{adom}".format(adom=paramgram["adom"])

    elif paramgram["mode"] == "delete":
        datagram = {}

        url = "/pm/devprof/adom/{adom}/{name}".format(adom=paramgram["adom"],
                                                      name=paramgram["delete_provisioning_template"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


def get_devprof_scope(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    response = DEFAULT_RESULT_OBJ
    datagram = {
        "name": paramgram["provisioning_template"],
        "type": "devprof",
        "description": "CreatedByAnsible",
    }

    url = "/pm/devprof/adom/{adom}".format(adom=paramgram["adom"])
    response = fmgr.process_request(url, datagram, FMGRMethods.GET)

    return response


def set_devprof_scope(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    response = DEFAULT_RESULT_OBJ
    if paramgram["mode"] in ['set', 'add', 'update']:
        datagram = {
            "name": paramgram["provisioning_template"],
            "type": "devprof",
            "description": "CreatedByAnsible",
        }

        targets = []
        for target in paramgram["provision_targets"].split(","):
            # split the host on the space to get the mask out
            new_target = {"name": target.strip()}
            targets.append(new_target)

        datagram["scope member"] = targets

        url = "/pm/devprof/adom/{adom}".format(adom=paramgram["adom"])

    elif paramgram["mode"] == "delete":
        datagram = {
            "name": paramgram["provisioning_template"],
            "type": "devprof",
            "description": "CreatedByAnsible",
            "scope member": paramgram["targets_to_add"]
        }

        url = "/pm/devprof/adom/{adom}".format(adom=paramgram["adom"])

    response = fmgr.process_request(url, datagram, FMGRMethods.SET)
    return response


def set_devprof_snmp(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    paramgram["mode"] = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    datagram = {
        "status": paramgram["snmp_status"]
    }
    url = "/pm/config/adom/{adom}/devprof/" \
          "{provisioning_template}/system/snmp/sysinfo".format(adom=adom,
                                                               provisioning_template=paramgram["provisioning_template"])

    response = fmgr.process_request(url, datagram, FMGRMethods.SET)
    return response


def set_devprof_snmp_v2c(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    paramgram["mode"] = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    if paramgram["mode"] in ['set', 'add', 'update']:
        datagram = {
            "query-v2c-port": paramgram["snmp_v2c_query_port"],
            "trap-v2c-rport": paramgram["snmp_v2c_trap_port"],
            "status": paramgram["snmp_v2c_status"],
            "trap-v2c-status": paramgram["snmp_v2c_trap_status"],
            "query-v2c-status": paramgram["snmp_v2c_query_status"],
            "name": paramgram["snmp_v2c_name"],
            "id": paramgram["snmp_v2c_id"],
            "meta fields": dict(),
            "hosts": list(),
            "events": 411578417151,
            "query-v1-status": 0,
            "query-v1-port": 161,
            "trap-v1-status": 0,
            "trap-v1-lport": 162,
            "trap-v1-rport": 162,
            "trap-v2c-lport": 162,
        }

        # BUILD THE HOST STRINGS
        id_counter = 1
        if paramgram["snmp_v2c_trap_hosts_ipv4"] or paramgram["snmp_v2c_query_hosts_ipv4"]:
            hosts = []
            if paramgram["snmp_v2c_query_hosts_ipv4"]:
                for ipv4_host in paramgram["snmp_v2c_query_hosts_ipv4"].strip().split(","):
                    # split the host on the space to get the mask out
                    new_ipv4_host = {"ha-direct": "enable",
                                     "host-type": "query",
                                     "id": id_counter,
                                     "ip": ipv4_host.strip().split(),
                                     "meta fields": {},
                                     "source-ip": "0.0.0.0"}
                    hosts.append(new_ipv4_host)
                    id_counter += 1

            if paramgram["snmp_v2c_trap_hosts_ipv4"]:
                for ipv4_host in paramgram["snmp_v2c_trap_hosts_ipv4"].strip().split(","):
                    # split the host on the space to get the mask out
                    new_ipv4_host = {"ha-direct": "enable",
                                     "host-type": "trap",
                                     "id": id_counter,
                                     "ip": ipv4_host.strip().split(),
                                     "meta fields": {},
                                     "source-ip": paramgram["snmp_v2c_trap_src_ipv4"]}
                    hosts.append(new_ipv4_host)
                    id_counter += 1
            datagram["hosts"] = hosts

        url = "/pm/config/adom/{adom}/devprof/" \
              "{provisioning_template}/system/snmp/community".format(adom=adom,
                                                                     provisioning_template=paramgram[
                                                                         "provisioning_template"])
    elif paramgram["mode"] == "delete":
        datagram = {
            "confirm": 1
        }

        url = "/pm/config/adom/{adom}/" \
              "devprof/{provisioning_template}/" \
              "system/snmp/community/{snmp_v2c_id}".format(adom=adom,
                                                           provisioning_template=paramgram["provisioning_template"],
                                                           snmp_v2c_id=paramgram["snmp_v2c_id"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


def set_devprof_snmp_v3(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    paramgram["mode"] = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    if paramgram["mode"] in ['set', 'add', 'update']:
        datagram = {}
        datagram["auth-pwd"] = paramgram["snmpv3_auth_pwd"]
        datagram["priv-pwd"] = paramgram["snmpv3_priv_pwd"]
        datagram["trap-rport"] = paramgram["snmpv3_trap_rport"]
        datagram["query-port"] = paramgram["snmpv3_query_port"]
        datagram["name"] = paramgram["snmpv3_name"]
        datagram["notify-hosts"] = paramgram["snmpv3_notify_hosts"].strip().split(",")
        datagram["events"] = 1647387997183
        datagram["trap-lport"] = 162

        datagram["source-ip"] = paramgram["snmpv3_source_ip"]
        datagram["ha-direct"] = 0

        url = "/pm/config/adom/{adom}/" \
              "devprof/{provisioning_template}/" \
              "system/snmp/user".format(adom=adom,
                                        provisioning_template=paramgram["provisioning_template"])
    elif paramgram["mode"] == "delete":
        datagram = {
            "confirm": 1
        }

        url = "/pm/config/adom/{adom}/devprof/" \
              "{provisioning_template}/system/snmp" \
              "/user/{snmpv3_name}".format(adom=adom,
                                           provisioning_template=paramgram["provisioning_template"],
                                           snmpv3_name=paramgram["snmpv3_name"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


def set_devprof_syslog(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    paramgram["mode"] = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ

    datagram = {
        "status": paramgram["syslog_status"],
        "port": paramgram["syslog_port"],
        "server": paramgram["syslog_server"],
        "mode": paramgram["syslog_mode"],
        "facility": paramgram["syslog_facility"]
    }

    if paramgram["mode"] in ['set', 'add', 'update']:
        if paramgram["syslog_enc_algorithm"] in ["high", "low", "high-medium"] \
                and paramgram["syslog_certificate"] is not None:
            datagram["certificate"] = paramgram["certificate"]
            datagram["enc-algorithm"] = paramgram["syslog_enc_algorithm"]

        url = "/pm/config/adom/{adom}/" \
              "devprof/{provisioning_template}/" \
              "log/syslogd/setting".format(adom=adom,
                                           provisioning_template=paramgram["provisioning_template"])
    elif paramgram["mode"] == "delete":
        url = "/pm/config/adom/{adom}/" \
              "devprof/{provisioning_template}/" \
              "log/syslogd/setting".format(adom=adom,
                                           provisioning_template=paramgram["provisioning_template"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


def set_devprof_syslog_filter(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    paramgram["mode"] = paramgram["mode"]
    adom = paramgram["adom"]
    datagram = {
        "severity": paramgram["syslog_filter"]
    }
    response = DEFAULT_RESULT_OBJ

    url = "/pm/config/adom/{adom}" \
          "/devprof/{provisioning_template}" \
          "/log/syslogd/filter".format(adom=adom,
                                       provisioning_template=paramgram["provisioning_template"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


def set_devprof_ntp(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    paramgram["mode"] = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ

    # IF SET TO FORTIGUARD, BUILD A STRING SPECIFIC TO THAT
    if paramgram["ntp_type"] == "fortiguard":
        datagram = {}
        if paramgram["ntp_status"] == "enable":
            datagram["ntpsync"] = 1
        if paramgram["ntp_status"] == "disable":
            datagram["ntpsync"] = 0
        if paramgram["ntp_sync_interval"] is None:
            datagram["syncinterval"] = 1
        else:
            datagram["syncinterval"] = paramgram["ntp_sync_interval"]

        datagram["type"] = 0

    # IF THE NTP TYPE IS CUSTOM BUILD THE SERVER LIST
    if paramgram["ntp_type"] == "custom":
        id_counter = 0
        key_counter = 0
        ntpservers = []
        datagram = {}
        if paramgram["ntp_status"] == "enable":
            datagram["ntpsync"] = 1
        if paramgram["ntp_status"] == "disable":
            datagram["ntpsync"] = 0
        try:
            datagram["syncinterval"] = paramgram["ntp_sync_interval"]
        except BaseException:
            datagram["syncinterval"] = 1
        datagram["type"] = 1

        for server in paramgram["ntp_server"].strip().split(","):
            id_counter += 1
            server_fields = dict()

            key_counter += 1
            if paramgram["ntp_auth"] == "enable":
                server_fields["authentication"] = 1
                server_fields["key"] = paramgram["ntp_auth_pwd"]
                server_fields["key-id"] = key_counter
            else:
                server_fields["authentication"] = 0
                server_fields["key"] = ""
                server_fields["key-id"] = key_counter

            if paramgram["ntp_v3"] == "enable":
                server_fields["ntp_v3"] = 1
            else:
                server_fields["ntp_v3"] = 0

            # split the host on the space to get the mask out
            new_ntp_server = {"authentication": server_fields["authentication"],
                              "id": id_counter, "key": server_fields["key"],
                              "key-id": id_counter, "ntpv3": server_fields["ntp_v3"],
                              "server": server}
            ntpservers.append(new_ntp_server)
        datagram["ntpserver"] = ntpservers

    url = "/pm/config/adom/{adom}" \
          "/devprof/{provisioning_template}" \
          "/system/ntp".format(adom=adom,
                               provisioning_template=paramgram["provisioning_template"])
    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


def set_devprof_admin(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    paramgram["mode"] = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    datagram = {
        "admin-https-redirect": paramgram["admin_https_redirect"],
        "admin-port": paramgram["admin_http_port"],
        "admin-sport": paramgram["admin_https_port"],
        "admintimeout": paramgram["admin_timeout"],
        "language": paramgram["admin_language"],
        "gui-theme": paramgram["admin_gui_theme"],
        "switch-controller": paramgram["admin_switch_controller"],
    }
    url = "/pm/config/adom/{adom}" \
          "/devprof/{provisioning_template}" \
          "/system/global".format(adom=adom,
                                  provisioning_template=paramgram["provisioning_template"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


def set_devprof_smtp(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    paramgram["mode"] = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    datagram = {
        "port": paramgram["smtp_port"],
        "reply-to": paramgram["smtp_replyto"],
        "server": paramgram["smtp_server"],
        "source-ip": paramgram["smtp_source_ipv4"]
    }

    if paramgram["smtp_username"]:
        datagram["authenticate"] = 1
        datagram["username"] = paramgram["smtp_username"]
        datagram["password"] = paramgram["smtp_password"]

    if paramgram["smtp_conn_sec"] == "none":
        datagram["security"] = 0
    if paramgram["smtp_conn_sec"] == "starttls":
        datagram["security"] = 1
    if paramgram["smtp_conn_sec"] == "smtps":
        datagram["security"] = 2

    if paramgram["smtp_validate_cert"] == "enable":
        datagram["validate-server"] = 1
    else:
        datagram["validate-server"] = 0

    url = "/pm/config/adom/{adom}" \
          "/devprof/{provisioning_template}" \
          "/system/email-server".format(adom=adom,
                                        provisioning_template=paramgram["provisioning_template"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


def set_devprof_dns(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    paramgram["mode"] = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    datagram = {
        "domain": paramgram["dns_suffix"],
        "primary": paramgram["dns_primary_ipv4"],
        "secondary": paramgram["dns_secondary_ipv4"],
    }
    url = "/pm/config/adom/{adom}" \
          "/devprof/{provisioning_template}" \
          "/system/dns".format(adom=adom,
                               provisioning_template=paramgram["provisioning_template"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


def set_devprof_toggle_fg(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    paramgram["mode"] = paramgram["mode"]
    adom = paramgram["adom"]
    response = DEFAULT_RESULT_OBJ
    datagram = {}
    if paramgram["admin_enable_fortiguard"] in ["direct", "this-fmg"]:
        datagram["include-default-servers"] = "enable"
    elif paramgram["admin_enable_fortiguard"] == "none":
        datagram["include-default-servers"] = "disable"

    datagram["server-list"] = list()

    url = "/pm/config/adom/{adom}" \
          "/devprof/{provisioning_template}" \
          "/system/central-management".format(adom=adom,
                                              provisioning_template=paramgram["provisioning_template"])
    response = fmgr.process_request(url, datagram, FMGRMethods.SET)

    return response


def set_devprof_fg(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    paramgram["mode"] = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    datagram = {
        "target": paramgram["admin_enable_fortiguard"],
        "target-ip": None
    }

    if paramgram["mode"] in ['set', 'add', 'update']:
        if paramgram["admin_fortiguard_target"] is not None and datagram["target"] == "direct":
            datagram["target-ip"] = paramgram["admin_fortiguard_target"]

    url = "/pm/config/adom/{adom}" \
          "/devprof/{provisioning_template}" \
          "/device/profile/fortiguard".format(adom=adom,
                                              provisioning_template=paramgram["provisioning_template"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


def set_devprof_faz(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    paramgram["mode"] = paramgram["mode"]
    adom = paramgram["adom"]
    response = DEFAULT_RESULT_OBJ
    datagram = {
        "target-ip": paramgram["admin_fortianalyzer_target"],
        "target": "others",
    }
    url = "/pm/config/adom/{adom}" \
          "/devprof/{provisioning_template}" \
          "/device/profile/fortianalyzer".format(adom=adom,
                                                 provisioning_template=paramgram["provisioning_template"])
    if paramgram["mode"] == "delete":
        datagram["hastarget"] = "False"

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


def main():
    argument_spec = dict(
        adom=dict(required=False, type="str"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        provisioning_template=dict(required=False, type="str"),
        provision_targets=dict(required=False, type="str"),

        device_unique_name=dict(required=False, type="str"),
        snmp_status=dict(required=False, type="str", choices=["enable", "disable"]),
        snmp_v2c_query_port=dict(required=False, type="int"),
        snmp_v2c_trap_port=dict(required=False, type="int"),
        snmp_v2c_status=dict(required=False, type="str", choices=["enable", "disable"]),
        snmp_v2c_trap_status=dict(required=False, type="str", choices=["enable", "disable"]),
        snmp_v2c_query_status=dict(required=False, type="str", choices=["enable", "disable"]),
        snmp_v2c_name=dict(required=False, type="str", no_log=True),
        snmp_v2c_id=dict(required=False, type="int"),
        snmp_v2c_trap_src_ipv4=dict(required=False, type="str"),
        snmp_v2c_trap_hosts_ipv4=dict(required=False, type="str"),
        snmp_v2c_query_hosts_ipv4=dict(required=False, type="str"),

        snmpv3_auth_proto=dict(required=False, type="str", choices=["md5", "sha"]),
        snmpv3_auth_pwd=dict(required=False, type="str", no_log=True),
        snmpv3_name=dict(required=False, type="str"),
        snmpv3_notify_hosts=dict(required=False, type="str"),
        snmpv3_priv_proto=dict(required=False, type="str", choices=["aes", "des", "aes256", "aes256cisco"]),
        snmpv3_priv_pwd=dict(required=False, type="str", no_log=True),
        snmpv3_queries=dict(required=False, type="str", choices=["enable", "disable"]),
        snmpv3_query_port=dict(required=False, type="int"),
        snmpv3_security_level=dict(required=False, type="str",
                                   choices=["no-auth-no-priv", "auth-no-priv", "auth-priv"]),
        snmpv3_source_ip=dict(required=False, type="str"),
        snmpv3_status=dict(required=False, type="str", choices=["enable", "disable"]),
        snmpv3_trap_rport=dict(required=False, type="int"),
        snmpv3_trap_status=dict(required=False, type="str", choices=["enable", "disable"]),

        syslog_port=dict(required=False, type="int"),
        syslog_server=dict(required=False, type="str"),
        syslog_mode=dict(required=False, type="str", choices=["udp", "legacy-reliable", "reliable"], default="udp"),
        syslog_status=dict(required=False, type="str", choices=["enable", "disable"]),
        syslog_filter=dict(required=False, type="str", choices=["emergency", "alert", "critical", "error",
                                                                "warning", "notification", "information", "debug"]),
        syslog_enc_algorithm=dict(required=False, type="str", choices=["high", "low", "disable", "high-medium"],
                                  default="disable"),
        syslog_facility=dict(required=False, type="str", choices=["kernel", "user", "mail", "daemon", "auth",
                                                                  "syslog", "lpr", "news", "uucp", "cron", "authpriv",
                                                                  "ftp", "ntp", "audit", "alert", "clock", "local0",
                                                                  "local1", "local2", "local3", "local4", "local5",
                                                                  "local6", "local7"], default="syslog"),
        syslog_certificate=dict(required=False, type="str"),

        ntp_status=dict(required=False, type="str", choices=["enable", "disable"]),
        ntp_sync_interval=dict(required=False, type="int"),
        ntp_type=dict(required=False, type="str", choices=["fortiguard", "custom"]),
        ntp_server=dict(required=False, type="str"),
        ntp_auth=dict(required=False, type="str", choices=["enable", "disable"]),
        ntp_auth_pwd=dict(required=False, type="str", no_log=True),
        ntp_v3=dict(required=False, type="str", choices=["enable", "disable"]),

        admin_https_redirect=dict(required=False, type="str", choices=["enable", "disable"]),
        admin_https_port=dict(required=False, type="int"),
        admin_http_port=dict(required=False, type="int"),
        admin_timeout=dict(required=False, type="int"),
        admin_language=dict(required=False, type="str",
                            choices=["english", "simch", "japanese", "korean",
                                     "spanish", "trach", "french", "portuguese"]),
        admin_switch_controller=dict(required=False, type="str", choices=["enable", "disable"]),
        admin_gui_theme=dict(required=False, type="str", choices=["green", "red", "blue", "melongene", "mariner"]),
        admin_enable_fortiguard=dict(required=False, type="str", choices=["none", "direct", "this-fmg"]),
        admin_fortianalyzer_target=dict(required=False, type="str"),
        admin_fortiguard_target=dict(required=False, type="str"),

        smtp_username=dict(required=False, type="str"),
        smtp_password=dict(required=False, type="str", no_log=True),
        smtp_port=dict(required=False, type="int"),
        smtp_replyto=dict(required=False, type="str"),
        smtp_conn_sec=dict(required=False, type="str", choices=["none", "starttls", "smtps"]),
        smtp_server=dict(required=False, type="str"),
        smtp_source_ipv4=dict(required=False, type="str"),
        smtp_validate_cert=dict(required=False, type="str", choices=["enable", "disable"]),

        dns_suffix=dict(required=False, type="str"),
        dns_primary_ipv4=dict(required=False, type="str"),
        dns_secondary_ipv4=dict(required=False, type="str"),
        delete_provisioning_template=dict(required=False, type="str")
    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    paramgram = {
        "adom": module.params["adom"],
        "mode": module.params["mode"],
        "provision_targets": module.params["provision_targets"],
        "provisioning_template": module.params["provisioning_template"],

        "snmp_status": module.params["snmp_status"],
        "snmp_v2c_query_port": module.params["snmp_v2c_query_port"],
        "snmp_v2c_trap_port": module.params["snmp_v2c_trap_port"],
        "snmp_v2c_status": module.params["snmp_v2c_status"],
        "snmp_v2c_trap_status": module.params["snmp_v2c_trap_status"],
        "snmp_v2c_query_status": module.params["snmp_v2c_query_status"],
        "snmp_v2c_name": module.params["snmp_v2c_name"],
        "snmp_v2c_id": module.params["snmp_v2c_id"],
        "snmp_v2c_trap_src_ipv4": module.params["snmp_v2c_trap_src_ipv4"],
        "snmp_v2c_trap_hosts_ipv4": module.params["snmp_v2c_trap_hosts_ipv4"],
        "snmp_v2c_query_hosts_ipv4": module.params["snmp_v2c_query_hosts_ipv4"],

        "snmpv3_auth_proto": module.params["snmpv3_auth_proto"],
        "snmpv3_auth_pwd": module.params["snmpv3_auth_pwd"],
        "snmpv3_name": module.params["snmpv3_name"],
        "snmpv3_notify_hosts": module.params["snmpv3_notify_hosts"],
        "snmpv3_priv_proto": module.params["snmpv3_priv_proto"],
        "snmpv3_priv_pwd": module.params["snmpv3_priv_pwd"],
        "snmpv3_queries": module.params["snmpv3_queries"],
        "snmpv3_query_port": module.params["snmpv3_query_port"],
        "snmpv3_security_level": module.params["snmpv3_security_level"],
        "snmpv3_source_ip": module.params["snmpv3_source_ip"],
        "snmpv3_status": module.params["snmpv3_status"],
        "snmpv3_trap_rport": module.params["snmpv3_trap_rport"],
        "snmpv3_trap_status": module.params["snmpv3_trap_status"],

        "syslog_port": module.params["syslog_port"],
        "syslog_server": module.params["syslog_server"],
        "syslog_mode": module.params["syslog_mode"],
        "syslog_status": module.params["syslog_status"],
        "syslog_filter": module.params["syslog_filter"],
        "syslog_facility": module.params["syslog_facility"],
        "syslog_enc_algorithm": module.params["syslog_enc_algorithm"],
        "syslog_certificate": module.params["syslog_certificate"],

        "ntp_status": module.params["ntp_status"],
        "ntp_sync_interval": module.params["ntp_sync_interval"],
        "ntp_type": module.params["ntp_type"],
        "ntp_server": module.params["ntp_server"],
        "ntp_auth": module.params["ntp_auth"],
        "ntp_auth_pwd": module.params["ntp_auth_pwd"],
        "ntp_v3": module.params["ntp_v3"],

        "admin_https_redirect": module.params["admin_https_redirect"],
        "admin_https_port": module.params["admin_https_port"],
        "admin_http_port": module.params["admin_http_port"],
        "admin_timeout": module.params["admin_timeout"],
        "admin_language": module.params["admin_language"],
        "admin_switch_controller": module.params["admin_switch_controller"],
        "admin_gui_theme": module.params["admin_gui_theme"],
        "admin_enable_fortiguard": module.params["admin_enable_fortiguard"],
        "admin_fortianalyzer_target": module.params["admin_fortianalyzer_target"],
        "admin_fortiguard_target": module.params["admin_fortiguard_target"],

        "smtp_username": module.params["smtp_username"],
        "smtp_password": module.params["smtp_password"],
        "smtp_port": module.params["smtp_port"],
        "smtp_replyto": module.params["smtp_replyto"],
        "smtp_conn_sec": module.params["smtp_conn_sec"],
        "smtp_server": module.params["smtp_server"],
        "smtp_source_ipv4": module.params["smtp_source_ipv4"],
        "smtp_validate_cert": module.params["smtp_validate_cert"],

        "dns_suffix": module.params["dns_suffix"],
        "dns_primary_ipv4": module.params["dns_primary_ipv4"],
        "dns_secondary_ipv4": module.params["dns_secondary_ipv4"],
        "delete_provisioning_template": module.params["delete_provisioning_template"]
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    results = DEFAULT_RESULT_OBJ
    try:
        # CHECK IF WE ARE DELETING AN ENTIRE TEMPLATE. IF THAT'S THE CASE DO IT FIRST AND IGNORE THE REST.
        if paramgram["delete_provisioning_template"] is not None:
            results = set_devprof(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0, -10, -1],
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram),
                                 stop_on_success=True)
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # CHECK TO SEE IF THE DEVPROF TEMPLATE EXISTS
        devprof = get_devprof(fmgr, paramgram)
        if devprof[0] != 0:
            results = set_devprof(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0, -2], stop_on_success=False,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # PROCESS THE SNMP SETTINGS IF THE SNMP_STATUS VARIABLE IS SET
        if paramgram["snmp_status"] is not None:
            results = set_devprof_snmp(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

        # PROCESS THE SNMP V2C COMMUNITY SETTINGS IF THEY ARE ALL HERE
        if all(v is not None for v in (paramgram["snmp_v2c_query_port"], paramgram["snmp_v2c_trap_port"],
                                       paramgram["snmp_v2c_status"], paramgram["snmp_v2c_trap_status"],
                                       paramgram["snmp_v2c_query_status"], paramgram["snmp_v2c_name"],
                                       paramgram["snmp_v2c_id"])):
            results = set_devprof_snmp_v2c(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0, -10033], stop_on_success=True,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

        # PROCESS THE SNMPV3 USER IF THERE
        if all(v is not None for v in (
                [paramgram["snmpv3_auth_proto"], paramgram["snmpv3_auth_pwd"], paramgram["snmpv3_name"],
                 paramgram["snmpv3_notify_hosts"], paramgram["snmpv3_priv_proto"],
                 paramgram["snmpv3_priv_pwd"],
                 paramgram["snmpv3_queries"],
                 paramgram["snmpv3_query_port"], paramgram["snmpv3_security_level"],
                 paramgram["snmpv3_source_ip"],
                 paramgram["snmpv3_status"], paramgram["snmpv3_trap_rport"], paramgram["snmpv3_trap_status"]])):

            results = set_devprof_snmp_v3(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0, -10033, -10000, -3],
                                 stop_on_success=True,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # PROCESS THE SYSLOG SETTINGS IF THE ALL THE NEEDED SYSLOG VARIABLES ARE PRESENT
        if all(v is not None for v in [paramgram["syslog_port"], paramgram["syslog_mode"],
                                       paramgram["syslog_server"], paramgram["syslog_status"]]):
            # enable syslog in the devprof template
            results = set_devprof_syslog(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0, -10033, -10000, -3],
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # IF THE SYSLOG FILTER IS PRESENT THEN RUN THAT
        if paramgram["syslog_filter"] is not None:
            results = set_devprof_syslog_filter(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0],
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # PROCESS NTP OPTIONS
        if paramgram["ntp_status"]:
            # VALIDATE INPUT
            if paramgram["ntp_type"] == "custom" and paramgram["ntp_server"] is None:
                module.exit_json(msg="You requested custom NTP type but did not provide ntp_server parameter.")
            if paramgram["ntp_auth"] == "enable" and paramgram["ntp_auth_pwd"] is None:
                module.exit_json(
                    msg="You requested NTP Authentication but did not provide ntp_auth_pwd parameter.")

            results = set_devprof_ntp(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0],
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)
    try:
        # PROCESS THE ADMIN OPTIONS
        if any(v is not None for v in (
                paramgram["admin_https_redirect"], paramgram["admin_https_port"], paramgram["admin_http_port"],
                paramgram["admin_timeout"],
                paramgram["admin_language"], paramgram["admin_switch_controller"],
                paramgram["admin_gui_theme"])):

            results = set_devprof_admin(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # PROCESS FORTIGUARD OPTIONS
        if paramgram["admin_enable_fortiguard"] is not None:

            results = set_devprof_toggle_fg(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
            results = set_devprof_fg(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # PROCESS THE SMTP OPTIONS
        if all(v is not None for v in (
                paramgram["smtp_username"], paramgram["smtp_password"], paramgram["smtp_port"],
                paramgram["smtp_replyto"],
                paramgram["smtp_conn_sec"], paramgram["smtp_server"],
                paramgram["smtp_source_ipv4"], paramgram["smtp_validate_cert"])):

            results = set_devprof_smtp(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # PROCESS THE DNS OPTIONS
        if any(v is not None for v in
               (paramgram["dns_suffix"], paramgram["dns_primary_ipv4"], paramgram["dns_secondary_ipv4"])):
            results = set_devprof_dns(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # PROCESS THE admin_fortianalyzer_target OPTIONS
        if paramgram["admin_fortianalyzer_target"] is not None:

            results = set_devprof_faz(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # PROCESS THE PROVISIONING TEMPLATE TARGET PARAMETER
        if paramgram["provision_targets"] is not None:
            if paramgram["mode"] != "delete":
                results = set_devprof_scope(fmgr, paramgram)
                fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False,
                                     ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

            if paramgram["mode"] == "delete":
                # WE NEED TO FIGURE OUT WHAT'S THERE FIRST, BEFORE WE CAN RUN THIS
                targets_to_add = list()
                try:
                    current_scope = get_devprof_scope(fmgr, paramgram)
                    targets_to_remove = paramgram["provision_targets"].strip().split(",")
                    targets = current_scope[1][1]["scope member"]
                    for target in targets:
                        if target["name"] not in targets_to_remove:
                            target_append = {"name": target["name"]}
                            targets_to_add.append(target_append)
                except BaseException:
                    pass
                paramgram["targets_to_add"] = targets_to_add
                results = set_devprof_scope(fmgr, paramgram)
                fmgr.govern_response(module=module, results=results, good_codes=[0, -10033, -10000, -3],
                                     ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_fortimeter

Metadata

Name: fmgr_fortimeter

Description: Provides MSPs the ability to programatically change FortiMeter license levels on devices.

Author(s): Luke Weighall (@lweighall)

Ansible Version Added/Required: 2.8

Dev Status: CODE UPDATE IN PROGRESS

Owning Developer: Luke Weighall

Pull Request Started:

Days in PR:

Module Github Link

Parameters
adom
  • Description: The ADOM the configuration should belong to.
  • Required: True
  • default: root
device_unique_name
  • Description: The desired “friendly” name of the device you want to query.
  • Required: True
fortimeter_utm_level
  • Description: Determines which UTM profiles should be allowed for Fortimeter. Multiple comma seperated selections allowed.
  • Required: True
  • default: all
  • choices: [‘fw’, ‘ips’, ‘av’, ‘ac’, ‘wf’, ‘all’]
foslic_type
  • Description: Sets the FortiMeterOS license Type (0 is temporary, 2 is regular, 1 is trial, 3 is expired)
  • Required: False
  • default: 2
Functions
  • fmgr_set_fortimeter_lic
def fmgr_set_fortimeter_lic(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # FIRST WE NEED TO PARSE THE DESIRED FOSLIC LEVEL ON THESE RULES
    # FW = 1
    # AV = 2
    # IPS = 4
    # AC = 8
    # WF = 16
    # PARSE THE DESIRED OPTIONS, AND THEN ADD THEM UP
    fos_levels = {
        "fw": 1,
        "av": 2,
        "ips": 4,
        "ac": 8,
        "wf": 16
    }

    foslic = 0
    fos_items = paramgram["fortimeter_utm_level"].strip().split(",")

    if "all" in paramgram["fortimeter_utm_level"].lower():
        foslic = 63
    else:
        for item in fos_items:
            if item.strip().lower() == "fw":
                foslic += fos_levels["fw"]
                continue
            if item.strip().lower() == "av":
                foslic += fos_levels["av"]
                continue
            if item.strip().lower() == "ips":
                foslic += fos_levels["ips"]
                continue
            if item.strip().lower() == "ac":
                foslic += fos_levels["ac"]
                continue
            if item.strip().lower() == "wf":
                foslic += fos_levels["wf"]
                continue

    datagram = {
        "foslic_utm": foslic,
        "foslic_type": paramgram["foslic_type"]
    }
    url = "/dvmdb/adom/{adom}/device/{device}".format(adom=paramgram["adom"], device=paramgram["device_unique_name"])
    response = fmgr.process_request(url, datagram, FMGRMethods.SET)

    return response
  • main
def main():
    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        device_unique_name=dict(required=True, type="str"),
        fortimeter_utm_level=dict(required=True, type="str"),
        foslic_type=dict(required=False, type="int", default=2)
    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    paramgram = {
        "adom": module.params["adom"],
        "device_unique_name": module.params["device_unique_name"],
        "fortimeter_utm_level": module.params["fortimeter_utm_level"],
        "foslic_type": module.params["foslic_type"]
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    results = DEFAULT_RESULT_OBJ
    try:
        results = fmgr_set_fortimeter_lic(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {
    "metadata_version": "1.1",
    "status": ["preview"],
    "supported_by": "community"
}

DOCUMENTATION = '''
---
module: fmgr_fortimeter
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author: Luke Weighall (@lweighall)
short_description: Sets FortiMeter licensing level
description:
  - Provides MSPs the ability to programatically change FortiMeter license levels on devices.

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: true
    default: root
  device_unique_name:
    description:
      - The desired "friendly" name of the device you want to query.
    required: true
  fortimeter_utm_level:
    description:
      - Determines which UTM profiles should be allowed for Fortimeter. Multiple comma seperated selections allowed.
    required: true
    default: "all"
    choices: ["fw", "ips", "av", "ac", "wf", "all"]
  foslic_type:
    description:
      - Sets the FortiMeterOS license Type (0 is temporary, 2 is regular, 1 is trial, 3 is expired)
    required: false
    default: 2
'''


EXAMPLES = '''
- name: SET LICENSING MODE ON FORTIMETER DEVICE to ALL
  fmgr_fortimeter:
    object: "device"
    adom: "ansible"
    device_unique_name: "FOSVM1FGPRJ411DD"
    fortimeter_utm_level: "all"

- name: SET LICENSING MODE ON FORTIMETER DEVICE to a COMBO
  fmgr_fortimeter:
    object: "device"
    adom: "ansible"
    device_unique_name: "FOSVM1FGPRJ411DD"
    fortimeter_utm_level: "fw, ips, av"
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import FMGRMethods
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG



def fmgr_set_fortimeter_lic(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # FIRST WE NEED TO PARSE THE DESIRED FOSLIC LEVEL ON THESE RULES
    # FW = 1
    # AV = 2
    # IPS = 4
    # AC = 8
    # WF = 16
    # PARSE THE DESIRED OPTIONS, AND THEN ADD THEM UP
    fos_levels = {
        "fw": 1,
        "av": 2,
        "ips": 4,
        "ac": 8,
        "wf": 16
    }

    foslic = 0
    fos_items = paramgram["fortimeter_utm_level"].strip().split(",")

    if "all" in paramgram["fortimeter_utm_level"].lower():
        foslic = 63
    else:
        for item in fos_items:
            if item.strip().lower() == "fw":
                foslic += fos_levels["fw"]
                continue
            if item.strip().lower() == "av":
                foslic += fos_levels["av"]
                continue
            if item.strip().lower() == "ips":
                foslic += fos_levels["ips"]
                continue
            if item.strip().lower() == "ac":
                foslic += fos_levels["ac"]
                continue
            if item.strip().lower() == "wf":
                foslic += fos_levels["wf"]
                continue

    datagram = {
        "foslic_utm": foslic,
        "foslic_type": paramgram["foslic_type"]
    }
    url = "/dvmdb/adom/{adom}/device/{device}".format(adom=paramgram["adom"], device=paramgram["device_unique_name"])
    response = fmgr.process_request(url, datagram, FMGRMethods.SET)

    return response


def main():
    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        device_unique_name=dict(required=True, type="str"),
        fortimeter_utm_level=dict(required=True, type="str"),
        foslic_type=dict(required=False, type="int", default=2)
    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    paramgram = {
        "adom": module.params["adom"],
        "device_unique_name": module.params["device_unique_name"],
        "fortimeter_utm_level": module.params["fortimeter_utm_level"],
        "foslic_type": module.params["foslic_type"]
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    results = DEFAULT_RESULT_OBJ
    try:
        results = fmgr_set_fortimeter_lic(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_fwobj_address

Metadata

Name: fmgr_fwobj_address

Description: Allows for the management of IPv4, IPv6, and multicast address objects within FortiManager.

Author(s):

  • Luke Weighall (github: @lweighall)
  • Andrew Welsh (github: @Ghilli3)
  • Jim Huber (github: @p4r4n0y1ng)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Luke Weighall

Module Github Link

Parameters
adom
  • Description: The ADOM the configuration should belong to.
  • Required: False
  • default: root
allow_routing
  • Description: Enable/disable use of this address in the static route configuration.
  • default: disable
  • choices: [‘enable’, ‘disable’]
associated_interface
  • Description: Associated interface name.
cache_ttl
  • Description: Minimal TTL of individual IP addresses in FQDN cache. Only applies when type = wildcard-fqdn.
color
  • Description: Color of the object in FortiManager GUI.

    Takes integers 1-32

  • default: 22

comment
  • Description: Comment for the object in FortiManager.
country
  • Description: Country name. Required if type = geographic.
end_ip
  • Description: End IP. Only used when ipv4 = iprange.
fqdn
  • Description: Fully qualified domain name.
group_members
  • Description: Address group member. If this is defined w/out group_name, the operation will fail.
group_name
  • Description: Address group name. If this is defined in playbook task, all other options are ignored.
ipv4
  • Description: Type of IPv4 Object.

    Must not be specified with either multicast or IPv6 parameters.

  • choices: [‘ipmask’, ‘iprange’, ‘fqdn’, ‘wildcard’, ‘geography’, ‘wildcard-fqdn’, ‘group’]

ipv4addr
  • Description: IP and network mask. If only defining one IP use this parameter. (i.e. 10.7.220.30/255.255.255.255)

    Can also define subnets (i.e. 10.7.220.0/255.255.255.0)

    Also accepts CIDR (i.e. 10.7.220.0/24)

    If Netmask is omitted after IP address, /32 is assumed.

    When multicast is set to Broadcast Subnet the ipv4addr parameter is used to specify the subnet.

ipv6
  • Description: Puts module into IPv6 mode.

    Must not be specified with either ipv4 or multicast parameters.

  • choices: [‘ip’, ‘iprange’, ‘group’]

ipv6addr
  • Description: IPv6 address in full. (i.e. 2001:0db8:85a3:0000:0000:8a2e:0370:7334)
mode
  • Description: Sets one of three modes for managing the object.
  • default: add
  • choices: [‘add’, ‘set’, ‘delete’]
multicast
  • Description: Manages Multicast Address Objects.

    Sets either a Multicast IP Range or a Broadcast Subnet.

    Must not be specified with either ipv4 or ipv6 parameters.

    When set to Broadcast Subnet the ipv4addr parameter is used to specify the subnet.

    Can create IPv4 Multicast Objects (multicastrange and broadcastmask options – uses start/end-ip and ipv4addr).

  • choices: [‘multicastrange’, ‘broadcastmask’, ‘ip6’]

name
  • Description: Friendly Name Address object name in FortiManager.
obj_id
  • Description: Object ID for NSX.
start_ip
  • Description: Start IP. Only used when ipv4 = iprange.
visibility
  • Description: Enable/disable address visibility.
  • default: enable
  • choices: [‘enable’, ‘disable’]
wildcard
  • Description: IP address and wildcard netmask. Required if ipv4 = wildcard.
wildcard_fqdn
  • Description: Wildcard FQDN. Required if ipv4 = wildcard-fqdn.
Functions
  • fmgr_fwobj_ipv4
def fmgr_fwobj_ipv4(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if paramgram["mode"] in ['set', 'add']:
        # CREATE THE DATAGRAM DICTIONARY
        # ENSURE THE DATAGRAM KEYS MATCH THE JSON API GUIDE ATTRIBUTES, NOT WHAT IS IN ANSIBLE
        # SOME PARAMETERS SHOWN IN THIS DICTIONARY WE DON'T EVEN ASK THE USER FOR IN PLAYBOOKS BUT ARE REQUIRED
        datagram = {
            "comment": paramgram["comment"],
            "associated-interface": paramgram["associated-interface"],
            "cache-ttl": paramgram["cache-ttl"],
            "name": paramgram["name"],
            "allow-routing": paramgram["allow-routing"],
            "color": paramgram["color"],
            "meta fields": {},
            "dynamic_mapping": [],
            "visibility": paramgram["allow-routing"],
            "type": paramgram["ipv4"],
        }

        # SET THE CORRECT URL BASED ON THE TYPE (WE'RE DOING GROUPS IN THIS METHOD, TOO)
        if datagram["type"] == "group":
            url = '/pm/config/adom/{adom}/obj/firewall/addrgrp'.format(adom=paramgram["adom"])
        else:
            url = '/pm/config/adom/{adom}/obj/firewall/address'.format(adom=paramgram["adom"])

        #########################
        # IF type = 'ipmask'
        #########################
        if datagram["type"] == "ipmask":
            # CREATE THE SUBNET LIST OBJECT
            subnet = []
            # EVAL THE IPV4ADDR INPUT AND SPLIT THE IP ADDRESS FROM THE MASK AND APPEND THEM TO THE SUBNET LIST
            for subnets in paramgram["ipv4addr"].split("/"):
                subnet.append(subnets)

            # CHECK THAT THE SECOND ENTRY IN THE SUBNET LIST (WHAT WAS TO THE RIGHT OF THE / CHARACTER)
            # IS IN SUBNET MASK FORMAT AND NOT CIDR FORMAT.
            # IF IT IS IN CIDR FORMAT, WE NEED TO CONVERT IT TO SUBNET BIT MASK FORMAT FOR THE JSON API
            if not re.match(r'\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}', subnet[1]):
                # IF THE SUBNET PARAMETER INPUT DIDN'T LOOK LIKE xxx.xxx.xxx.xxx TO REGEX...
                # ... RUN IT THROUGH THE CIDR_TO_NETMASK() FUNCTION
                mask = fmgr._tools.cidr_to_netmask(subnet[1])
                # AND THEN UPDATE THE SUBNET LIST OBJECT
                subnet[1] = mask

            # INCLUDE THE SUBNET LIST OBJECT IN THE DATAGRAM DICTIONARY TO BE SUBMITTED
            datagram["subnet"] = subnet

        #########################
        # IF type = 'iprange'
        #########################
        if datagram["type"] == "iprange":
            datagram["start-ip"] = paramgram["start-ip"]
            datagram["end-ip"] = paramgram["end-ip"]
            datagram["subnet"] = ["0.0.0.0", "0.0.0.0"]

        #########################
        # IF type = 'geography'
        #########################
        if datagram["type"] == "geography":
            datagram["country"] = paramgram["country"]

        #########################
        # IF type = 'wildcard'
        #########################
        if datagram["type"] == "wildcard":

            subnet = []
            for subnets in paramgram["wildcard"].split("/"):
                subnet.append(subnets)

            if not re.match(r'\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}', subnet[1]):
                mask = fmgr._tools.cidr_to_netmask(subnet[1])
                subnet[1] = mask

            datagram["wildcard"] = subnet

        #########################
        # IF type = 'wildcard-fqdn'
        #########################
        if datagram["type"] == "wildcard-fqdn":
            datagram["wildcard-fqdn"] = paramgram["wildcard-fqdn"]

        #########################
        # IF type = 'fqdn'
        #########################
        if datagram["type"] == "fqdn":
            datagram["fqdn"] = paramgram["fqdn"]

        #########################
        # IF type = 'group'
        #########################
        if datagram["type"] == "group":
            datagram = {
                "comment": paramgram["comment"],
                "name": paramgram["group_name"],
                "color": paramgram["color"],
                "meta fields": {},
                "dynamic_mapping": [],
                "visibility": paramgram["visibility"]
            }

            members = []
            group_members = paramgram["group_members"].replace(" ", "")
            try:
                for member in group_members.split(","):
                    members.append(member)
            except Exception:
                pass

            datagram["member"] = members

    # EVAL THE MODE PARAMETER FOR DELETE
    if paramgram["mode"] == "delete":
        # IF A GROUP, SET THE CORRECT NAME AND URL FOR THE GROUP ENDPOINT
        if paramgram["ipv4"] == "group":
            datagram = {}
            url = '/pm/config/adom/{adom}/obj/firewall/addrgrp/{name}'.format(adom=paramgram["adom"],
                                                                              name=paramgram["group_name"])
        # OTHERWISE WE'RE JUST GOING TO USE THE ADDRESS ENDPOINT
        else:
            datagram = {}
            url = '/pm/config/adom/{adom}/obj/firewall/address/{name}'.format(adom=paramgram["adom"],
                                                                              name=paramgram["name"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response
  • fmgr_fwobj_ipv6
def fmgr_fwobj_ipv6(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if paramgram["mode"] in ['set', 'add']:
        # CREATE THE DATAGRAM DICTIONARY
        # ENSURE THE DATAGRAM KEYS MATCH THE JSON API GUIDE ATTRIBUTES, NOT WHAT IS IN ANSIBLE
        # SOME PARAMETERS SHOWN IN THIS DICTIONARY WE DON'T EVEN ASK THE USER FOR IN PLAYBOOKS BUT ARE REQUIRED
        datagram = {
            "comment": paramgram["comment"],
            "name": paramgram["name"],
            "color": paramgram["color"],
            "dynamic_mapping": [],
            "visibility": paramgram["visibility"],
            "type": paramgram["ipv6"]
        }

        # SET THE CORRECT URL BASED ON THE TYPE (WE'RE DOING GROUPS IN THIS METHOD, TOO)
        if datagram["type"] == "group":
            url = '/pm/config/adom/{adom}/obj/firewall/addrgrp6'.format(adom=paramgram["adom"])
        else:
            url = '/pm/config/adom/{adom}/obj/firewall/address6'.format(adom=paramgram["adom"])

        #########################
        # IF type = 'ip'
        #########################
        if datagram["type"] == "ip":
            datagram["type"] = "ipprefix"
            datagram["ip6"] = paramgram["ipv6addr"]

        #########################
        # IF type = 'iprange'
        #########################
        if datagram["type"] == "iprange":
            datagram["start-ip"] = paramgram["start-ip"]
            datagram["end-ip"] = paramgram["end-ip"]

        #########################
        # IF type = 'group'
        #########################
        if datagram["type"] == "group":
            datagram = None
            datagram = {
                "comment": paramgram["comment"],
                "name": paramgram["group_name"],
                "color": paramgram["color"],
                "visibility": paramgram["visibility"]
            }

            members = []
            group_members = paramgram["group_members"].replace(" ", "")
            try:
                for member in group_members.split(","):
                    members.append(member)
            except Exception:
                pass

            datagram["member"] = members

    # EVAL THE MODE PARAMETER FOR DELETE
    if paramgram["mode"] == "delete":
        # IF A GROUP, SET THE CORRECT NAME AND URL FOR THE GROUP ENDPOINT
        if paramgram["ipv6"] == "group":
            datagram = {}
            url = '/pm/config/adom/{adom}/obj/firewall/addrgrp6/{name}'.format(adom=paramgram["adom"],
                                                                               name=paramgram["group_name"])
        # OTHERWISE WE'RE JUST GOING TO USE THE ADDRESS ENDPOINT
        else:
            datagram = {}
            url = '/pm/config/adom/{adom}/obj/firewall/address6/{name}'.format(adom=paramgram["adom"],
                                                                               name=paramgram["name"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response
  • fmgr_fwobj_multicast
def fmgr_fwobj_multicast(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if paramgram["mode"] in ['set', 'add']:
        # CREATE THE DATAGRAM DICTIONARY
        # ENSURE THE DATAGRAM KEYS MATCH THE JSON API GUIDE ATTRIBUTES, NOT WHAT IS IN ANSIBLE
        # SOME PARAMETERS SHOWN IN THIS DICTIONARY WE DON'T EVEN ASK THE USER FOR IN PLAYBOOKS BUT ARE REQUIRED
        datagram = {
            "associated-interface": paramgram["associated-interface"],
            "comment": paramgram["comment"],
            "name": paramgram["name"],
            "color": paramgram["color"],
            "type": paramgram["multicast"],
            "visibility": paramgram["visibility"],
        }

        # SET THE CORRECT URL
        url = '/pm/config/adom/{adom}/obj/firewall/multicast-address'.format(adom=paramgram["adom"])

        #########################
        # IF type = 'multicastrange'
        #########################
        if paramgram["multicast"] == "multicastrange":
            datagram["start-ip"] = paramgram["start-ip"]
            datagram["end-ip"] = paramgram["end-ip"]
            datagram["subnet"] = ["0.0.0.0", "0.0.0.0"]

        #########################
        # IF type = 'broadcastmask'
        #########################
        if paramgram["multicast"] == "broadcastmask":
            # EVAL THE IPV4ADDR INPUT AND SPLIT THE IP ADDRESS FROM THE MASK AND APPEND THEM TO THE SUBNET LIST
            subnet = []
            for subnets in paramgram["ipv4addr"].split("/"):
                subnet.append(subnets)
            # CHECK THAT THE SECOND ENTRY IN THE SUBNET LIST (WHAT WAS TO THE RIGHT OF THE / CHARACTER)
            # IS IN SUBNET MASK FORMAT AND NOT CIDR FORMAT.
            # IF IT IS IN CIDR FORMAT, WE NEED TO CONVERT IT TO SUBNET BIT MASK FORMAT FOR THE JSON API
            if not re.match(r'\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}', subnet[1]):
                # IF THE SUBNET PARAMETER INPUT DIDN'T LOOK LIKE 255.255.255.255 TO REGEX...
                # ... RUN IT THROUGH THE fmgr_cidr_to_netmask() FUNCTION
                mask = fmgr._tools.cidr_to_netmask(subnet[1])
                # AND THEN UPDATE THE SUBNET LIST OBJECT
                subnet[1] = mask

            # INCLUDE THE SUBNET LIST OBJECT IN THE DATAGRAM DICTIONARY TO BE SUBMITTED
            datagram["subnet"] = subnet

    # EVAL THE MODE PARAMETER FOR DELETE
    if paramgram["mode"] == "delete":
        datagram = {
            "name": paramgram["name"]
        }
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/firewall/multicast-address/{name}'.format(adom=paramgram["adom"],
                                                                                    name=paramgram["name"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response
  • main
def main():
    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        mode=dict(choices=["add", "set", "delete"], type="str", default="add"),

        allow_routing=dict(required=False, type="str", choices=['enable', 'disable'], default="disable"),
        associated_interface=dict(required=False, type="str"),
        cache_ttl=dict(required=False, type="str"),
        color=dict(required=False, type="str", default=22),
        comment=dict(required=False, type="str"),
        country=dict(required=False, type="str"),
        fqdn=dict(required=False, type="str"),
        name=dict(required=False, type="str"),
        start_ip=dict(required=False, type="str"),
        end_ip=dict(required=False, type="str"),
        ipv4=dict(required=False, type="str", choices=['ipmask', 'iprange', 'fqdn', 'wildcard',
                                                       'geography', 'wildcard-fqdn', 'group']),
        visibility=dict(required=False, type="str", choices=['enable', 'disable'], default="enable"),
        wildcard=dict(required=False, type="str"),
        wildcard_fqdn=dict(required=False, type="str"),
        ipv6=dict(required=False, type="str", choices=['ip', 'iprange', 'group']),
        group_members=dict(required=False, type="str"),
        group_name=dict(required=False, type="str"),
        ipv4addr=dict(required=False, type="str"),
        ipv6addr=dict(required=False, type="str"),
        multicast=dict(required=False, type="str", choices=['multicastrange', 'broadcastmask', 'ip6']),
        obj_id=dict(required=False, type="str"),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False,
                           mutually_exclusive=[
                               ['ipv4', 'ipv6'],
                               ['ipv4', 'multicast'],
                               ['ipv6', 'multicast']
                           ])
    paramgram = {
        "adom": module.params["adom"],
        "allow-routing": module.params["allow_routing"],
        "associated-interface": module.params["associated_interface"],
        "cache-ttl": module.params["cache_ttl"],
        "color": module.params["color"],
        "comment": module.params["comment"],
        "country": module.params["country"],
        "end-ip": module.params["end_ip"],
        "fqdn": module.params["fqdn"],
        "name": module.params["name"],
        "start-ip": module.params["start_ip"],
        "visibility": module.params["visibility"],
        "wildcard": module.params["wildcard"],
        "wildcard-fqdn": module.params["wildcard_fqdn"],
        "ipv6": module.params["ipv6"],
        "ipv4": module.params["ipv4"],
        "group_members": module.params["group_members"],
        "group_name": module.params["group_name"],
        "ipv4addr": module.params["ipv4addr"],
        "ipv6addr": module.params["ipv6addr"],
        "multicast": module.params["multicast"],
        "mode": module.params["mode"],
        "obj-id": module.params["obj_id"],
    }

    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr._tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    results = DEFAULT_RESULT_OBJ
    try:
        if paramgram["ipv4"]:
            results = fmgr_fwobj_ipv4(fmgr, paramgram)

        elif paramgram["ipv6"]:
            results = fmgr_fwobj_ipv6(fmgr, paramgram)

        elif paramgram["multicast"]:
            results = fmgr_fwobj_multicast(fmgr, paramgram)

        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    if results is not None:
        return module.exit_json(**results[1])
    else:
        return module.exit_json(msg="Couldn't find a proper ipv4 or ipv6 or multicast parameter "
                                    "to run in the logic tree. Exiting...")
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {
    "metadata_version": "1.1",
    "status": ["preview"],
    "supported_by": "community"
}

DOCUMENTATION = '''
---
module: fmgr_fwobj_address
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author:
    - Luke Weighall (@lweighall)
    - Andrew Welsh (@Ghilli3)
    - Jim Huber (@p4r4n0y1ng)
short_description: Allows the management of firewall objects in FortiManager
description:
  -  Allows for the management of IPv4, IPv6, and multicast address objects within FortiManager.

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: false
    default: root

  allow_routing:
    description:
      - Enable/disable use of this address in the static route configuration.
    choices: ['enable', 'disable']
    default: 'disable'

  associated_interface:
    description:
      - Associated interface name.

  cache_ttl:
    description:
      - Minimal TTL of individual IP addresses in FQDN cache. Only applies when type = wildcard-fqdn.

  color:
    description:
      - Color of the object in FortiManager GUI.
      - Takes integers 1-32
    default: 22

  comment:
    description:
      - Comment for the object in FortiManager.

  country:
    description:
      - Country name. Required if type = geographic.

  end_ip:
    description:
      - End IP. Only used when ipv4 = iprange.

  group_members:
    description:
      - Address group member. If this is defined w/out group_name, the operation will fail.

  group_name:
    description:
      - Address group name. If this is defined in playbook task, all other options are ignored.

  ipv4:
    description:
      - Type of IPv4 Object.
      - Must not be specified with either multicast or IPv6 parameters.
    choices: ['ipmask', 'iprange', 'fqdn', 'wildcard', 'geography', 'wildcard-fqdn', 'group']

  ipv4addr:
    description:
      - IP and network mask. If only defining one IP use this parameter. (i.e. 10.7.220.30/255.255.255.255)
      - Can also define subnets (i.e. 10.7.220.0/255.255.255.0)
      - Also accepts CIDR (i.e. 10.7.220.0/24)
      - If Netmask is omitted after IP address, /32 is assumed.
      - When multicast is set to Broadcast Subnet the ipv4addr parameter is used to specify the subnet.

  ipv6:
    description:
      - Puts module into IPv6 mode.
      - Must not be specified with either ipv4 or multicast parameters.
    choices: ['ip', 'iprange', 'group']

  ipv6addr:
    description:
      - IPv6 address in full. (i.e. 2001:0db8:85a3:0000:0000:8a2e:0370:7334)

  fqdn:
    description:
      - Fully qualified domain name.

  mode:
    description:
      - Sets one of three modes for managing the object.
    choices: ['add', 'set', 'delete']
    default: add

  multicast:
    description:
      - Manages Multicast Address Objects.
      - Sets either a Multicast IP Range or a Broadcast Subnet.
      - Must not be specified with either ipv4 or ipv6 parameters.
      - When set to Broadcast Subnet the ipv4addr parameter is used to specify the subnet.
      - Can create IPv4 Multicast Objects (multicastrange and broadcastmask options -- uses start/end-ip and ipv4addr).
    choices: ['multicastrange', 'broadcastmask', 'ip6']

  name:
    description:
      - Friendly Name Address object name in FortiManager.

  obj_id:
    description:
      - Object ID for NSX.

  start_ip:
    description:
      - Start IP. Only used when ipv4 = iprange.

  visibility:
    description:
      - Enable/disable address visibility.
    choices: ['enable', 'disable']
    default: 'enable'

  wildcard:
    description:
      - IP address and wildcard netmask. Required if ipv4 = wildcard.

  wildcard_fqdn:
    description:
      - Wildcard FQDN. Required if ipv4 = wildcard-fqdn.
'''

EXAMPLES = '''
- name: ADD IPv4 IP ADDRESS OBJECT
  fmgr_fwobj_address:
    ipv4: "ipmask"
    ipv4addr: "10.7.220.30/32"
    name: "ansible_v4Obj"
    comment: "Created by Ansible"
    color: "6"

- name: ADD IPv4 IP ADDRESS OBJECT MORE OPTIONS
  fmgr_fwobj_address:
    ipv4: "ipmask"
    ipv4addr: "10.7.220.34/32"
    name: "ansible_v4Obj_MORE"
    comment: "Created by Ansible"
    color: "6"
    allow_routing: "enable"
    cache_ttl: "180"
    associated_interface: "port1"
    obj_id: "123"

- name: ADD IPv4 IP ADDRESS SUBNET OBJECT
  fmgr_fwobj_address:
    ipv4: "ipmask"
    ipv4addr: "10.7.220.0/255.255.255.128"
    name: "ansible_subnet"
    comment: "Created by Ansible"
    mode: "set"

- name: ADD IPv4 IP ADDRESS RANGE OBJECT
  fmgr_fwobj_address:
    ipv4: "iprange"
    start_ip: "10.7.220.1"
    end_ip: "10.7.220.125"
    name: "ansible_range"
    comment: "Created by Ansible"

- name: ADD IPv4 IP ADDRESS WILDCARD OBJECT
  fmgr_fwobj_address:
    ipv4: "wildcard"
    wildcard: "10.7.220.30/255.255.255.255"
    name: "ansible_wildcard"
    comment: "Created by Ansible"

- name: ADD IPv4 IP ADDRESS WILDCARD FQDN OBJECT
  fmgr_fwobj_address:
    ipv4: "wildcard-fqdn"
    wildcard_fqdn: "*.myds.com"
    name: "Synology myds DDNS service"
    comment: "Created by Ansible"

- name: ADD IPv4 IP ADDRESS FQDN OBJECT
  fmgr_fwobj_address:
    ipv4: "fqdn"
    fqdn: "ansible.com"
    name: "ansible_fqdn"
    comment: "Created by Ansible"

- name: ADD IPv4 IP ADDRESS GEO OBJECT
  fmgr_fwobj_address:
    ipv4: "geography"
    country: "usa"
    name: "ansible_geo"
    comment: "Created by Ansible"

- name: ADD IPv6 ADDRESS
  fmgr_fwobj_address:
    ipv6: "ip"
    ipv6addr: "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
    name: "ansible_v6Obj"
    comment: "Created by Ansible"

- name: ADD IPv6 ADDRESS RANGE
  fmgr_fwobj_address:
    ipv6: "iprange"
    start_ip: "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
    end_ip: "2001:0db8:85a3:0000:0000:8a2e:0370:7446"
    name: "ansible_v6range"
    comment: "Created by Ansible"

- name: ADD IPv4 IP ADDRESS GROUP
  fmgr_fwobj_address:
    ipv4: "group"
    group_name: "ansibleIPv4Group"
    group_members: "ansible_fqdn, ansible_wildcard, ansible_range"

- name: ADD IPv6 IP ADDRESS GROUP
  fmgr_fwobj_address:
    ipv6: "group"
    group_name: "ansibleIPv6Group"
    group_members: "ansible_v6Obj, ansible_v6range"

- name: ADD MULTICAST RANGE
  fmgr_fwobj_address:
    multicast: "multicastrange"
    start_ip: "224.0.0.251"
    end_ip: "224.0.0.251"
    name: "ansible_multicastrange"
    comment: "Created by Ansible"

- name: ADD BROADCAST SUBNET
  fmgr_fwobj_address:
    multicast: "broadcastmask"
    ipv4addr: "10.7.220.0/24"
    name: "ansible_broadcastSubnet"
    comment: "Created by Ansible"
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""


import re
from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG


def fmgr_fwobj_ipv4(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if paramgram["mode"] in ['set', 'add']:
        # CREATE THE DATAGRAM DICTIONARY
        # ENSURE THE DATAGRAM KEYS MATCH THE JSON API GUIDE ATTRIBUTES, NOT WHAT IS IN ANSIBLE
        # SOME PARAMETERS SHOWN IN THIS DICTIONARY WE DON'T EVEN ASK THE USER FOR IN PLAYBOOKS BUT ARE REQUIRED
        datagram = {
            "comment": paramgram["comment"],
            "associated-interface": paramgram["associated-interface"],
            "cache-ttl": paramgram["cache-ttl"],
            "name": paramgram["name"],
            "allow-routing": paramgram["allow-routing"],
            "color": paramgram["color"],
            "meta fields": {},
            "dynamic_mapping": [],
            "visibility": paramgram["allow-routing"],
            "type": paramgram["ipv4"],
        }

        # SET THE CORRECT URL BASED ON THE TYPE (WE'RE DOING GROUPS IN THIS METHOD, TOO)
        if datagram["type"] == "group":
            url = '/pm/config/adom/{adom}/obj/firewall/addrgrp'.format(adom=paramgram["adom"])
        else:
            url = '/pm/config/adom/{adom}/obj/firewall/address'.format(adom=paramgram["adom"])

        #########################
        # IF type = 'ipmask'
        #########################
        if datagram["type"] == "ipmask":
            # CREATE THE SUBNET LIST OBJECT
            subnet = []
            # EVAL THE IPV4ADDR INPUT AND SPLIT THE IP ADDRESS FROM THE MASK AND APPEND THEM TO THE SUBNET LIST
            for subnets in paramgram["ipv4addr"].split("/"):
                subnet.append(subnets)

            # CHECK THAT THE SECOND ENTRY IN THE SUBNET LIST (WHAT WAS TO THE RIGHT OF THE / CHARACTER)
            # IS IN SUBNET MASK FORMAT AND NOT CIDR FORMAT.
            # IF IT IS IN CIDR FORMAT, WE NEED TO CONVERT IT TO SUBNET BIT MASK FORMAT FOR THE JSON API
            if not re.match(r'\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}', subnet[1]):
                # IF THE SUBNET PARAMETER INPUT DIDN'T LOOK LIKE xxx.xxx.xxx.xxx TO REGEX...
                # ... RUN IT THROUGH THE CIDR_TO_NETMASK() FUNCTION
                mask = fmgr._tools.cidr_to_netmask(subnet[1])
                # AND THEN UPDATE THE SUBNET LIST OBJECT
                subnet[1] = mask

            # INCLUDE THE SUBNET LIST OBJECT IN THE DATAGRAM DICTIONARY TO BE SUBMITTED
            datagram["subnet"] = subnet

        #########################
        # IF type = 'iprange'
        #########################
        if datagram["type"] == "iprange":
            datagram["start-ip"] = paramgram["start-ip"]
            datagram["end-ip"] = paramgram["end-ip"]
            datagram["subnet"] = ["0.0.0.0", "0.0.0.0"]

        #########################
        # IF type = 'geography'
        #########################
        if datagram["type"] == "geography":
            datagram["country"] = paramgram["country"]

        #########################
        # IF type = 'wildcard'
        #########################
        if datagram["type"] == "wildcard":

            subnet = []
            for subnets in paramgram["wildcard"].split("/"):
                subnet.append(subnets)

            if not re.match(r'\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}', subnet[1]):
                mask = fmgr._tools.cidr_to_netmask(subnet[1])
                subnet[1] = mask

            datagram["wildcard"] = subnet

        #########################
        # IF type = 'wildcard-fqdn'
        #########################
        if datagram["type"] == "wildcard-fqdn":
            datagram["wildcard-fqdn"] = paramgram["wildcard-fqdn"]

        #########################
        # IF type = 'fqdn'
        #########################
        if datagram["type"] == "fqdn":
            datagram["fqdn"] = paramgram["fqdn"]

        #########################
        # IF type = 'group'
        #########################
        if datagram["type"] == "group":
            datagram = {
                "comment": paramgram["comment"],
                "name": paramgram["group_name"],
                "color": paramgram["color"],
                "meta fields": {},
                "dynamic_mapping": [],
                "visibility": paramgram["visibility"]
            }

            members = []
            group_members = paramgram["group_members"].replace(" ", "")
            try:
                for member in group_members.split(","):
                    members.append(member)
            except Exception:
                pass

            datagram["member"] = members

    # EVAL THE MODE PARAMETER FOR DELETE
    if paramgram["mode"] == "delete":
        # IF A GROUP, SET THE CORRECT NAME AND URL FOR THE GROUP ENDPOINT
        if paramgram["ipv4"] == "group":
            datagram = {}
            url = '/pm/config/adom/{adom}/obj/firewall/addrgrp/{name}'.format(adom=paramgram["adom"],
                                                                              name=paramgram["group_name"])
        # OTHERWISE WE'RE JUST GOING TO USE THE ADDRESS ENDPOINT
        else:
            datagram = {}
            url = '/pm/config/adom/{adom}/obj/firewall/address/{name}'.format(adom=paramgram["adom"],
                                                                              name=paramgram["name"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


def fmgr_fwobj_ipv6(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if paramgram["mode"] in ['set', 'add']:
        # CREATE THE DATAGRAM DICTIONARY
        # ENSURE THE DATAGRAM KEYS MATCH THE JSON API GUIDE ATTRIBUTES, NOT WHAT IS IN ANSIBLE
        # SOME PARAMETERS SHOWN IN THIS DICTIONARY WE DON'T EVEN ASK THE USER FOR IN PLAYBOOKS BUT ARE REQUIRED
        datagram = {
            "comment": paramgram["comment"],
            "name": paramgram["name"],
            "color": paramgram["color"],
            "dynamic_mapping": [],
            "visibility": paramgram["visibility"],
            "type": paramgram["ipv6"]
        }

        # SET THE CORRECT URL BASED ON THE TYPE (WE'RE DOING GROUPS IN THIS METHOD, TOO)
        if datagram["type"] == "group":
            url = '/pm/config/adom/{adom}/obj/firewall/addrgrp6'.format(adom=paramgram["adom"])
        else:
            url = '/pm/config/adom/{adom}/obj/firewall/address6'.format(adom=paramgram["adom"])

        #########################
        # IF type = 'ip'
        #########################
        if datagram["type"] == "ip":
            datagram["type"] = "ipprefix"
            datagram["ip6"] = paramgram["ipv6addr"]

        #########################
        # IF type = 'iprange'
        #########################
        if datagram["type"] == "iprange":
            datagram["start-ip"] = paramgram["start-ip"]
            datagram["end-ip"] = paramgram["end-ip"]

        #########################
        # IF type = 'group'
        #########################
        if datagram["type"] == "group":
            datagram = None
            datagram = {
                "comment": paramgram["comment"],
                "name": paramgram["group_name"],
                "color": paramgram["color"],
                "visibility": paramgram["visibility"]
            }

            members = []
            group_members = paramgram["group_members"].replace(" ", "")
            try:
                for member in group_members.split(","):
                    members.append(member)
            except Exception:
                pass

            datagram["member"] = members

    # EVAL THE MODE PARAMETER FOR DELETE
    if paramgram["mode"] == "delete":
        # IF A GROUP, SET THE CORRECT NAME AND URL FOR THE GROUP ENDPOINT
        if paramgram["ipv6"] == "group":
            datagram = {}
            url = '/pm/config/adom/{adom}/obj/firewall/addrgrp6/{name}'.format(adom=paramgram["adom"],
                                                                               name=paramgram["group_name"])
        # OTHERWISE WE'RE JUST GOING TO USE THE ADDRESS ENDPOINT
        else:
            datagram = {}
            url = '/pm/config/adom/{adom}/obj/firewall/address6/{name}'.format(adom=paramgram["adom"],
                                                                               name=paramgram["name"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


def fmgr_fwobj_multicast(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if paramgram["mode"] in ['set', 'add']:
        # CREATE THE DATAGRAM DICTIONARY
        # ENSURE THE DATAGRAM KEYS MATCH THE JSON API GUIDE ATTRIBUTES, NOT WHAT IS IN ANSIBLE
        # SOME PARAMETERS SHOWN IN THIS DICTIONARY WE DON'T EVEN ASK THE USER FOR IN PLAYBOOKS BUT ARE REQUIRED
        datagram = {
            "associated-interface": paramgram["associated-interface"],
            "comment": paramgram["comment"],
            "name": paramgram["name"],
            "color": paramgram["color"],
            "type": paramgram["multicast"],
            "visibility": paramgram["visibility"],
        }

        # SET THE CORRECT URL
        url = '/pm/config/adom/{adom}/obj/firewall/multicast-address'.format(adom=paramgram["adom"])

        #########################
        # IF type = 'multicastrange'
        #########################
        if paramgram["multicast"] == "multicastrange":
            datagram["start-ip"] = paramgram["start-ip"]
            datagram["end-ip"] = paramgram["end-ip"]
            datagram["subnet"] = ["0.0.0.0", "0.0.0.0"]

        #########################
        # IF type = 'broadcastmask'
        #########################
        if paramgram["multicast"] == "broadcastmask":
            # EVAL THE IPV4ADDR INPUT AND SPLIT THE IP ADDRESS FROM THE MASK AND APPEND THEM TO THE SUBNET LIST
            subnet = []
            for subnets in paramgram["ipv4addr"].split("/"):
                subnet.append(subnets)
            # CHECK THAT THE SECOND ENTRY IN THE SUBNET LIST (WHAT WAS TO THE RIGHT OF THE / CHARACTER)
            # IS IN SUBNET MASK FORMAT AND NOT CIDR FORMAT.
            # IF IT IS IN CIDR FORMAT, WE NEED TO CONVERT IT TO SUBNET BIT MASK FORMAT FOR THE JSON API
            if not re.match(r'\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}', subnet[1]):
                # IF THE SUBNET PARAMETER INPUT DIDN'T LOOK LIKE 255.255.255.255 TO REGEX...
                # ... RUN IT THROUGH THE fmgr_cidr_to_netmask() FUNCTION
                mask = fmgr._tools.cidr_to_netmask(subnet[1])
                # AND THEN UPDATE THE SUBNET LIST OBJECT
                subnet[1] = mask

            # INCLUDE THE SUBNET LIST OBJECT IN THE DATAGRAM DICTIONARY TO BE SUBMITTED
            datagram["subnet"] = subnet

    # EVAL THE MODE PARAMETER FOR DELETE
    if paramgram["mode"] == "delete":
        datagram = {
            "name": paramgram["name"]
        }
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/firewall/multicast-address/{name}'.format(adom=paramgram["adom"],
                                                                                    name=paramgram["name"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


def main():
    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        mode=dict(choices=["add", "set", "delete"], type="str", default="add"),

        allow_routing=dict(required=False, type="str", choices=['enable', 'disable'], default="disable"),
        associated_interface=dict(required=False, type="str"),
        cache_ttl=dict(required=False, type="str"),
        color=dict(required=False, type="str", default=22),
        comment=dict(required=False, type="str"),
        country=dict(required=False, type="str"),
        fqdn=dict(required=False, type="str"),
        name=dict(required=False, type="str"),
        start_ip=dict(required=False, type="str"),
        end_ip=dict(required=False, type="str"),
        ipv4=dict(required=False, type="str", choices=['ipmask', 'iprange', 'fqdn', 'wildcard',
                                                       'geography', 'wildcard-fqdn', 'group']),
        visibility=dict(required=False, type="str", choices=['enable', 'disable'], default="enable"),
        wildcard=dict(required=False, type="str"),
        wildcard_fqdn=dict(required=False, type="str"),
        ipv6=dict(required=False, type="str", choices=['ip', 'iprange', 'group']),
        group_members=dict(required=False, type="str"),
        group_name=dict(required=False, type="str"),
        ipv4addr=dict(required=False, type="str"),
        ipv6addr=dict(required=False, type="str"),
        multicast=dict(required=False, type="str", choices=['multicastrange', 'broadcastmask', 'ip6']),
        obj_id=dict(required=False, type="str"),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False,
                           mutually_exclusive=[
                               ['ipv4', 'ipv6'],
                               ['ipv4', 'multicast'],
                               ['ipv6', 'multicast']
                           ])
    paramgram = {
        "adom": module.params["adom"],
        "allow-routing": module.params["allow_routing"],
        "associated-interface": module.params["associated_interface"],
        "cache-ttl": module.params["cache_ttl"],
        "color": module.params["color"],
        "comment": module.params["comment"],
        "country": module.params["country"],
        "end-ip": module.params["end_ip"],
        "fqdn": module.params["fqdn"],
        "name": module.params["name"],
        "start-ip": module.params["start_ip"],
        "visibility": module.params["visibility"],
        "wildcard": module.params["wildcard"],
        "wildcard-fqdn": module.params["wildcard_fqdn"],
        "ipv6": module.params["ipv6"],
        "ipv4": module.params["ipv4"],
        "group_members": module.params["group_members"],
        "group_name": module.params["group_name"],
        "ipv4addr": module.params["ipv4addr"],
        "ipv6addr": module.params["ipv6addr"],
        "multicast": module.params["multicast"],
        "mode": module.params["mode"],
        "obj-id": module.params["obj_id"],
    }

    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr._tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    results = DEFAULT_RESULT_OBJ
    try:
        if paramgram["ipv4"]:
            results = fmgr_fwobj_ipv4(fmgr, paramgram)

        elif paramgram["ipv6"]:
            results = fmgr_fwobj_ipv6(fmgr, paramgram)

        elif paramgram["multicast"]:
            results = fmgr_fwobj_multicast(fmgr, paramgram)

        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    if results is not None:
        return module.exit_json(**results[1])
    else:
        return module.exit_json(msg="Couldn't find a proper ipv4 or ipv6 or multicast parameter "
                                    "to run in the logic tree. Exiting...")


if __name__ == "__main__":
    main()

fmgr_fwobj_ippool

Metadata

Name: fmgr_fwobj_ippool

Description: Allows users to add/edit/delete IP Pool Objects.

Author(s):

  • Luke Weighall (github: @lweighall)
  • Andrew Welsh (github: @Ghilli3)
  • Jim Huber (github: @p4r4n0y1ng)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Luke Weighall

Module Github Link

Parameters
adom
  • Description: The ADOM the configuration should belong to.
  • Required: False
  • default: root
arp_intf
  • Description: Select an interface from available options that will reply to ARP requests. (If blank, any is selected).
  • Required: False
arp_reply
  • Description: Enable/disable replying to ARP requests when an IP Pool is added to a policy (default = enable).

    choice | disable | Disable ARP reply.

    choice | enable | Enable ARP reply.

  • Required: False

  • choices: [‘disable’, ‘enable’]

associated_interface
  • Description: Associated interface name.
  • Required: False
block_size
  • Description: Number of addresses in a block (64 to 4096, default = 128).
  • Required: False
comments
  • Description: Comment.
  • Required: False
dynamic_mapping
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameter.ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

dynamic_mapping_arp_intf
  • Description: Dynamic Mapping clone of original suffixed parameter.
  • Required: False
dynamic_mapping_arp_reply
  • Description: Dynamic Mapping clone of original suffixed parameter.
  • Required: False
  • choices: [‘disable’, ‘enable’]
dynamic_mapping_associated_interface
  • Description: Dynamic Mapping clone of original suffixed parameter.
  • Required: False
dynamic_mapping_block_size
  • Description: Dynamic Mapping clone of original suffixed parameter.
  • Required: False
dynamic_mapping_comments
  • Description: Dynamic Mapping clone of original suffixed parameter.
  • Required: False
dynamic_mapping_endip
  • Description: Dynamic Mapping clone of original suffixed parameter.
  • Required: False
dynamic_mapping_num_blocks_per_user
  • Description: Dynamic Mapping clone of original suffixed parameter.
  • Required: False
dynamic_mapping_pba_timeout
  • Description: Dynamic Mapping clone of original suffixed parameter.
  • Required: False
dynamic_mapping_permit_any_host
  • Description: Dynamic Mapping clone of original suffixed parameter.
  • Required: False
  • choices: [‘disable’, ‘enable’]
dynamic_mapping_source_endip
  • Description: Dynamic Mapping clone of original suffixed parameter.
  • Required: False
dynamic_mapping_source_startip
  • Description: Dynamic Mapping clone of original suffixed parameter.
  • Required: False
dynamic_mapping_startip
  • Description: Dynamic Mapping clone of original suffixed parameter.
  • Required: False
dynamic_mapping_type
  • Description: Dynamic Mapping clone of original suffixed parameter.
  • Required: False
  • choices: [‘overload’, ‘one-to-one’, ‘fixed-port-range’, ‘port-block-allocation’]
endip
  • Description: Final IPv4 address (inclusive) in the range for the address pool (format xxx.xxx.xxx.xxx, Default| 0.0.0.0).
  • Required: False
mode
  • Description: Sets one of three modes for managing the object.

    Allows use of soft-adds instead of overwriting existing values

  • Required: False

  • default: add

  • choices: [‘add’, ‘set’, ‘delete’, ‘update’]

name
  • Description: IP pool name.
  • Required: False
num_blocks_per_user
  • Description: Number of addresses blocks that can be used by a user (1 to 128, default = 8).
  • Required: False
pba_timeout
  • Description: Port block allocation timeout (seconds).
  • Required: False
permit_any_host
  • Description: Enable/disable full cone NAT.

    choice | disable | Disable full cone NAT.

    choice | enable | Enable full cone NAT.

  • Required: False

  • choices: [‘disable’, ‘enable’]

source_endip
  • Description: Final IPv4 address (inclusive) in the range of the source addresses to be translated (format xxx.xxx.xxx.xxx, Default| 0.0.0.0).
  • Required: False
source_startip
  • Description: First IPv4 address (inclusive) in the range of the source addresses to be translated (format xxx.xxx.xxx.xxx, Default| 0.0.0.0).
  • Required: False
startip
  • Description: First IPv4 address (inclusive) in the range for the address pool (format xxx.xxx.xxx.xxx, Default| 0.0.0.0).
  • Required: False
type
  • Description: IP pool type (overload, one-to-one, fixed port range, or port block allocation).

    choice | overload | IP addresses in the IP pool can be shared by clients.

    choice | one-to-one | One to one mapping.

    choice | fixed-port-range | Fixed port range.

    choice | port-block-allocation | Port block allocation.

  • Required: False

  • choices: [‘overload’, ‘one-to-one’, ‘fixed-port-range’, ‘port-block-allocation’]

Functions
  • fmgr_fwobj_ippool_modify
def fmgr_fwobj_ippool_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/firewall/ippool'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/firewall/ippool/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])

    return response


#############
# END METHODS
#############
  • main
def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        type=dict(required=False, type="str", choices=["overload",
                                                       "one-to-one",
                                                       "fixed-port-range",
                                                       "port-block-allocation"]),
        startip=dict(required=False, type="str"),
        source_startip=dict(required=False, type="str"),
        source_endip=dict(required=False, type="str"),
        permit_any_host=dict(required=False, type="str", choices=["disable", "enable"]),
        pba_timeout=dict(required=False, type="int"),
        num_blocks_per_user=dict(required=False, type="int"),
        name=dict(required=False, type="str"),
        endip=dict(required=False, type="str"),
        comments=dict(required=False, type="str"),
        block_size=dict(required=False, type="int"),
        associated_interface=dict(required=False, type="str"),
        arp_reply=dict(required=False, type="str", choices=["disable", "enable"]),
        arp_intf=dict(required=False, type="str"),
        dynamic_mapping=dict(required=False, type="list"),
        dynamic_mapping_arp_intf=dict(required=False, type="str"),
        dynamic_mapping_arp_reply=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_associated_interface=dict(required=False, type="str"),
        dynamic_mapping_block_size=dict(required=False, type="int"),
        dynamic_mapping_comments=dict(required=False, type="str"),
        dynamic_mapping_endip=dict(required=False, type="str"),
        dynamic_mapping_num_blocks_per_user=dict(required=False, type="int"),
        dynamic_mapping_pba_timeout=dict(required=False, type="int"),
        dynamic_mapping_permit_any_host=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_source_endip=dict(required=False, type="str"),
        dynamic_mapping_source_startip=dict(required=False, type="str"),
        dynamic_mapping_startip=dict(required=False, type="str"),
        dynamic_mapping_type=dict(required=False, type="str", choices=["overload",
                                                                       "one-to-one",
                                                                       "fixed-port-range",
                                                                       "port-block-allocation"]),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "type": module.params["type"],
        "startip": module.params["startip"],
        "source-startip": module.params["source_startip"],
        "source-endip": module.params["source_endip"],
        "permit-any-host": module.params["permit_any_host"],
        "pba-timeout": module.params["pba_timeout"],
        "num-blocks-per-user": module.params["num_blocks_per_user"],
        "name": module.params["name"],
        "endip": module.params["endip"],
        "comments": module.params["comments"],
        "block-size": module.params["block_size"],
        "associated-interface": module.params["associated_interface"],
        "arp-reply": module.params["arp_reply"],
        "arp-intf": module.params["arp_intf"],
        "dynamic_mapping": {
            "arp-intf": module.params["dynamic_mapping_arp_intf"],
            "arp-reply": module.params["dynamic_mapping_arp_reply"],
            "associated-interface": module.params["dynamic_mapping_associated_interface"],
            "block-size": module.params["dynamic_mapping_block_size"],
            "comments": module.params["dynamic_mapping_comments"],
            "endip": module.params["dynamic_mapping_endip"],
            "num-blocks-per-user": module.params["dynamic_mapping_num_blocks_per_user"],
            "pba-timeout": module.params["dynamic_mapping_pba_timeout"],
            "permit-any-host": module.params["dynamic_mapping_permit_any_host"],
            "source-endip": module.params["dynamic_mapping_source_endip"],
            "source-startip": module.params["dynamic_mapping_source_startip"],
            "startip": module.params["dynamic_mapping_startip"],
            "type": module.params["dynamic_mapping_type"],
        }
    }

    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['dynamic_mapping']
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)
    # UPDATE THE CHANGED PARAMGRAM
    module.paramgram = paramgram

    results = DEFAULT_RESULT_OBJ
    try:
        results = fmgr_fwobj_ippool_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {'status': ['preview'],
                    'supported_by': 'community',
                    'metadata_version': '1.1'}

DOCUMENTATION = '''
---
module: fmgr_fwobj_ippool
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author:
    - Luke Weighall (@lweighall)
    - Andrew Welsh (@Ghilli3)
    - Jim Huber (@p4r4n0y1ng)
short_description: Allows the editing of IP Pool Objects within FortiManager.
description:
  -  Allows users to add/edit/delete IP Pool Objects.

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: false
    default: root

  mode:
    description:
      - Sets one of three modes for managing the object.
      - Allows use of soft-adds instead of overwriting existing values
    choices: ['add', 'set', 'delete', 'update']
    required: false
    default: add

  type:
    description:
      - IP pool type (overload, one-to-one, fixed port range, or port block allocation).
      - choice | overload | IP addresses in the IP pool can be shared by clients.
      - choice | one-to-one | One to one mapping.
      - choice | fixed-port-range | Fixed port range.
      - choice | port-block-allocation | Port block allocation.
    required: false
    choices: ["overload", "one-to-one", "fixed-port-range", "port-block-allocation"]

  startip:
    description:
      - First IPv4 address (inclusive) in the range for the address pool (format xxx.xxx.xxx.xxx, Default| 0.0.0.0).
    required: false

  source_startip:
    description:
      -  First IPv4 address (inclusive) in the range of the source addresses to be translated (format xxx.xxx.xxx.xxx,
         Default| 0.0.0.0).
    required: false

  source_endip:
    description:
      - Final IPv4 address (inclusive) in the range of the source addresses to be translated (format xxx.xxx.xxx.xxx,
        Default| 0.0.0.0).
    required: false

  permit_any_host:
    description:
      - Enable/disable full cone NAT.
      - choice | disable | Disable full cone NAT.
      - choice | enable | Enable full cone NAT.
    required: false
    choices: ["disable", "enable"]

  pba_timeout:
    description:
      - Port block allocation timeout (seconds).
    required: false

  num_blocks_per_user:
    description:
      - Number of addresses blocks that can be used by a user (1 to 128, default = 8).
    required: false

  name:
    description:
      - IP pool name.
    required: false

  endip:
    description:
      - Final IPv4 address (inclusive) in the range for the address pool (format xxx.xxx.xxx.xxx, Default| 0.0.0.0).
    required: false

  comments:
    description:
      - Comment.
    required: false

  block_size:
    description:
      -  Number of addresses in a block (64 to 4096, default = 128).
    required: false

  associated_interface:
    description:
      - Associated interface name.
    required: false

  arp_reply:
    description:
      - Enable/disable replying to ARP requests when an IP Pool is added to a policy (default = enable).
      - choice | disable | Disable ARP reply.
      - choice | enable | Enable ARP reply.
    required: false
    choices: ["disable", "enable"]

  arp_intf:
    description:
      - Select an interface from available options that will reply to ARP requests. (If blank, any is selected).
    required: false

  dynamic_mapping:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameter.ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  dynamic_mapping_arp_intf:
    description:
      - Dynamic Mapping clone of original suffixed parameter.
    required: false

  dynamic_mapping_arp_reply:
    description:
      - Dynamic Mapping clone of original suffixed parameter.
    required: false
    choices: ["disable", "enable"]

  dynamic_mapping_associated_interface:
    description:
      - Dynamic Mapping clone of original suffixed parameter.
    required: false

  dynamic_mapping_block_size:
    description:
      - Dynamic Mapping clone of original suffixed parameter.
    required: false

  dynamic_mapping_comments:
    description:
      - Dynamic Mapping clone of original suffixed parameter.
    required: false

  dynamic_mapping_endip:
    description:
      - Dynamic Mapping clone of original suffixed parameter.
    required: false

  dynamic_mapping_num_blocks_per_user:
    description:
      - Dynamic Mapping clone of original suffixed parameter.
    required: false

  dynamic_mapping_pba_timeout:
    description:
      - Dynamic Mapping clone of original suffixed parameter.
    required: false

  dynamic_mapping_permit_any_host:
    description:
      - Dynamic Mapping clone of original suffixed parameter.
    required: false
    choices: ["disable", "enable"]

  dynamic_mapping_source_endip:
    description:
      - Dynamic Mapping clone of original suffixed parameter.
    required: false

  dynamic_mapping_source_startip:
    description:
      - Dynamic Mapping clone of original suffixed parameter.
    required: false

  dynamic_mapping_startip:
    description:
      - Dynamic Mapping clone of original suffixed parameter.
    required: false

  dynamic_mapping_type:
    description:
      - Dynamic Mapping clone of original suffixed parameter.
    required: false
    choices: ["overload", "one-to-one", "fixed-port-range", "port-block-allocation"]


'''

EXAMPLES = '''
- name: ADD FMGR_FIREWALL_IPPOOL Overload
  fmgr_fwobj_ippool:
    mode: "add"
    adom: "ansible"
    name: "Ansible_pool4_overload"
    comments: "Created by ansible"
    type: "overload"

    # OPTIONS FOR ALL MODES
    startip: "10.10.10.10"
    endip: "10.10.10.100"
    arp_reply: "enable"

- name: ADD FMGR_FIREWALL_IPPOOL one-to-one
  fmgr_fwobj_ippool:
    mode: "add"
    adom: "ansible"
    name: "Ansible_pool4_121"
    comments: "Created by ansible"
    type: "one-to-one"

    # OPTIONS FOR ALL MODES
    startip: "10.10.20.10"
    endip: "10.10.20.100"
    arp_reply: "enable"

- name: ADD FMGR_FIREWALL_IPPOOL FIXED PORT RANGE
  fmgr_fwobj_ippool:
    mode: "add"
    adom: "ansible"
    name: "Ansible_pool4_fixed_port"
    comments: "Created by ansible"
    type: "fixed-port-range"

    # OPTIONS FOR ALL MODES
    startip: "10.10.40.10"
    endip: "10.10.40.100"
    arp_reply: "enable"
    # FIXED PORT RANGE OPTIONS
    source_startip: "192.168.20.1"
    source_endip: "192.168.20.20"

- name: ADD FMGR_FIREWALL_IPPOOL PORT BLOCK ALLOCATION
  fmgr_fwobj_ippool:
    mode: "add"
    adom: "ansible"
    name: "Ansible_pool4_port_block_allocation"
    comments: "Created by ansible"
    type: "port-block-allocation"

    # OPTIONS FOR ALL MODES
    startip: "10.10.30.10"
    endip: "10.10.30.100"
    arp_reply: "enable"
    # PORT BLOCK ALLOCATION OPTIONS
    block_size: "128"
    num_blocks_per_user: "1"
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
from ansible.module_utils.network.fortimanager.common import prepare_dict
from ansible.module_utils.network.fortimanager.common import scrub_dict


###############
# START METHODS
###############


def fmgr_fwobj_ippool_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/firewall/ippool'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/firewall/ippool/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])

    return response


#############
# END METHODS
#############


def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        type=dict(required=False, type="str", choices=["overload",
                                                       "one-to-one",
                                                       "fixed-port-range",
                                                       "port-block-allocation"]),
        startip=dict(required=False, type="str"),
        source_startip=dict(required=False, type="str"),
        source_endip=dict(required=False, type="str"),
        permit_any_host=dict(required=False, type="str", choices=["disable", "enable"]),
        pba_timeout=dict(required=False, type="int"),
        num_blocks_per_user=dict(required=False, type="int"),
        name=dict(required=False, type="str"),
        endip=dict(required=False, type="str"),
        comments=dict(required=False, type="str"),
        block_size=dict(required=False, type="int"),
        associated_interface=dict(required=False, type="str"),
        arp_reply=dict(required=False, type="str", choices=["disable", "enable"]),
        arp_intf=dict(required=False, type="str"),
        dynamic_mapping=dict(required=False, type="list"),
        dynamic_mapping_arp_intf=dict(required=False, type="str"),
        dynamic_mapping_arp_reply=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_associated_interface=dict(required=False, type="str"),
        dynamic_mapping_block_size=dict(required=False, type="int"),
        dynamic_mapping_comments=dict(required=False, type="str"),
        dynamic_mapping_endip=dict(required=False, type="str"),
        dynamic_mapping_num_blocks_per_user=dict(required=False, type="int"),
        dynamic_mapping_pba_timeout=dict(required=False, type="int"),
        dynamic_mapping_permit_any_host=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_source_endip=dict(required=False, type="str"),
        dynamic_mapping_source_startip=dict(required=False, type="str"),
        dynamic_mapping_startip=dict(required=False, type="str"),
        dynamic_mapping_type=dict(required=False, type="str", choices=["overload",
                                                                       "one-to-one",
                                                                       "fixed-port-range",
                                                                       "port-block-allocation"]),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "type": module.params["type"],
        "startip": module.params["startip"],
        "source-startip": module.params["source_startip"],
        "source-endip": module.params["source_endip"],
        "permit-any-host": module.params["permit_any_host"],
        "pba-timeout": module.params["pba_timeout"],
        "num-blocks-per-user": module.params["num_blocks_per_user"],
        "name": module.params["name"],
        "endip": module.params["endip"],
        "comments": module.params["comments"],
        "block-size": module.params["block_size"],
        "associated-interface": module.params["associated_interface"],
        "arp-reply": module.params["arp_reply"],
        "arp-intf": module.params["arp_intf"],
        "dynamic_mapping": {
            "arp-intf": module.params["dynamic_mapping_arp_intf"],
            "arp-reply": module.params["dynamic_mapping_arp_reply"],
            "associated-interface": module.params["dynamic_mapping_associated_interface"],
            "block-size": module.params["dynamic_mapping_block_size"],
            "comments": module.params["dynamic_mapping_comments"],
            "endip": module.params["dynamic_mapping_endip"],
            "num-blocks-per-user": module.params["dynamic_mapping_num_blocks_per_user"],
            "pba-timeout": module.params["dynamic_mapping_pba_timeout"],
            "permit-any-host": module.params["dynamic_mapping_permit_any_host"],
            "source-endip": module.params["dynamic_mapping_source_endip"],
            "source-startip": module.params["dynamic_mapping_source_startip"],
            "startip": module.params["dynamic_mapping_startip"],
            "type": module.params["dynamic_mapping_type"],
        }
    }

    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['dynamic_mapping']
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)
    # UPDATE THE CHANGED PARAMGRAM
    module.paramgram = paramgram

    results = DEFAULT_RESULT_OBJ
    try:
        results = fmgr_fwobj_ippool_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_fwobj_ippool6

Metadata

Name: fmgr_fwobj_ippool6

Description: Allows users to add/edit/delete IPv6 Pool Objects.

Author(s):

  • Luke Weighall (github: @lweighall)
  • Andrew Welsh (github: @Ghilli3)
  • Jim Huber (github: @p4r4n0y1ng)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Luke Weighall

Module Github Link

Parameters
adom
  • Description: The ADOM the configuration should belong to.
  • Required: False
  • default: root
comments
  • Description: Comment.
  • Required: False
dynamic_mapping
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

dynamic_mapping_comments
  • Description: Dynamic Mapping clone of original suffixed parameter.
  • Required: False
dynamic_mapping_endip
  • Description: Dynamic Mapping clone of original suffixed parameter.
  • Required: False
dynamic_mapping_startip
  • Description: Dynamic Mapping clone of original suffixed parameter.
  • Required: False
endip
  • Description: Final IPv6 address (inclusive) in the range for the address pool.
  • Required: False
mode
  • Description: Sets one of three modes for managing the object.

    Allows use of soft-adds instead of overwriting existing values

  • Required: False

  • default: add

  • choices: [‘add’, ‘set’, ‘delete’, ‘update’]

name
  • Description: IPv6 IP pool name.
  • Required: False
startip
  • Description: First IPv6 address (inclusive) in the range for the address pool.
  • Required: False
Functions
  • fmgr_fwobj_ippool6_modify
def fmgr_fwobj_ippool6_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/firewall/ippool6'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/firewall/ippool6/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response
  • main
def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),
        startip=dict(required=False, type="str"),
        name=dict(required=False, type="str"),
        endip=dict(required=False, type="str"),
        comments=dict(required=False, type="str"),
        dynamic_mapping=dict(required=False, type="list"),
        dynamic_mapping_comments=dict(required=False, type="str"),
        dynamic_mapping_endip=dict(required=False, type="str"),
        dynamic_mapping_startip=dict(required=False, type="str"),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "startip": module.params["startip"],
        "name": module.params["name"],
        "endip": module.params["endip"],
        "comments": module.params["comments"],
        "dynamic_mapping": {
            "comments": module.params["dynamic_mapping_comments"],
            "endip": module.params["dynamic_mapping_endip"],
            "startip": module.params["dynamic_mapping_startip"],
        }
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['dynamic_mapping']
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)

    results = DEFAULT_RESULT_OBJ

    try:
        results = fmgr_fwobj_ippool6_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {'status': ['preview'],
                    'supported_by': 'community',
                    'metadata_version': '1.1'}

DOCUMENTATION = '''
---
module: fmgr_fwobj_ippool6
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author:
    - Luke Weighall (@lweighall)
    - Andrew Welsh (@Ghilli3)
    - Jim Huber (@p4r4n0y1ng)
short_description: Allows the editing of IP Pool Objects within FortiManager.
description:
  -  Allows users to add/edit/delete IPv6 Pool Objects.

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: false
    default: root

  mode:
    description:
      - Sets one of three modes for managing the object.
      - Allows use of soft-adds instead of overwriting existing values
    choices: ['add', 'set', 'delete', 'update']
    required: false
    default: add

  startip:
    description:
      - First IPv6 address (inclusive) in the range for the address pool.
    required: false

  name:
    description:
      - IPv6 IP pool name.
    required: false

  endip:
    description:
      - Final IPv6 address (inclusive) in the range for the address pool.
    required: false

  comments:
    description:
      - Comment.
    required: false

  dynamic_mapping:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  dynamic_mapping_comments:
    description:
      - Dynamic Mapping clone of original suffixed parameter.
    required: false

  dynamic_mapping_endip:
    description:
      - Dynamic Mapping clone of original suffixed parameter.
    required: false

  dynamic_mapping_startip:
    description:
      - Dynamic Mapping clone of original suffixed parameter.
    required: false


'''

EXAMPLES = '''
- name: ADD FMGR_FIREWALL_IPPOOL6
  fmgr_firewall_ippool6:
    mode: "add"
    adom: "ansible"
    startip:
    name: "IPv6 IPPool"
    endip:
    comments: "Created by Ansible"

- name: DELETE FMGR_FIREWALL_IPPOOL6
  fmgr_firewall_ippool6:
    mode: "delete"
    adom: "ansible"
    name: "IPv6 IPPool"
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
from ansible.module_utils.network.fortimanager.common import prepare_dict
from ansible.module_utils.network.fortimanager.common import scrub_dict


def fmgr_fwobj_ippool6_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/firewall/ippool6'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/firewall/ippool6/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),
        startip=dict(required=False, type="str"),
        name=dict(required=False, type="str"),
        endip=dict(required=False, type="str"),
        comments=dict(required=False, type="str"),
        dynamic_mapping=dict(required=False, type="list"),
        dynamic_mapping_comments=dict(required=False, type="str"),
        dynamic_mapping_endip=dict(required=False, type="str"),
        dynamic_mapping_startip=dict(required=False, type="str"),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "startip": module.params["startip"],
        "name": module.params["name"],
        "endip": module.params["endip"],
        "comments": module.params["comments"],
        "dynamic_mapping": {
            "comments": module.params["dynamic_mapping_comments"],
            "endip": module.params["dynamic_mapping_endip"],
            "startip": module.params["dynamic_mapping_startip"],
        }
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['dynamic_mapping']
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)

    results = DEFAULT_RESULT_OBJ

    try:
        results = fmgr_fwobj_ippool6_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_fwobj_service

Metadata

Name: fmgr_fwobj_service

Description: Manages FortiManager Firewall Service Objects.

Author(s):

  • Luke Weighall (github: @lweighall)
  • Andrew Welsh (github: @Ghilli3)
  • Jim Huber (github: @p4r4n0y1ng)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Luke Weighall

Module Github Link

Parameters
adom
  • Description: The ADOM the configuration should belong to.
  • Required: False
  • default: root
app_category
  • Description: Application category ID.
  • Required: False
app_service_type
  • Description: Application service type.
  • Required: False
application
  • Description: Application ID.
  • Required: False
category
  • Description: Service category.
  • Required: False
check_reset_range
  • Description: Enable disable RST check.
  • Required: False
color
  • Description: GUI icon color.
  • Required: False
  • default: 22
comment
  • Description: Comment.
  • Required: False
custom_type
  • Description: Tells module what kind of custom service to be added.
  • Required: False
  • default: all
  • choices: [‘tcp_udp_sctp’, ‘icmp’, ‘icmp6’, ‘ip’, ‘http’, ‘ftp’, ‘connect’, ‘socks_tcp’, ‘socks_udp’, ‘all’]
explicit_proxy
  • Description: Enable/disable explicit web proxy service.
  • Required: False
  • default: disable
  • choices: [‘enable’, ‘disable’]
fqdn
  • Description: Fully qualified domain name.
  • Required: False
  • default:
group_member
  • Description: Comma-Seperated list of members’ names.
  • Required: False
group_name
  • Description: Name of the Service Group.
  • Required: False
icmp_code
  • Description: ICMP code.
  • Required: False
icmp_type
  • Description: ICMP type.
  • Required: False
iprange
  • Description: Start IP-End IP.
  • Required: False
  • default: 0.0.0.0
mode
  • Description: Sets one of three modes for managing the object.
  • Required: False
  • default: add
  • choices: [‘add’, ‘set’, ‘delete’]
name
  • Description: Custom service name.
  • Required: False
object_type
  • Description: Tells module if we are adding a custom service, category, or group.
  • Required: False
  • choices: [‘custom’, ‘group’, ‘category’]
protocol
  • Description: Protocol type.
  • Required: False
protocol_number
  • Description: IP protocol number.
  • Required: False
sctp_portrange
  • Description: Multiple SCTP port ranges. Comma separated list of destination ports to add (i.e. ‘443,80’).

    Syntax is <destPort:sourcePort>

    If no sourcePort is defined, it assumes all of them.

    Ranges can be defined with a hyphen -

    Examples – ‘443’ (destPort 443 only) ‘443:1000-2000’ (destPort 443 from source ports 1000-2000).

    String multiple together in same quotes, comma separated. (‘443:1000-2000, 80:1000-2000’).

  • Required: False

session_ttl
  • Description: Session TTL (300 - 604800, 0 = default).
  • Required: False
  • default: 0
tcp_halfclose_timer
  • Description: TCP half close timeout (1 - 86400 sec, 0 = default).
  • Required: False
  • default: 0
tcp_halfopen_timer
  • Description: TCP half close timeout (1 - 86400 sec, 0 = default).
  • Required: False
  • default: 0
tcp_portrange
  • Description: Comma separated list of destination ports to add (i.e. ‘443,80’).

    Syntax is <destPort:sourcePort>

    If no sourcePort is defined, it assumes all of them.

    Ranges can be defined with a hyphen -

    Examples – ‘443’ (destPort 443 only) ‘443:1000-2000’ (destPort 443 from source ports 1000-2000).

    String multiple together in same quotes, comma separated. (‘443:1000-2000, 80:1000-2000’).

  • Required: False

tcp_timewait_timer
  • Description: TCP half close timeout (1 - 300 sec, 0 = default).
  • Required: False
  • default: 0
udp_idle_timer
  • Description: TCP half close timeout (0 - 86400 sec, 0 = default).
  • Required: False
  • default: 0
udp_portrange
  • Description: Comma separated list of destination ports to add (i.e. ‘443,80’).

    Syntax is <destPort:sourcePort>

    If no sourcePort is defined, it assumes all of them.

    Ranges can be defined with a hyphen -

    Examples – ‘443’ (destPort 443 only) ‘443:1000-2000’ (destPort 443 from source ports 1000-2000).

    String multiple together in same quotes, comma separated. (‘443:1000-2000, 80:1000-2000’).

  • Required: False

visibility
  • Description: Enable/disable service visibility.
  • Required: False
  • default: enable
  • choices: [‘enable’, ‘disable’]
Functions
  • fmgr_fwobj_service_custom
def fmgr_fwobj_service_custom(fmgr, paramgram):
    """
    description:
        - the tcp and udp-portrange parameters are in a list when there are multiple. they are not in a list when they
          singular or by themselves (only 1 was listed)
        - the syntax for this is (destPort:sourcePort). Ranges are (xxxx-xxxx) i.e. 443:443, or 443:1000-2000.
        - if you leave out the second field after the colon (source port) it assumes any source port (which is usual)
        - multiples would look like ['443:1000-2000','80']
        - a single would look simple like "443:1000-2000" without the list around it ( a string!)
        - the protocol parameter is the protocol NUMBER, not the string of it.
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    response = DEFAULT_RESULT_OBJ
    if paramgram["mode"] in ['set', 'add']:
        # SET THE URL FOR ADD / SET
        url = '/pm/config/adom/{adom}/obj/firewall/service/custom'.format(adom=paramgram["adom"])
        # BUILD THE DEFAULT DATAGRAM
        datagram = {
            # ADVANCED OPTIONS
            "app-category": paramgram["app-category"],
            "app-service-type": paramgram["app-service-type"],
            "application": paramgram["application"],
            "category": paramgram["category"],
            "check-reset-range": paramgram["check-reset-range"],
            "color": paramgram["color"],
            "session-ttl": paramgram["session-ttl"],
            "tcp-halfclose-timer": paramgram["tcp-halfclose-timer"],
            "tcp-halfopen-timer": paramgram["tcp-halfopen-timer"],
            "tcp-timewait-timer": paramgram["tcp-timewait-timer"],
            "udp-idle-timer": paramgram["udp-idle-timer"],
            "visibility": paramgram["visibility"],
            "comment": paramgram["comment"],
            "proxy": paramgram["explicit-proxy"],
            "name": paramgram["name"]
        }

        if datagram["proxy"] == "disable":
            #######################################
            # object-type = "TCP/UDP/SCTP"
            #######################################
            if paramgram["custom_type"] == "tcp_udp_sctp":
                datagram["protocol"] = "TCP/UDP/SCTP"
                # PROCESS PORT RANGES TO PUT INTO THE PROPER SYNTAX
                if paramgram["tcp-portrange"] is not None:
                    tcp_list = []
                    for tcp in paramgram["tcp-portrange"].split(","):
                        tcp = tcp.strip()
                        tcp_list.append(tcp)
                    datagram["tcp-portrange"] = tcp_list

                if paramgram["udp-portrange"] is not None:
                    udp_list = []
                    for udp in paramgram["udp-portrange"].split(","):
                        udp = udp.strip()
                        udp_list.append(udp)
                    datagram["udp-portrange"] = udp_list

                if paramgram["sctp-portrange"] is not None:
                    sctp_list = []
                    for sctp in paramgram["sctp-portrange"].split(","):
                        sctp = sctp.strip()
                        sctp_list.append(sctp)
                    datagram["sctp-portrange"] = sctp_list

            #######################################
            # object-type = "ICMP"
            #######################################
            if paramgram["custom_type"] == "icmp":
                datagram["icmpcode"] = paramgram["icmp_code"]
                datagram["icmptype"] = paramgram["icmp_type"]
                datagram["protocol"] = "ICMP"

            #######################################
            # object-type = "ICMP6"
            #######################################
            if paramgram["custom_type"] == "icmp6":
                datagram["icmpcode"] = paramgram["icmp_code"]
                datagram["icmptype"] = paramgram["icmp_type"]
                datagram["protocol"] = "ICMP6"

            #######################################
            # object-type = "IP"
            #######################################
            if paramgram["custom_type"] == "ip":
                datagram["protocol"] = "IP"
                datagram["protocol-number"] = paramgram["protocol-number"]

        #######################################
        # object-type in any of the explicit proxy options
        #######################################
        if datagram["proxy"] == "enable":
            datagram["protocol"] = paramgram["custom_type"].upper()
            datagram["iprange"] = paramgram["iprange"]

            # PROCESS PROXY TCP PORT RANGES TO PUT INTO THE PROPER SYNTAX
            if paramgram["tcp-portrange"] is not None:
                tcp_list = []
                for tcp in paramgram["tcp-portrange"].split(","):
                    tcp = tcp.strip()
                    tcp_list.append(tcp)
                datagram["tcp-portrange"] = tcp_list

    if paramgram["mode"] == "delete":
        datagram = {
            "name": paramgram["name"]
        }
        # SET DELETE URL
        url = '/pm/config/adom/{adom}/obj/firewall/service/custom' \
              '/{name}'.format(adom=paramgram["adom"], name=paramgram["name"])

    datagram = scrub_dict(datagram)
    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response
  • fmgr_fwobj_service_group
def fmgr_fwobj_service_group(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    response = DEFAULT_RESULT_OBJ
    if paramgram["mode"] in ['set', 'add']:
        url = '/pm/config/adom/{adom}/obj/firewall/service/group'.format(adom=paramgram["adom"])
        datagram = {
            "name": paramgram["group-name"],
            "comment": paramgram["comment"],
            "proxy": paramgram["explicit-proxy"],
            "color": paramgram["color"]
        }

        members = paramgram["group-member"]
        member = []
        for obj in members.split(","):
            member.append(obj.strip())
        datagram["member"] = member

    if paramgram["mode"] == "delete":
        datagram = {
            "name": paramgram["name"]
        }
        # SET DELETE URL
        url = '/pm/config/adom/{adom}/obj/firewall/service/group' \
              '/{name}'.format(adom=paramgram["adom"], name=paramgram["group-name"])

    datagram = scrub_dict(datagram)
    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response
  • fmgr_fwobj_service_category
def fmgr_fwobj_service_category(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    response = DEFAULT_RESULT_OBJ
    if paramgram["mode"] in ['set', 'add']:
        url = '/pm/config/adom/{adom}/obj/firewall/service/category'.format(adom=paramgram["adom"])
        # GET RID OF ANY WHITESPACE
        category = paramgram["category"]
        category = category.strip()

        datagram = {
            "name": paramgram["category"],
            "comment": "Created by Ansible"
        }

    # IF MODE = DELETE
    if paramgram["mode"] == "delete":
        datagram = {
            "name": paramgram["name"]
        }
        # SET DELETE URL
        url = '/pm/config/adom/{adom}/obj/firewall/service/category' \
              '/{name}'.format(adom=paramgram["adom"], name=paramgram["category"])

    datagram = scrub_dict(datagram)
    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response
  • main
def main():
    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        mode=dict(required=False, type="str", choices=['add', 'set', 'delete'], default="add"),
        app_category=dict(required=False, type="str"),
        app_service_type=dict(required=False, type="str"),
        application=dict(required=False, type="str"),
        category=dict(required=False, type="str"),
        check_reset_range=dict(required=False, type="str"),
        color=dict(required=False, type="int", default=22),
        comment=dict(required=False, type="str"),
        custom_type=dict(required=False, type="str", choices=['tcp_udp_sctp', 'icmp', 'icmp6', 'ip', 'http', 'ftp',
                                                              'connect', 'socks_tcp', 'socks_udp', 'all'],
                         default="all"),
        explicit_proxy=dict(required=False, type="str", choices=['enable', 'disable'], default="disable"),
        fqdn=dict(required=False, type="str", default=""),
        group_name=dict(required=False, type="str"),
        group_member=dict(required=False, type="str"),
        icmp_code=dict(required=False, type="int"),
        icmp_type=dict(required=False, type="int"),
        iprange=dict(required=False, type="str", default="0.0.0.0"),
        name=dict(required=False, type="str"),
        protocol=dict(required=False, type="str"),
        protocol_number=dict(required=False, type="int"),
        sctp_portrange=dict(required=False, type="str"),
        session_ttl=dict(required=False, type="int", default=0),
        object_type=dict(required=False, type="str", choices=['custom', 'group', 'category']),
        tcp_halfclose_timer=dict(required=False, type="int", default=0),
        tcp_halfopen_timer=dict(required=False, type="int", default=0),
        tcp_portrange=dict(required=False, type="str"),
        tcp_timewait_timer=dict(required=False, type="int", default=0),
        udp_idle_timer=dict(required=False, type="int", default=0),
        udp_portrange=dict(required=False, type="str"),
        visibility=dict(required=False, type="str", default="enable", choices=["enable", "disable"]),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE DATAGRAM
    paramgram = {
        "adom": module.params["adom"],
        "app-category": module.params["app_category"],
        "app-service-type": module.params["app_service_type"],
        "application": module.params["application"],
        "category": module.params["category"],
        "check-reset-range": module.params["check_reset_range"],
        "color": module.params["color"],
        "comment": module.params["comment"],
        "custom_type": module.params["custom_type"],
        "explicit-proxy": module.params["explicit_proxy"],
        "fqdn": module.params["fqdn"],
        "group-name": module.params["group_name"],
        "group-member": module.params["group_member"],
        "icmp_code": module.params["icmp_code"],
        "icmp_type": module.params["icmp_type"],
        "iprange": module.params["iprange"],
        "name": module.params["name"],
        "mode": module.params["mode"],
        "protocol": module.params["protocol"],
        "protocol-number": module.params["protocol_number"],
        "sctp-portrange": module.params["sctp_portrange"],
        "object_type": module.params["object_type"],
        "session-ttl": module.params["session_ttl"],
        "tcp-halfclose-timer": module.params["tcp_halfclose_timer"],
        "tcp-halfopen-timer": module.params["tcp_halfopen_timer"],
        "tcp-portrange": module.params["tcp_portrange"],
        "tcp-timewait-timer": module.params["tcp_timewait_timer"],
        "udp-idle-timer": module.params["udp_idle_timer"],
        "udp-portrange": module.params["udp_portrange"],
        "visibility": module.params["visibility"],
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    results = DEFAULT_RESULT_OBJ

    try:
        # CHECK FOR CATEGORIES TO ADD
        # THIS IS ONLY WHEN OBJECT_TYPE ISN'T SPECIFICALLY ADDING A CATEGORY!
        # WE NEED TO ADD THE CATEGORY BEFORE ADDING THE OBJECT
        # IF ANY category ARE DEFINED AND MODE IS ADD OR SET LETS ADD THOSE
        # THIS IS A "BLIND ADD" AND THE EXIT CODE FOR OBJECT ALREADY EXISTS IS TREATED AS A PASS
        if paramgram["category"] is not None and paramgram["mode"] in ['add', 'set'] \
                and paramgram["object_type"] != "category":
            category_add = fmgr_fwobj_service_category(fmgr, paramgram)
            fmgr.govern_response(module=module, results=category_add,
                                 ansible_facts=fmgr.construct_ansible_facts(category_add, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # IF OBJECT_TYPE IS CATEGORY...
        if paramgram["object_type"] == 'category':
            results = fmgr_fwobj_service_category(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0, -2, -3],
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # IF OBJECT_TYPE IS CUSTOM...
        if paramgram["object_type"] == 'custom':
            results = fmgr_fwobj_service_custom(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0, -2, -3],
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # IF OBJECT_TYPE IS GROUP...
        if paramgram["object_type"] == 'group':
            results = fmgr_fwobj_service_group(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0, -2, -3],
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function

__metaclass__ = type

ANSIBLE_METADATA = {
    "metadata_version": "1.1",
    "status": ["preview"],
    "supported_by": "community"
}

DOCUMENTATION = '''
---
module: fmgr_fwobj_service
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author:
    - Luke Weighall (@lweighall)
    - Andrew Welsh (@Ghilli3)
    - Jim Huber (@p4r4n0y1ng)
short_description: Manages FortiManager Firewall Service Objects.
description:
  -  Manages FortiManager Firewall Service Objects.

options:
  adom:
    description:
     -The ADOM the configuration should belong to.
    required: false
    default: root

  app_category:
    description:
      - Application category ID.
    required: false

  app_service_type:
    description:
      - Application service type.
    required: false

  application:
    description:
      - Application ID.
    required: false

  category:
    description:
      - Service category.
    required: false

  check_reset_range:
    description:
      - Enable disable RST check.
    required: false

  color:
    description:
      - GUI icon color.
    required: false
    default: 22

  comment:
    description:
      - Comment.
    required: false

  custom_type:
    description:
      - Tells module what kind of custom service to be added.
    choices: ['tcp_udp_sctp', 'icmp', 'icmp6', 'ip', 'http', 'ftp', 'connect', 'socks_tcp', 'socks_udp', 'all']
    default: all
    required: false

  explicit_proxy:
    description:
      - Enable/disable explicit web proxy service.
    choices: ['enable', 'disable']
    default: 'disable'
    required: false

  fqdn:
    description:
      - Fully qualified domain name.
    required: false
    default: ""

  group_name:
    description:
      - Name of the Service Group.
    required: false

  group_member:
    description:
      - Comma-Seperated list of members' names.
    required: false

  icmp_code:
    description:
      - ICMP code.
    required: false

  icmp_type:
    description:
      - ICMP type.
    required: false

  iprange:
    description:
      - Start IP-End IP.
    required: false
    default: "0.0.0.0"

  name:
    description:
      - Custom service name.
    required: false

  mode:
    description:
      - Sets one of three modes for managing the object.
    choices: ['add', 'set', 'delete']
    default: add
    required: false

  object_type:
    description:
      - Tells module if we are adding a custom service, category, or group.
    choices: ['custom', 'group', 'category']
    required: false

  protocol:
    description:
      - Protocol type.
    required: false

  protocol_number:
    description:
      - IP protocol number.
    required: false

  sctp_portrange:
    description:
      - Multiple SCTP port ranges. Comma separated list of destination ports to add (i.e. '443,80').
      - Syntax is <destPort:sourcePort>
      - If no sourcePort is defined, it assumes all of them.
      - Ranges can be defined with a hyphen -
      - Examples -- '443' (destPort 443 only)  '443:1000-2000' (destPort 443 from source ports 1000-2000).
      - String multiple together in same quotes, comma separated. ('443:1000-2000, 80:1000-2000').
    required: false

  session_ttl:
    description:
      - Session TTL (300 - 604800, 0 = default).
    required: false
    default: 0

  tcp_halfclose_timer:
    description:
      - TCP half close timeout (1 - 86400 sec, 0 = default).
    required: false
    default: 0

  tcp_halfopen_timer:
    description:
      - TCP half close timeout (1 - 86400 sec, 0 = default).
    required: false
    default: 0

  tcp_portrange:
    description:
      - Comma separated list of destination ports to add (i.e. '443,80').
      - Syntax is <destPort:sourcePort>
      - If no sourcePort is defined, it assumes all of them.
      - Ranges can be defined with a hyphen -
      - Examples -- '443' (destPort 443 only)  '443:1000-2000' (destPort 443 from source ports 1000-2000).
      - String multiple together in same quotes, comma separated. ('443:1000-2000, 80:1000-2000').
    required: false

  tcp_timewait_timer:
    description:
      - TCP half close timeout (1 - 300 sec, 0 = default).
    required: false
    default: 0

  udp_idle_timer:
    description:
      - TCP half close timeout (0 - 86400 sec, 0 = default).
    required: false
    default: 0

  udp_portrange:
    description:
      - Comma separated list of destination ports to add (i.e. '443,80').
      - Syntax is <destPort:sourcePort>
      - If no sourcePort is defined, it assumes all of them.
      - Ranges can be defined with a hyphen -
      - Examples -- '443' (destPort 443 only)  '443:1000-2000' (destPort 443 from source ports 1000-2000).
      - String multiple together in same quotes, comma separated. ('443:1000-2000, 80:1000-2000').
    required: false

  visibility:
    description:
      - Enable/disable service visibility.
    required: false
    choices: ["enable", "disable"]
    default: "enable"

'''

EXAMPLES = '''
- name: ADD A CUSTOM SERVICE FOR TCP/UDP/SCP
  fmgr_fwobj_service:
    adom: "ansible"
    name: "ansible_custom_service"
    object_type: "custom"
    custom_type: "tcp_udp_sctp"
    tcp_portrange: "443"
    udp_portrange: "51"
    sctp_portrange: "100"

- name: ADD A CUSTOM SERVICE FOR TCP/UDP/SCP WITH SOURCE RANGES AND MULTIPLES
  fmgr_fwobj_service:
    adom: "ansible"
    name: "ansible_custom_serviceWithSource"
    object_type: "custom"
    custom_type: "tcp_udp_sctp"
    tcp_portrange: "443:2000-1000,80-82:10000-20000"
    udp_portrange: "51:100-200,162:200-400"
    sctp_portrange: "100:2000-2500"

- name: ADD A CUSTOM SERVICE FOR ICMP
  fmgr_fwobj_service:
    adom: "ansible"
    name: "ansible_custom_icmp"
    object_type: "custom"
    custom_type: "icmp"
    icmp_type: "8"
    icmp_code: "3"

- name: ADD A CUSTOM SERVICE FOR ICMP6
  fmgr_fwobj_service:
    adom: "ansible"
    name: "ansible_custom_icmp6"
    object_type: "custom"
    custom_type: "icmp6"
    icmp_type: "5"
    icmp_code: "1"

- name: ADD A CUSTOM SERVICE FOR IP - GRE
  fmgr_fwobj_service:
    adom: "ansible"
    name: "ansible_custom_icmp6"
    object_type: "custom"
    custom_type: "ip"
    protocol_number: "47"

- name: ADD A CUSTOM PROXY FOR ALL WITH SOURCE RANGES AND MULTIPLES
  fmgr_fwobj_service:
    adom: "ansible"
    name: "ansible_custom_proxy_all"
    object_type: "custom"
    custom_type: "all"
    explicit_proxy: "enable"
    tcp_portrange: "443:2000-1000,80-82:10000-20000"
    iprange: "www.ansible.com"
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
from ansible.module_utils.network.fortimanager.common import scrub_dict


def fmgr_fwobj_service_custom(fmgr, paramgram):
    """
    description:
        - the tcp and udp-portrange parameters are in a list when there are multiple. they are not in a list when they
          singular or by themselves (only 1 was listed)
        - the syntax for this is (destPort:sourcePort). Ranges are (xxxx-xxxx) i.e. 443:443, or 443:1000-2000.
        - if you leave out the second field after the colon (source port) it assumes any source port (which is usual)
        - multiples would look like ['443:1000-2000','80']
        - a single would look simple like "443:1000-2000" without the list around it ( a string!)
        - the protocol parameter is the protocol NUMBER, not the string of it.
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    response = DEFAULT_RESULT_OBJ
    if paramgram["mode"] in ['set', 'add']:
        # SET THE URL FOR ADD / SET
        url = '/pm/config/adom/{adom}/obj/firewall/service/custom'.format(adom=paramgram["adom"])
        # BUILD THE DEFAULT DATAGRAM
        datagram = {
            # ADVANCED OPTIONS
            "app-category": paramgram["app-category"],
            "app-service-type": paramgram["app-service-type"],
            "application": paramgram["application"],
            "category": paramgram["category"],
            "check-reset-range": paramgram["check-reset-range"],
            "color": paramgram["color"],
            "session-ttl": paramgram["session-ttl"],
            "tcp-halfclose-timer": paramgram["tcp-halfclose-timer"],
            "tcp-halfopen-timer": paramgram["tcp-halfopen-timer"],
            "tcp-timewait-timer": paramgram["tcp-timewait-timer"],
            "udp-idle-timer": paramgram["udp-idle-timer"],
            "visibility": paramgram["visibility"],
            "comment": paramgram["comment"],
            "proxy": paramgram["explicit-proxy"],
            "name": paramgram["name"]
        }

        if datagram["proxy"] == "disable":
            #######################################
            # object-type = "TCP/UDP/SCTP"
            #######################################
            if paramgram["custom_type"] == "tcp_udp_sctp":
                datagram["protocol"] = "TCP/UDP/SCTP"
                # PROCESS PORT RANGES TO PUT INTO THE PROPER SYNTAX
                if paramgram["tcp-portrange"] is not None:
                    tcp_list = []
                    for tcp in paramgram["tcp-portrange"].split(","):
                        tcp = tcp.strip()
                        tcp_list.append(tcp)
                    datagram["tcp-portrange"] = tcp_list

                if paramgram["udp-portrange"] is not None:
                    udp_list = []
                    for udp in paramgram["udp-portrange"].split(","):
                        udp = udp.strip()
                        udp_list.append(udp)
                    datagram["udp-portrange"] = udp_list

                if paramgram["sctp-portrange"] is not None:
                    sctp_list = []
                    for sctp in paramgram["sctp-portrange"].split(","):
                        sctp = sctp.strip()
                        sctp_list.append(sctp)
                    datagram["sctp-portrange"] = sctp_list

            #######################################
            # object-type = "ICMP"
            #######################################
            if paramgram["custom_type"] == "icmp":
                datagram["icmpcode"] = paramgram["icmp_code"]
                datagram["icmptype"] = paramgram["icmp_type"]
                datagram["protocol"] = "ICMP"

            #######################################
            # object-type = "ICMP6"
            #######################################
            if paramgram["custom_type"] == "icmp6":
                datagram["icmpcode"] = paramgram["icmp_code"]
                datagram["icmptype"] = paramgram["icmp_type"]
                datagram["protocol"] = "ICMP6"

            #######################################
            # object-type = "IP"
            #######################################
            if paramgram["custom_type"] == "ip":
                datagram["protocol"] = "IP"
                datagram["protocol-number"] = paramgram["protocol-number"]

        #######################################
        # object-type in any of the explicit proxy options
        #######################################
        if datagram["proxy"] == "enable":
            datagram["protocol"] = paramgram["custom_type"].upper()
            datagram["iprange"] = paramgram["iprange"]

            # PROCESS PROXY TCP PORT RANGES TO PUT INTO THE PROPER SYNTAX
            if paramgram["tcp-portrange"] is not None:
                tcp_list = []
                for tcp in paramgram["tcp-portrange"].split(","):
                    tcp = tcp.strip()
                    tcp_list.append(tcp)
                datagram["tcp-portrange"] = tcp_list

    if paramgram["mode"] == "delete":
        datagram = {
            "name": paramgram["name"]
        }
        # SET DELETE URL
        url = '/pm/config/adom/{adom}/obj/firewall/service/custom' \
              '/{name}'.format(adom=paramgram["adom"], name=paramgram["name"])

    datagram = scrub_dict(datagram)
    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


def fmgr_fwobj_service_group(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    response = DEFAULT_RESULT_OBJ
    if paramgram["mode"] in ['set', 'add']:
        url = '/pm/config/adom/{adom}/obj/firewall/service/group'.format(adom=paramgram["adom"])
        datagram = {
            "name": paramgram["group-name"],
            "comment": paramgram["comment"],
            "proxy": paramgram["explicit-proxy"],
            "color": paramgram["color"]
        }

        members = paramgram["group-member"]
        member = []
        for obj in members.split(","):
            member.append(obj.strip())
        datagram["member"] = member

    if paramgram["mode"] == "delete":
        datagram = {
            "name": paramgram["name"]
        }
        # SET DELETE URL
        url = '/pm/config/adom/{adom}/obj/firewall/service/group' \
              '/{name}'.format(adom=paramgram["adom"], name=paramgram["group-name"])

    datagram = scrub_dict(datagram)
    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


def fmgr_fwobj_service_category(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    response = DEFAULT_RESULT_OBJ
    if paramgram["mode"] in ['set', 'add']:
        url = '/pm/config/adom/{adom}/obj/firewall/service/category'.format(adom=paramgram["adom"])
        # GET RID OF ANY WHITESPACE
        category = paramgram["category"]
        category = category.strip()

        datagram = {
            "name": paramgram["category"],
            "comment": "Created by Ansible"
        }

    # IF MODE = DELETE
    if paramgram["mode"] == "delete":
        datagram = {
            "name": paramgram["name"]
        }
        # SET DELETE URL
        url = '/pm/config/adom/{adom}/obj/firewall/service/category' \
              '/{name}'.format(adom=paramgram["adom"], name=paramgram["category"])

    datagram = scrub_dict(datagram)
    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


def main():
    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        mode=dict(required=False, type="str", choices=['add', 'set', 'delete'], default="add"),
        app_category=dict(required=False, type="str"),
        app_service_type=dict(required=False, type="str"),
        application=dict(required=False, type="str"),
        category=dict(required=False, type="str"),
        check_reset_range=dict(required=False, type="str"),
        color=dict(required=False, type="int", default=22),
        comment=dict(required=False, type="str"),
        custom_type=dict(required=False, type="str", choices=['tcp_udp_sctp', 'icmp', 'icmp6', 'ip', 'http', 'ftp',
                                                              'connect', 'socks_tcp', 'socks_udp', 'all'],
                         default="all"),
        explicit_proxy=dict(required=False, type="str", choices=['enable', 'disable'], default="disable"),
        fqdn=dict(required=False, type="str", default=""),
        group_name=dict(required=False, type="str"),
        group_member=dict(required=False, type="str"),
        icmp_code=dict(required=False, type="int"),
        icmp_type=dict(required=False, type="int"),
        iprange=dict(required=False, type="str", default="0.0.0.0"),
        name=dict(required=False, type="str"),
        protocol=dict(required=False, type="str"),
        protocol_number=dict(required=False, type="int"),
        sctp_portrange=dict(required=False, type="str"),
        session_ttl=dict(required=False, type="int", default=0),
        object_type=dict(required=False, type="str", choices=['custom', 'group', 'category']),
        tcp_halfclose_timer=dict(required=False, type="int", default=0),
        tcp_halfopen_timer=dict(required=False, type="int", default=0),
        tcp_portrange=dict(required=False, type="str"),
        tcp_timewait_timer=dict(required=False, type="int", default=0),
        udp_idle_timer=dict(required=False, type="int", default=0),
        udp_portrange=dict(required=False, type="str"),
        visibility=dict(required=False, type="str", default="enable", choices=["enable", "disable"]),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE DATAGRAM
    paramgram = {
        "adom": module.params["adom"],
        "app-category": module.params["app_category"],
        "app-service-type": module.params["app_service_type"],
        "application": module.params["application"],
        "category": module.params["category"],
        "check-reset-range": module.params["check_reset_range"],
        "color": module.params["color"],
        "comment": module.params["comment"],
        "custom_type": module.params["custom_type"],
        "explicit-proxy": module.params["explicit_proxy"],
        "fqdn": module.params["fqdn"],
        "group-name": module.params["group_name"],
        "group-member": module.params["group_member"],
        "icmp_code": module.params["icmp_code"],
        "icmp_type": module.params["icmp_type"],
        "iprange": module.params["iprange"],
        "name": module.params["name"],
        "mode": module.params["mode"],
        "protocol": module.params["protocol"],
        "protocol-number": module.params["protocol_number"],
        "sctp-portrange": module.params["sctp_portrange"],
        "object_type": module.params["object_type"],
        "session-ttl": module.params["session_ttl"],
        "tcp-halfclose-timer": module.params["tcp_halfclose_timer"],
        "tcp-halfopen-timer": module.params["tcp_halfopen_timer"],
        "tcp-portrange": module.params["tcp_portrange"],
        "tcp-timewait-timer": module.params["tcp_timewait_timer"],
        "udp-idle-timer": module.params["udp_idle_timer"],
        "udp-portrange": module.params["udp_portrange"],
        "visibility": module.params["visibility"],
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    results = DEFAULT_RESULT_OBJ

    try:
        # CHECK FOR CATEGORIES TO ADD
        # THIS IS ONLY WHEN OBJECT_TYPE ISN'T SPECIFICALLY ADDING A CATEGORY!
        # WE NEED TO ADD THE CATEGORY BEFORE ADDING THE OBJECT
        # IF ANY category ARE DEFINED AND MODE IS ADD OR SET LETS ADD THOSE
        # THIS IS A "BLIND ADD" AND THE EXIT CODE FOR OBJECT ALREADY EXISTS IS TREATED AS A PASS
        if paramgram["category"] is not None and paramgram["mode"] in ['add', 'set'] \
                and paramgram["object_type"] != "category":
            category_add = fmgr_fwobj_service_category(fmgr, paramgram)
            fmgr.govern_response(module=module, results=category_add,
                                 ansible_facts=fmgr.construct_ansible_facts(category_add, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # IF OBJECT_TYPE IS CATEGORY...
        if paramgram["object_type"] == 'category':
            results = fmgr_fwobj_service_category(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0, -2, -3],
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # IF OBJECT_TYPE IS CUSTOM...
        if paramgram["object_type"] == 'custom':
            results = fmgr_fwobj_service_custom(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0, -2, -3],
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # IF OBJECT_TYPE IS GROUP...
        if paramgram["object_type"] == 'group':
            results = fmgr_fwobj_service_group(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, good_codes=[0, -2, -3],
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_fwobj_vip

Metadata

Name: fmgr_fwobj_vip

Description: Manages Virtual IP objects in FortiManager for IPv4

Author(s):

  • Luke Weighall (github: @lweighall)
  • Andrew Welsh (github: @Ghilli3)
  • Jim Huber (github: @p4r4n0y1ng)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Luke Weighall

Module Github Link

Parameters
adom
  • Description: The ADOM the configuration should belong to.
  • Required: False
  • default: root
arp_reply
  • Description: Enable to respond to ARP requests for this virtual IP address. Enabled by default.

    choice | disable | Disable ARP reply.

    choice | enable | Enable ARP reply.

  • Required: False

  • choices: [‘disable’, ‘enable’]

color
  • Description: Color of icon on the GUI.
  • Required: False
comment
  • Description: Comment.
  • Required: False
dns_mapping_ttl
  • Description: DNS mapping TTL (Set to zero to use TTL in DNS response, default = 0).
  • Required: False
dynamic_mapping
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

dynamic_mapping_arp_reply
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | disable |

    choice | enable |

  • Required: False

  • choices: [‘disable’, ‘enable’]

dynamic_mapping_color
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_comment
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_dns_mapping_ttl
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_extaddr
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_extintf
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_extip
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_extport
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_gratuitous_arp_interval
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_http_ip_header
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | disable |

    choice | enable |

  • Required: False

  • choices: [‘disable’, ‘enable’]

dynamic_mapping_http_ip_header_name
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_http_multiplex
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | disable |

    choice | enable |

  • Required: False

  • choices: [‘disable’, ‘enable’]

dynamic_mapping_ldb_method
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | static |

    choice | round-robin |

    choice | weighted |

    choice | least-session |

    choice | least-rtt |

    choice | first-alive |

    choice | http-host |

  • Required: False

  • choices: [‘static’, ‘round-robin’, ‘weighted’, ‘least-session’, ‘least-rtt’, ‘first-alive’, ‘http-host’]

dynamic_mapping_mapped_addr
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_mappedip
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_mappedport
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_max_embryonic_connections
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_monitor
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_nat_source_vip
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | disable |

    choice | enable |

  • Required: False

  • choices: [‘disable’, ‘enable’]

dynamic_mapping_outlook_web_access
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | disable |

    choice | enable |

  • Required: False

  • choices: [‘disable’, ‘enable’]

dynamic_mapping_persistence
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | none |

    choice | http-cookie |

    choice | ssl-session-id |

  • Required: False

  • choices: [‘none’, ‘http-cookie’, ‘ssl-session-id’]

dynamic_mapping_portforward
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | disable |

    choice | enable |

  • Required: False

  • choices: [‘disable’, ‘enable’]

dynamic_mapping_portmapping_type
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | 1-to-1 |

    choice | m-to-n |

  • Required: False

  • choices: [‘1-to-1’, ‘m-to-n’]

dynamic_mapping_protocol
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | tcp |

    choice | udp |

    choice | sctp |

    choice | icmp |

  • Required: False

  • choices: [‘tcp’, ‘udp’, ‘sctp’, ‘icmp’]

dynamic_mapping_realservers_client_ip
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_realservers_healthcheck
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | disable |

    choice | enable |

    choice | vip |

  • Required: False

  • choices: [‘disable’, ‘enable’, ‘vip’]

dynamic_mapping_realservers_holddown_interval
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_realservers_http_host
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_realservers_ip
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_realservers_max_connections
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_realservers_monitor
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_realservers_port
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_realservers_seq
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_realservers_status
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | active |

    choice | standby |

    choice | disable |

  • Required: False

  • choices: [‘active’, ‘standby’, ‘disable’]

dynamic_mapping_realservers_weight
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_server_type
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | http |

    choice | https |

    choice | ssl |

    choice | tcp |

    choice | udp |

    choice | ip |

    choice | imaps |

    choice | pop3s |

    choice | smtps |

  • Required: False

  • choices: [‘http’, ‘https’, ‘ssl’, ‘tcp’, ‘udp’, ‘ip’, ‘imaps’, ‘pop3s’, ‘smtps’]

dynamic_mapping_service
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_src_filter
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_srcintf_filter
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_ssl_algorithm
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | high |

    choice | medium |

    choice | low |

    choice | custom |

  • Required: False

  • choices: [‘high’, ‘medium’, ‘low’, ‘custom’]

dynamic_mapping_ssl_certificate
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_ssl_cipher_suites_cipher
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | TLS-RSA-WITH-RC4-128-MD5 |

    choice | TLS-RSA-WITH-RC4-128-SHA |

    choice | TLS-RSA-WITH-DES-CBC-SHA |

    choice | TLS-RSA-WITH-3DES-EDE-CBC-SHA |

    choice | TLS-RSA-WITH-AES-128-CBC-SHA |

    choice | TLS-RSA-WITH-AES-256-CBC-SHA |

    choice | TLS-RSA-WITH-AES-128-CBC-SHA256 |

    choice | TLS-RSA-WITH-AES-256-CBC-SHA256 |

    choice | TLS-RSA-WITH-CAMELLIA-128-CBC-SHA |

    choice | TLS-RSA-WITH-CAMELLIA-256-CBC-SHA |

    choice | TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256 |

    choice | TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256 |

    choice | TLS-RSA-WITH-SEED-CBC-SHA |

    choice | TLS-RSA-WITH-ARIA-128-CBC-SHA256 |

    choice | TLS-RSA-WITH-ARIA-256-CBC-SHA384 |

    choice | TLS-DHE-RSA-WITH-DES-CBC-SHA |

    choice | TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA |

    choice | TLS-DHE-RSA-WITH-AES-128-CBC-SHA |

    choice | TLS-DHE-RSA-WITH-AES-256-CBC-SHA |

    choice | TLS-DHE-RSA-WITH-AES-128-CBC-SHA256 |

    choice | TLS-DHE-RSA-WITH-AES-256-CBC-SHA256 |

    choice | TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA |

    choice | TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA |

    choice | TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256 |

    choice | TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256 |

    choice | TLS-DHE-RSA-WITH-SEED-CBC-SHA |

    choice | TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256 |

    choice | TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384 |

    choice | TLS-ECDHE-RSA-WITH-RC4-128-SHA |

    choice | TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA |

    choice | TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA |

    choice | TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA |

    choice | TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256 |

    choice | TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256 |

    choice | TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256 |

    choice | TLS-DHE-RSA-WITH-AES-128-GCM-SHA256 |

    choice | TLS-DHE-RSA-WITH-AES-256-GCM-SHA384 |

    choice | TLS-DHE-DSS-WITH-AES-128-CBC-SHA |

    choice | TLS-DHE-DSS-WITH-AES-256-CBC-SHA |

    choice | TLS-DHE-DSS-WITH-AES-128-CBC-SHA256 |

    choice | TLS-DHE-DSS-WITH-AES-128-GCM-SHA256 |

    choice | TLS-DHE-DSS-WITH-AES-256-CBC-SHA256 |

    choice | TLS-DHE-DSS-WITH-AES-256-GCM-SHA384 |

    choice | TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256 |

    choice | TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256 |

    choice | TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384 |

    choice | TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384 |

    choice | TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA |

    choice | TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256 |

    choice | TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 |

    choice | TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384 |

    choice | TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384 |

    choice | TLS-RSA-WITH-AES-128-GCM-SHA256 |

    choice | TLS-RSA-WITH-AES-256-GCM-SHA384 |

    choice | TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA |

    choice | TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA |

    choice | TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256 |

    choice | TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256 |

    choice | TLS-DHE-DSS-WITH-SEED-CBC-SHA |

    choice | TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256 |

    choice | TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384 |

    choice | TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256 |

    choice | TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384 |

    choice | TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256 |

    choice | TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384 |

    choice | TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA |

    choice | TLS-DHE-DSS-WITH-DES-CBC-SHA |

  • Required: False

  • choices: [‘TLS-RSA-WITH-RC4-128-MD5’, ‘TLS-RSA-WITH-RC4-128-SHA’, ‘TLS-RSA-WITH-DES-CBC-SHA’, ‘TLS-RSA-WITH-3DES-EDE-CBC-SHA’, ‘TLS-RSA-WITH-AES-128-CBC-SHA’, ‘TLS-RSA-WITH-AES-256-CBC-SHA’, ‘TLS-RSA-WITH-AES-128-CBC-SHA256’, ‘TLS-RSA-WITH-AES-256-CBC-SHA256’, ‘TLS-RSA-WITH-CAMELLIA-128-CBC-SHA’, ‘TLS-RSA-WITH-CAMELLIA-256-CBC-SHA’, ‘TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256’, ‘TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256’, ‘TLS-RSA-WITH-SEED-CBC-SHA’, ‘TLS-RSA-WITH-ARIA-128-CBC-SHA256’, ‘TLS-RSA-WITH-ARIA-256-CBC-SHA384’, ‘TLS-DHE-RSA-WITH-DES-CBC-SHA’, ‘TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA’, ‘TLS-DHE-RSA-WITH-AES-128-CBC-SHA’, ‘TLS-DHE-RSA-WITH-AES-256-CBC-SHA’, ‘TLS-DHE-RSA-WITH-AES-128-CBC-SHA256’, ‘TLS-DHE-RSA-WITH-AES-256-CBC-SHA256’, ‘TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA’, ‘TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA’, ‘TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256’, ‘TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256’, ‘TLS-DHE-RSA-WITH-SEED-CBC-SHA’, ‘TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256’, ‘TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384’, ‘TLS-ECDHE-RSA-WITH-RC4-128-SHA’, ‘TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA’, ‘TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA’, ‘TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA’, ‘TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256’, ‘TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256’, ‘TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256’, ‘TLS-DHE-RSA-WITH-AES-128-GCM-SHA256’, ‘TLS-DHE-RSA-WITH-AES-256-GCM-SHA384’, ‘TLS-DHE-DSS-WITH-AES-128-CBC-SHA’, ‘TLS-DHE-DSS-WITH-AES-256-CBC-SHA’, ‘TLS-DHE-DSS-WITH-AES-128-CBC-SHA256’, ‘TLS-DHE-DSS-WITH-AES-128-GCM-SHA256’, ‘TLS-DHE-DSS-WITH-AES-256-CBC-SHA256’, ‘TLS-DHE-DSS-WITH-AES-256-GCM-SHA384’, ‘TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256’, ‘TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256’, ‘TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384’, ‘TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384’, ‘TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA’, ‘TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256’, ‘TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256’, ‘TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384’, ‘TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384’, ‘TLS-RSA-WITH-AES-128-GCM-SHA256’, ‘TLS-RSA-WITH-AES-256-GCM-SHA384’, ‘TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA’, ‘TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA’, ‘TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256’, ‘TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256’, ‘TLS-DHE-DSS-WITH-SEED-CBC-SHA’, ‘TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256’, ‘TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384’, ‘TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256’, ‘TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384’, ‘TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256’, ‘TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384’, ‘TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA’, ‘TLS-DHE-DSS-WITH-DES-CBC-SHA’]

dynamic_mapping_ssl_cipher_suites_versions
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    FLAG Based Options. Specify multiple in list form.

    flag | ssl-3.0 |

    flag | tls-1.0 |

    flag | tls-1.1 |

    flag | tls-1.2 |

  • Required: False

  • choices: [‘ssl-3.0’, ‘tls-1.0’, ‘tls-1.1’, ‘tls-1.2’]

dynamic_mapping_ssl_client_fallback
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | disable |

    choice | enable |

  • Required: False

  • choices: [‘disable’, ‘enable’]

dynamic_mapping_ssl_client_renegotiation
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | deny |

    choice | allow |

    choice | secure |

  • Required: False

  • choices: [‘deny’, ‘allow’, ‘secure’]

dynamic_mapping_ssl_client_session_state_max
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_ssl_client_session_state_timeout
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_ssl_client_session_state_type
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | disable |

    choice | time |

    choice | count |

    choice | both |

  • Required: False

  • choices: [‘disable’, ‘time’, ‘count’, ‘both’]

dynamic_mapping_ssl_dh_bits
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | 768 |

    choice | 1024 |

    choice | 1536 |

    choice | 2048 |

    choice | 3072 |

    choice | 4096 |

  • Required: False

  • choices: [‘768’, ‘1024’, ‘1536’, ‘2048’, ‘3072’, ‘4096’]

dynamic_mapping_ssl_hpkp
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | disable |

    choice | enable |

    choice | report-only |

  • Required: False

  • choices: [‘disable’, ‘enable’, ‘report-only’]

dynamic_mapping_ssl_hpkp_age
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_ssl_hpkp_backup
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_ssl_hpkp_include_subdomains
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | disable |

    choice | enable |

  • Required: False

  • choices: [‘disable’, ‘enable’]

dynamic_mapping_ssl_hpkp_primary
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_ssl_hpkp_report_uri
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_ssl_hsts
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | disable |

    choice | enable |

  • Required: False

  • choices: [‘disable’, ‘enable’]

dynamic_mapping_ssl_hsts_age
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_ssl_hsts_include_subdomains
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | disable |

    choice | enable |

  • Required: False

  • choices: [‘disable’, ‘enable’]

dynamic_mapping_ssl_http_location_conversion
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | disable |

    choice | enable |

  • Required: False

  • choices: [‘disable’, ‘enable’]

dynamic_mapping_ssl_http_match_host
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | disable |

    choice | enable |

  • Required: False

  • choices: [‘disable’, ‘enable’]

dynamic_mapping_ssl_max_version
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | ssl-3.0 |

    choice | tls-1.0 |

    choice | tls-1.1 |

    choice | tls-1.2 |

  • Required: False

  • choices: [‘ssl-3.0’, ‘tls-1.0’, ‘tls-1.1’, ‘tls-1.2’]

dynamic_mapping_ssl_min_version
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | ssl-3.0 |

    choice | tls-1.0 |

    choice | tls-1.1 |

    choice | tls-1.2 |

  • Required: False

  • choices: [‘ssl-3.0’, ‘tls-1.0’, ‘tls-1.1’, ‘tls-1.2’]

dynamic_mapping_ssl_mode
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | half |

    choice | full |

  • Required: False

  • choices: [‘half’, ‘full’]

dynamic_mapping_ssl_pfs
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | require |

    choice | deny |

    choice | allow |

  • Required: False

  • choices: [‘require’, ‘deny’, ‘allow’]

dynamic_mapping_ssl_send_empty_frags
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | disable |

    choice | enable |

  • Required: False

  • choices: [‘disable’, ‘enable’]

dynamic_mapping_ssl_server_algorithm
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | high |

    choice | low |

    choice | medium |

    choice | custom |

    choice | client |

  • Required: False

  • choices: [‘high’, ‘low’, ‘medium’, ‘custom’, ‘client’]

dynamic_mapping_ssl_server_max_version
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | ssl-3.0 |

    choice | tls-1.0 |

    choice | tls-1.1 |

    choice | tls-1.2 |

    choice | client |

  • Required: False

  • choices: [‘ssl-3.0’, ‘tls-1.0’, ‘tls-1.1’, ‘tls-1.2’, ‘client’]

dynamic_mapping_ssl_server_min_version
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | ssl-3.0 |

    choice | tls-1.0 |

    choice | tls-1.1 |

    choice | tls-1.2 |

    choice | client |

  • Required: False

  • choices: [‘ssl-3.0’, ‘tls-1.0’, ‘tls-1.1’, ‘tls-1.2’, ‘client’]

dynamic_mapping_ssl_server_session_state_max
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_ssl_server_session_state_timeout
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
  • Required: False
dynamic_mapping_ssl_server_session_state_type
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | disable |

    choice | time |

    choice | count |

    choice | both |

  • Required: False

  • choices: [‘disable’, ‘time’, ‘count’, ‘both’]

dynamic_mapping_type
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | static-nat |

    choice | load-balance |

    choice | server-load-balance |

    choice | dns-translation |

    choice | fqdn |

  • Required: False

  • choices: [‘static-nat’, ‘load-balance’, ‘server-load-balance’, ‘dns-translation’, ‘fqdn’]

dynamic_mapping_weblogic_server
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | disable |

    choice | enable |

  • Required: False

  • choices: [‘disable’, ‘enable’]

dynamic_mapping_websphere_server
  • Description: Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.

    choice | disable |

    choice | enable |

  • Required: False

  • choices: [‘disable’, ‘enable’]

extaddr
  • Description: External FQDN address name.
  • Required: False
extintf
  • Description: Interface connected to the source network that receives the packets that will be forwarded to the destination

    network.

  • Required: False

extip
  • Description: IP address or address range on the external interface that you want to map to an address or address range on t

    he destination network.

  • Required: False

extport
  • Description: Incoming port number range that you want to map to a port number range on the destination network.
  • Required: False
gratuitous_arp_interval
  • Description: Enable to have the VIP send gratuitous ARPs. 0=disabled. Set from 5 up to 8640000 seconds to enable.
  • Required: False
http_ip_header
  • Description: For HTTP multiplexing, enable to add the original client IP address in the XForwarded-For HTTP header.

    choice | disable | Disable adding HTTP header.

    choice | enable | Enable adding HTTP header.

  • Required: False

  • choices: [‘disable’, ‘enable’]

http_ip_header_name
  • Description: For HTTP multiplexing, enter a custom HTTPS header name. The orig client IP address is added to this header.

    If empty, X-Forwarded-For is used.

  • Required: False

http_multiplex
  • Description: Enable/disable HTTP multiplexing.

    choice | disable | Disable HTTP session multiplexing.

    choice | enable | Enable HTTP session multiplexing.

  • Required: False

  • choices: [‘disable’, ‘enable’]

ldb_method
  • Description: Method used to distribute sessions to real servers.

    choice | static | Distribute to server based on source IP.

    choice | round-robin | Distribute to server based round robin order.

    choice | weighted | Distribute to server based on weight.

    choice | least-session | Distribute to server with lowest session count.

    choice | least-rtt | Distribute to server with lowest Round-Trip-Time.

    choice | first-alive | Distribute to the first server that is alive.

    choice | http-host | Distribute to server based on host field in HTTP header.

  • Required: False

  • choices: [‘static’, ‘round-robin’, ‘weighted’, ‘least-session’, ‘least-rtt’, ‘first-alive’, ‘http-host’]

mapped_addr
  • Description: Mapped FQDN address name.
  • Required: False
mappedip
  • Description: IP address or address range on the destination network to which the external IP address is mapped.
  • Required: False
mappedport
  • Description: Port number range on the destination network to which the external port number range is mapped.
  • Required: False
max_embryonic_connections
  • Description: Maximum number of incomplete connections.
  • Required: False
mode
  • Description: Sets one of three modes for managing the object.

    Allows use of soft-adds instead of overwriting existing values

  • Required: False

  • default: add

  • choices: [‘add’, ‘set’, ‘delete’, ‘update’]

monitor
  • Description: Name of the health check monitor to use when polling to determine a virtual server’s connectivity status.
  • Required: False
name
  • Description: Virtual IP name.
  • Required: False
nat_source_vip
  • Description: Enable to prevent unintended servers from using a virtual IP.

    Disable to use the actual IP address of the server as the source address.

    choice | disable | Do not force to NAT as VIP.

    choice | enable | Force to NAT as VIP.

  • Required: False

  • choices: [‘disable’, ‘enable’]

outlook_web_access
  • Description: Enable to add the Front-End-Https header for Microsoft Outlook Web Access.

    choice | disable | Disable Outlook Web Access support.

    choice | enable | Enable Outlook Web Access support.

  • Required: False

  • choices: [‘disable’, ‘enable’]

persistence
  • Description: Configure how to make sure that clients connect to the same server every time they make a request that is part

    of the same session.

    choice | none | None.

    choice | http-cookie | HTTP cookie.

    choice | ssl-session-id | SSL session ID.

  • Required: False

  • choices: [‘none’, ‘http-cookie’, ‘ssl-session-id’]

portforward
  • Description: Enable/disable port forwarding.

    choice | disable | Disable port forward.

    choice | enable | Enable port forward.

  • Required: False

  • choices: [‘disable’, ‘enable’]

portmapping_type
  • Description: Port mapping type.

    choice | 1-to-1 | One to one.

    choice | m-to-n | Many to many.

  • Required: False

  • choices: [‘1-to-1’, ‘m-to-n’]

protocol
  • Description: Protocol to use when forwarding packets.

    choice | tcp | TCP.

    choice | udp | UDP.

    choice | sctp | SCTP.

    choice | icmp | ICMP.

  • Required: False

  • choices: [‘tcp’, ‘udp’, ‘sctp’, ‘icmp’]

realservers
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

realservers_client_ip
  • Description: Only clients in this IP range can connect to this real server.
  • Required: False
realservers_healthcheck
  • Description: Enable to check the responsiveness of the real server before forwarding traffic.

    choice | disable | Disable per server health check.

    choice | enable | Enable per server health check.

    choice | vip | Use health check defined in VIP.

  • Required: False

  • choices: [‘disable’, ‘enable’, ‘vip’]

realservers_holddown_interval
  • Description: Time in seconds that the health check monitor monitors an unresponsive server that should be active.
  • Required: False
realservers_http_host
  • Description: HTTP server domain name in HTTP header.
  • Required: False
realservers_ip
  • Description: IP address of the real server.
  • Required: False
realservers_max_connections
  • Description: Max number of active connections that can be directed to the real server. When reached, sessions are sent to

    their real servers.

  • Required: False

realservers_monitor
  • Description: Name of the health check monitor to use when polling to determine a virtual server’s connectivity status.
  • Required: False
realservers_port
  • Description: Port for communicating with the real server. Required if port forwarding is enabled.
  • Required: False
realservers_seq
  • Description: Real Server Sequence Number
  • Required: False
realservers_status
  • Description: Set the status of the real server to active so that it can accept traffic.

    Or on standby or disabled so no traffic is sent.

    choice | active | Server status active.

    choice | standby | Server status standby.

    choice | disable | Server status disable.

  • Required: False

  • choices: [‘active’, ‘standby’, ‘disable’]

realservers_weight
  • Description: Weight of the real server. If weighted load balancing is enabled, the server with the highest weight gets more

    connections.

  • Required: False

server_type
  • Description: Protocol to be load balanced by the virtual server (also called the server load balance virtual IP).

    choice | http | HTTP

    choice | https | HTTPS

    choice | ssl | SSL

    choice | tcp | TCP

    choice | udp | UDP

    choice | ip | IP

    choice | imaps | IMAPS

    choice | pop3s | POP3S

    choice | smtps | SMTPS

  • Required: False

  • choices: [‘http’, ‘https’, ‘ssl’, ‘tcp’, ‘udp’, ‘ip’, ‘imaps’, ‘pop3s’, ‘smtps’]

service
  • Description: Service name.
  • Required: False
src_filter
  • Description: Source address filter. Each address must be either an IP/subnet (x.x.x.x/n) or a range (x.x.x.x-y.y.y.y).

    Separate addresses with spaces.

  • Required: False

srcintf_filter
  • Description: Interfaces to which the VIP applies. Separate the names with spaces.
  • Required: False
ssl_algorithm
  • Description: Permitted encryption algorithms for SSL sessions according to encryption strength.

    choice | high | High encryption. Allow only AES and ChaCha.

    choice | medium | Medium encryption. Allow AES, ChaCha, 3DES, and RC4.

    choice | low | Low encryption. Allow AES, ChaCha, 3DES, RC4, and DES.

    choice | custom | Custom encryption. Use config ssl-cipher-suites to select the cipher suites that are allowed.

  • Required: False

  • choices: [‘high’, ‘medium’, ‘low’, ‘custom’]

ssl_certificate
  • Description: The name of the SSL certificate to use for SSL acceleration.
  • Required: False
ssl_cipher_suites
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

ssl_cipher_suites_cipher
  • Description: Cipher suite name.

    choice | TLS-RSA-WITH-RC4-128-MD5 | Cipher suite TLS-RSA-WITH-RC4-128-MD5.

    choice | TLS-RSA-WITH-RC4-128-SHA | Cipher suite TLS-RSA-WITH-RC4-128-SHA.

    choice | TLS-RSA-WITH-DES-CBC-SHA | Cipher suite TLS-RSA-WITH-DES-CBC-SHA.

    choice | TLS-RSA-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-RSA-WITH-3DES-EDE-CBC-SHA.

    choice | TLS-RSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-RSA-WITH-AES-128-CBC-SHA.

    choice | TLS-RSA-WITH-AES-256-CBC-SHA | Cipher suite TLS-RSA-WITH-AES-256-CBC-SHA.

    choice | TLS-RSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-RSA-WITH-AES-128-CBC-SHA256.

    choice | TLS-RSA-WITH-AES-256-CBC-SHA256 | Cipher suite TLS-RSA-WITH-AES-256-CBC-SHA256.

    choice | TLS-RSA-WITH-CAMELLIA-128-CBC-SHA | Cipher suite TLS-RSA-WITH-CAMELLIA-128-CBC-SHA.

    choice | TLS-RSA-WITH-CAMELLIA-256-CBC-SHA | Cipher suite TLS-RSA-WITH-CAMELLIA-256-CBC-SHA.

    choice | TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256 | Cipher suite TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256.

    choice | TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256 | Cipher suite TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256.

    choice | TLS-RSA-WITH-SEED-CBC-SHA | Cipher suite TLS-RSA-WITH-SEED-CBC-SHA.

    choice | TLS-RSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-RSA-WITH-ARIA-128-CBC-SHA256.

    choice | TLS-RSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-RSA-WITH-ARIA-256-CBC-SHA384.

    choice | TLS-DHE-RSA-WITH-DES-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-DES-CBC-SHA.

    choice | TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA.

    choice | TLS-DHE-RSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-AES-128-CBC-SHA.

    choice | TLS-DHE-RSA-WITH-AES-256-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-AES-256-CBC-SHA.

    choice | TLS-DHE-RSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-AES-128-CBC-SHA256.

    choice | TLS-DHE-RSA-WITH-AES-256-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-AES-256-CBC-SHA256.

    choice | TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA.

    choice | TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA.

    choice | TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256.

    choice | TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256.

    choice | TLS-DHE-RSA-WITH-SEED-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-SEED-CBC-SHA.

    choice | TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256.

    choice | TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384.

    choice | TLS-ECDHE-RSA-WITH-RC4-128-SHA | Cipher suite TLS-ECDHE-RSA-WITH-RC4-128-SHA.

    choice | TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA.

    choice | TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA.

    choice | TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA | Cipher suite TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA.

    choice | TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256.

    choice | TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256.

    choice | TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256 | Cipher suite TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256.

    choice | TLS-DHE-RSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-DHE-RSA-WITH-AES-128-GCM-SHA256.

    choice | TLS-DHE-RSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-DHE-RSA-WITH-AES-256-GCM-SHA384.

    choice | TLS-DHE-DSS-WITH-AES-128-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-AES-128-CBC-SHA.

    choice | TLS-DHE-DSS-WITH-AES-256-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-AES-256-CBC-SHA.

    choice | TLS-DHE-DSS-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-AES-128-CBC-SHA256.

    choice | TLS-DHE-DSS-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-DHE-DSS-WITH-AES-128-GCM-SHA256.

    choice | TLS-DHE-DSS-WITH-AES-256-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-AES-256-CBC-SHA256.

    choice | TLS-DHE-DSS-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-DHE-DSS-WITH-AES-256-GCM-SHA384.

    choice | TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256.

    choice | TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256.

    choice | TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384 | Cipher suite TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384.

    choice | TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384.

    choice | TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA.

    choice | TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256.

    choice | TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256.

    choice | TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384.

    choice | TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384.

    choice | TLS-RSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-RSA-WITH-AES-128-GCM-SHA256.

    choice | TLS-RSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-RSA-WITH-AES-256-GCM-SHA384.

    choice | TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA | Cipher suite TLS-DSS-RSA-WITH-CAMELLIA-128-CBC-SHA.

    choice | TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA.

    choice | TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256.

    choice | TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256.

    choice | TLS-DHE-DSS-WITH-SEED-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-SEED-CBC-SHA.

    choice | TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256.

    choice | TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384.

    choice | TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256.

    choice | TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384.

    choice | TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC_SHA256.

    choice | TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC_SHA384.

    choice | TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA.

    choice | TLS-DHE-DSS-WITH-DES-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-DES-CBC-SHA.

  • Required: False

  • choices: [‘TLS-RSA-WITH-RC4-128-MD5’, ‘TLS-RSA-WITH-RC4-128-SHA’, ‘TLS-RSA-WITH-DES-CBC-SHA’, ‘TLS-RSA-WITH-3DES-EDE-CBC-SHA’, ‘TLS-RSA-WITH-AES-128-CBC-SHA’, ‘TLS-RSA-WITH-AES-256-CBC-SHA’, ‘TLS-RSA-WITH-AES-128-CBC-SHA256’, ‘TLS-RSA-WITH-AES-256-CBC-SHA256’, ‘TLS-RSA-WITH-CAMELLIA-128-CBC-SHA’, ‘TLS-RSA-WITH-CAMELLIA-256-CBC-SHA’, ‘TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256’, ‘TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256’, ‘TLS-RSA-WITH-SEED-CBC-SHA’, ‘TLS-RSA-WITH-ARIA-128-CBC-SHA256’, ‘TLS-RSA-WITH-ARIA-256-CBC-SHA384’, ‘TLS-DHE-RSA-WITH-DES-CBC-SHA’, ‘TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA’, ‘TLS-DHE-RSA-WITH-AES-128-CBC-SHA’, ‘TLS-DHE-RSA-WITH-AES-256-CBC-SHA’, ‘TLS-DHE-RSA-WITH-AES-128-CBC-SHA256’, ‘TLS-DHE-RSA-WITH-AES-256-CBC-SHA256’, ‘TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA’, ‘TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA’, ‘TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256’, ‘TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256’, ‘TLS-DHE-RSA-WITH-SEED-CBC-SHA’, ‘TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256’, ‘TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384’, ‘TLS-ECDHE-RSA-WITH-RC4-128-SHA’, ‘TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA’, ‘TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA’, ‘TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA’, ‘TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256’, ‘TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256’, ‘TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256’, ‘TLS-DHE-RSA-WITH-AES-128-GCM-SHA256’, ‘TLS-DHE-RSA-WITH-AES-256-GCM-SHA384’, ‘TLS-DHE-DSS-WITH-AES-128-CBC-SHA’, ‘TLS-DHE-DSS-WITH-AES-256-CBC-SHA’, ‘TLS-DHE-DSS-WITH-AES-128-CBC-SHA256’, ‘TLS-DHE-DSS-WITH-AES-128-GCM-SHA256’, ‘TLS-DHE-DSS-WITH-AES-256-CBC-SHA256’, ‘TLS-DHE-DSS-WITH-AES-256-GCM-SHA384’, ‘TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256’, ‘TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256’, ‘TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384’, ‘TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384’, ‘TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA’, ‘TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256’, ‘TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256’, ‘TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384’, ‘TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384’, ‘TLS-RSA-WITH-AES-128-GCM-SHA256’, ‘TLS-RSA-WITH-AES-256-GCM-SHA384’, ‘TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA’, ‘TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA’, ‘TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256’, ‘TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256’, ‘TLS-DHE-DSS-WITH-SEED-CBC-SHA’, ‘TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256’, ‘TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384’, ‘TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256’, ‘TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384’, ‘TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256’, ‘TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384’, ‘TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA’, ‘TLS-DHE-DSS-WITH-DES-CBC-SHA’]

ssl_cipher_suites_versions
  • Description: SSL/TLS versions that the cipher suite can be used with.

    FLAG Based Options. Specify multiple in list form.

    flag | ssl-3.0 | SSL 3.0.

    flag | tls-1.0 | TLS 1.0.

    flag | tls-1.1 | TLS 1.1.

    flag | tls-1.2 | TLS 1.2.

  • Required: False

  • choices: [‘ssl-3.0’, ‘tls-1.0’, ‘tls-1.1’, ‘tls-1.2’]

ssl_client_fallback
  • Description: Enable/disable support for preventing Downgrade Attacks on client connections (RFC 7507).

    choice | disable | Disable.

    choice | enable | Enable.

  • Required: False

  • choices: [‘disable’, ‘enable’]

ssl_client_renegotiation
  • Description: Allow, deny, or require secure renegotiation of client sessions to comply with RFC 5746.

    choice | deny | Abort any client initiated SSL re-negotiation attempt.

    choice | allow | Allow a SSL client to renegotiate.

    choice | secure | Abort any client initiated SSL re-negotiation attempt that does not use RFC 5746.

  • Required: False

  • choices: [‘deny’, ‘allow’, ‘secure’]

ssl_client_session_state_max
  • Description: Maximum number of client to FortiGate SSL session states to keep.
  • Required: False
ssl_client_session_state_timeout
  • Description: Number of minutes to keep client to FortiGate SSL session state.
  • Required: False
ssl_client_session_state_type
  • Description: How to expire SSL sessions for the segment of the SSL connection between the client and the FortiGate.

    choice | disable | Do not keep session states.

    choice | time | Expire session states after this many minutes.

    choice | count | Expire session states when this maximum is reached.

    choice | both | Expire session states based on time or count, whichever occurs first.

  • Required: False

  • choices: [‘disable’, ‘time’, ‘count’, ‘both’]

ssl_dh_bits
  • Description: Number of bits to use in the Diffie-Hellman exchange for RSA encryption of SSL sessions.

    choice | 768 | 768-bit Diffie-Hellman prime.

    choice | 1024 | 1024-bit Diffie-Hellman prime.

    choice | 1536 | 1536-bit Diffie-Hellman prime.

    choice | 2048 | 2048-bit Diffie-Hellman prime.

    choice | 3072 | 3072-bit Diffie-Hellman prime.

    choice | 4096 | 4096-bit Diffie-Hellman prime.

  • Required: False

  • choices: [‘768’, ‘1024’, ‘1536’, ‘2048’, ‘3072’, ‘4096’]

ssl_hpkp
  • Description: Enable/disable including HPKP header in response.

    choice | disable | Do not add a HPKP header to each HTTP response.

    choice | enable | Add a HPKP header to each a HTTP response.

    choice | report-only | Add a HPKP Report-Only header to each HTTP response.

  • Required: False

  • choices: [‘disable’, ‘enable’, ‘report-only’]

ssl_hpkp_age
  • Description: Number of seconds the client should honour the HPKP setting.
  • Required: False
ssl_hpkp_backup
  • Description: Certificate to generate backup HPKP pin from.
  • Required: False
ssl_hpkp_include_subdomains
  • Description: Indicate that HPKP header applies to all subdomains.

    choice | disable | HPKP header does not apply to subdomains.

    choice | enable | HPKP header applies to subdomains.

  • Required: False

  • choices: [‘disable’, ‘enable’]

ssl_hpkp_primary
  • Description: Certificate to generate primary HPKP pin from.
  • Required: False
ssl_hpkp_report_uri
  • Description: URL to report HPKP violations to.
  • Required: False
ssl_hsts
  • Description: Enable/disable including HSTS header in response.

    choice | disable | Do not add a HSTS header to each a HTTP response.

    choice | enable | Add a HSTS header to each HTTP response.

  • Required: False

  • choices: [‘disable’, ‘enable’]

ssl_hsts_age
  • Description: Number of seconds the client should honour the HSTS setting.
  • Required: False
ssl_hsts_include_subdomains
  • Description: Indicate that HSTS header applies to all subdomains.

    choice | disable | HSTS header does not apply to subdomains.

    choice | enable | HSTS header applies to subdomains.

  • Required: False

  • choices: [‘disable’, ‘enable’]

ssl_http_location_conversion
  • Description: Enable to replace HTTP with HTTPS in the reply’s Location HTTP header field.

    choice | disable | Disable HTTP location conversion.

    choice | enable | Enable HTTP location conversion.

  • Required: False

  • choices: [‘disable’, ‘enable’]

ssl_http_match_host
  • Description: Enable/disable HTTP host matching for location conversion.

    choice | disable | Do not match HTTP host.

    choice | enable | Match HTTP host in response header.

  • Required: False

  • choices: [‘disable’, ‘enable’]

ssl_max_version
  • Description: Highest SSL/TLS version acceptable from a client.

    choice | ssl-3.0 | SSL 3.0.

    choice | tls-1.0 | TLS 1.0.

    choice | tls-1.1 | TLS 1.1.

    choice | tls-1.2 | TLS 1.2.

  • Required: False

  • choices: [‘ssl-3.0’, ‘tls-1.0’, ‘tls-1.1’, ‘tls-1.2’]

ssl_min_version
  • Description: Lowest SSL/TLS version acceptable from a client.

    choice | ssl-3.0 | SSL 3.0.

    choice | tls-1.0 | TLS 1.0.

    choice | tls-1.1 | TLS 1.1.

    choice | tls-1.2 | TLS 1.2.

  • Required: False

  • choices: [‘ssl-3.0’, ‘tls-1.0’, ‘tls-1.1’, ‘tls-1.2’]

ssl_mode
  • Description: Apply SSL offloading mode

    choice | half | Client to FortiGate SSL.

    choice | full | Client to FortiGate and FortiGate to Server SSL.

  • Required: False

  • choices: [‘half’, ‘full’]

ssl_pfs
  • Description: Select the cipher suites that can be used for SSL perfect forward secrecy (PFS).

    choice | require | Allow only Diffie-Hellman cipher-suites, so PFS is applied.

    choice | deny | Allow only non-Diffie-Hellman cipher-suites, so PFS is not applied.

    choice | allow | Allow use of any cipher suite so PFS may or may not be used depending on the cipher suite

  • Required: False

  • choices: [‘require’, ‘deny’, ‘allow’]

ssl_send_empty_frags
  • Description: Enable/disable sending empty fragments to avoid CBC IV attacks (SSL 3.0 &amp; TLS 1.0 only).

    choice | disable | Do not send empty fragments.

    choice | enable | Send empty fragments.

  • Required: False

  • choices: [‘disable’, ‘enable’]

ssl_server_algorithm
  • Description: Permitted encryption algorithms for the server side of SSL full mode sessions according to encryption strength

    choice | high | High encryption. Allow only AES and ChaCha.

    choice | low | Low encryption. Allow AES, ChaCha, 3DES, RC4, and DES.

    choice | medium | Medium encryption. Allow AES, ChaCha, 3DES, and RC4.

    choice | custom | Custom encryption. Use ssl-server-cipher-suites to select the cipher suites that are allowed.

    choice | client | Use the same encryption algorithms for both client and server sessions.

  • Required: False

  • choices: [‘high’, ‘low’, ‘medium’, ‘custom’, ‘client’]

ssl_server_cipher_suites
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

ssl_server_cipher_suites_cipher
  • Description: Cipher suite name.

    choice | TLS-RSA-WITH-RC4-128-MD5 | Cipher suite TLS-RSA-WITH-RC4-128-MD5.

    choice | TLS-RSA-WITH-RC4-128-SHA | Cipher suite TLS-RSA-WITH-RC4-128-SHA.

    choice | TLS-RSA-WITH-DES-CBC-SHA | Cipher suite TLS-RSA-WITH-DES-CBC-SHA.

    choice | TLS-RSA-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-RSA-WITH-3DES-EDE-CBC-SHA.

    choice | TLS-RSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-RSA-WITH-AES-128-CBC-SHA.

    choice | TLS-RSA-WITH-AES-256-CBC-SHA | Cipher suite TLS-RSA-WITH-AES-256-CBC-SHA.

    choice | TLS-RSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-RSA-WITH-AES-128-CBC-SHA256.

    choice | TLS-RSA-WITH-AES-256-CBC-SHA256 | Cipher suite TLS-RSA-WITH-AES-256-CBC-SHA256.

    choice | TLS-RSA-WITH-CAMELLIA-128-CBC-SHA | Cipher suite TLS-RSA-WITH-CAMELLIA-128-CBC-SHA.

    choice | TLS-RSA-WITH-CAMELLIA-256-CBC-SHA | Cipher suite TLS-RSA-WITH-CAMELLIA-256-CBC-SHA.

    choice | TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256 | Cipher suite TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256.

    choice | TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256 | Cipher suite TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256.

    choice | TLS-RSA-WITH-SEED-CBC-SHA | Cipher suite TLS-RSA-WITH-SEED-CBC-SHA.

    choice | TLS-RSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-RSA-WITH-ARIA-128-CBC-SHA256.

    choice | TLS-RSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-RSA-WITH-ARIA-256-CBC-SHA384.

    choice | TLS-DHE-RSA-WITH-DES-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-DES-CBC-SHA.

    choice | TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA.

    choice | TLS-DHE-RSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-AES-128-CBC-SHA.

    choice | TLS-DHE-RSA-WITH-AES-256-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-AES-256-CBC-SHA.

    choice | TLS-DHE-RSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-AES-128-CBC-SHA256.

    choice | TLS-DHE-RSA-WITH-AES-256-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-AES-256-CBC-SHA256.

    choice | TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA.

    choice | TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA.

    choice | TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256.

    choice | TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256.

    choice | TLS-DHE-RSA-WITH-SEED-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-SEED-CBC-SHA.

    choice | TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256.

    choice | TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384.

    choice | TLS-ECDHE-RSA-WITH-RC4-128-SHA | Cipher suite TLS-ECDHE-RSA-WITH-RC4-128-SHA.

    choice | TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA.

    choice | TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA.

    choice | TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA | Cipher suite TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA.

    choice | TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256.

    choice | TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256 | Suite TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256.

    choice | TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256 | Cipher suite TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256.

    choice | TLS-DHE-RSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-DHE-RSA-WITH-AES-128-GCM-SHA256.

    choice | TLS-DHE-RSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-DHE-RSA-WITH-AES-256-GCM-SHA384.

    choice | TLS-DHE-DSS-WITH-AES-128-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-AES-128-CBC-SHA.

    choice | TLS-DHE-DSS-WITH-AES-256-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-AES-256-CBC-SHA.

    choice | TLS-DHE-DSS-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-AES-128-CBC-SHA256.

    choice | TLS-DHE-DSS-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-DHE-DSS-WITH-AES-128-GCM-SHA256.

    choice | TLS-DHE-DSS-WITH-AES-256-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-AES-256-CBC-SHA256.

    choice | TLS-DHE-DSS-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-DHE-DSS-WITH-AES-256-GCM-SHA384.

    choice | TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256.

    choice | TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256.

    choice | TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384 | Cipher suite TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384.

    choice | TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384.

    choice | TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA.

    choice | TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256.

    choice | TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256.

    choice | TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384.

    choice | TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384.

    choice | TLS-RSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-RSA-WITH-AES-128-GCM-SHA256.

    choice | TLS-RSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-RSA-WITH-AES-256-GCM-SHA384.

    choice | TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA | Cipher suite TLS-DSS-RSA-WITH-CAMELLIA-128-CBC-SHA.

    choice | TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA.

    choice | TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256.

    choice | TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256.

    choice | TLS-DHE-DSS-WITH-SEED-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-SEED-CBC-SHA.

    choice | TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256.

    choice | TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384.

    choice | TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256.

    choice | TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384.

    choice | TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC_SHA256.

    choice | TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC_SHA384.

    choice | TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA.

    choice | TLS-DHE-DSS-WITH-DES-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-DES-CBC-SHA.

  • Required: False

  • choices: [‘TLS-RSA-WITH-RC4-128-MD5’, ‘TLS-RSA-WITH-RC4-128-SHA’, ‘TLS-RSA-WITH-DES-CBC-SHA’, ‘TLS-RSA-WITH-3DES-EDE-CBC-SHA’, ‘TLS-RSA-WITH-AES-128-CBC-SHA’, ‘TLS-RSA-WITH-AES-256-CBC-SHA’, ‘TLS-RSA-WITH-AES-128-CBC-SHA256’, ‘TLS-RSA-WITH-AES-256-CBC-SHA256’, ‘TLS-RSA-WITH-CAMELLIA-128-CBC-SHA’, ‘TLS-RSA-WITH-CAMELLIA-256-CBC-SHA’, ‘TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256’, ‘TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256’, ‘TLS-RSA-WITH-SEED-CBC-SHA’, ‘TLS-RSA-WITH-ARIA-128-CBC-SHA256’, ‘TLS-RSA-WITH-ARIA-256-CBC-SHA384’, ‘TLS-DHE-RSA-WITH-DES-CBC-SHA’, ‘TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA’, ‘TLS-DHE-RSA-WITH-AES-128-CBC-SHA’, ‘TLS-DHE-RSA-WITH-AES-256-CBC-SHA’, ‘TLS-DHE-RSA-WITH-AES-128-CBC-SHA256’, ‘TLS-DHE-RSA-WITH-AES-256-CBC-SHA256’, ‘TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA’, ‘TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA’, ‘TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256’, ‘TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256’, ‘TLS-DHE-RSA-WITH-SEED-CBC-SHA’, ‘TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256’, ‘TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384’, ‘TLS-ECDHE-RSA-WITH-RC4-128-SHA’, ‘TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA’, ‘TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA’, ‘TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA’, ‘TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256’, ‘TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256’, ‘TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256’, ‘TLS-DHE-RSA-WITH-AES-128-GCM-SHA256’, ‘TLS-DHE-RSA-WITH-AES-256-GCM-SHA384’, ‘TLS-DHE-DSS-WITH-AES-128-CBC-SHA’, ‘TLS-DHE-DSS-WITH-AES-256-CBC-SHA’, ‘TLS-DHE-DSS-WITH-AES-128-CBC-SHA256’, ‘TLS-DHE-DSS-WITH-AES-128-GCM-SHA256’, ‘TLS-DHE-DSS-WITH-AES-256-CBC-SHA256’, ‘TLS-DHE-DSS-WITH-AES-256-GCM-SHA384’, ‘TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256’, ‘TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256’, ‘TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384’, ‘TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384’, ‘TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA’, ‘TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256’, ‘TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256’, ‘TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384’, ‘TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384’, ‘TLS-RSA-WITH-AES-128-GCM-SHA256’, ‘TLS-RSA-WITH-AES-256-GCM-SHA384’, ‘TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA’, ‘TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA’, ‘TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256’, ‘TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256’, ‘TLS-DHE-DSS-WITH-SEED-CBC-SHA’, ‘TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256’, ‘TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384’, ‘TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256’, ‘TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384’, ‘TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256’, ‘TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384’, ‘TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA’, ‘TLS-DHE-DSS-WITH-DES-CBC-SHA’]

ssl_server_cipher_suites_priority
  • Description: SSL/TLS cipher suites priority.
  • Required: False
ssl_server_cipher_suites_versions
  • Description: SSL/TLS versions that the cipher suite can be used with.

    FLAG Based Options. Specify multiple in list form.

    flag | ssl-3.0 | SSL 3.0.

    flag | tls-1.0 | TLS 1.0.

    flag | tls-1.1 | TLS 1.1.

    flag | tls-1.2 | TLS 1.2.

  • Required: False

  • choices: [‘ssl-3.0’, ‘tls-1.0’, ‘tls-1.1’, ‘tls-1.2’]

ssl_server_max_version
  • Description: Highest SSL/TLS version acceptable from a server. Use the client setting by default.

    choice | ssl-3.0 | SSL 3.0.

    choice | tls-1.0 | TLS 1.0.

    choice | tls-1.1 | TLS 1.1.

    choice | tls-1.2 | TLS 1.2.

    choice | client | Use same value as client configuration.

  • Required: False

  • choices: [‘ssl-3.0’, ‘tls-1.0’, ‘tls-1.1’, ‘tls-1.2’, ‘client’]

ssl_server_min_version
  • Description: Lowest SSL/TLS version acceptable from a server. Use the client setting by default.

    choice | ssl-3.0 | SSL 3.0.

    choice | tls-1.0 | TLS 1.0.

    choice | tls-1.1 | TLS 1.1.

    choice | tls-1.2 | TLS 1.2.

    choice | client | Use same value as client configuration.

  • Required: False

  • choices: [‘ssl-3.0’, ‘tls-1.0’, ‘tls-1.1’, ‘tls-1.2’, ‘client’]

ssl_server_session_state_max
  • Description: Maximum number of FortiGate to Server SSL session states to keep.
  • Required: False
ssl_server_session_state_timeout
  • Description: Number of minutes to keep FortiGate to Server SSL session state.
  • Required: False
ssl_server_session_state_type
  • Description: How to expire SSL sessions for the segment of the SSL connection between the server and the FortiGate.

    choice | disable | Do not keep session states.

    choice | time | Expire session states after this many minutes.

    choice | count | Expire session states when this maximum is reached.

    choice | both | Expire session states based on time or count, whichever occurs first.

  • Required: False

  • choices: [‘disable’, ‘time’, ‘count’, ‘both’]

type
  • Description: Configure a static NAT, load balance, server load balance, DNS translation, or FQDN VIP.

    choice | static-nat | Static NAT.

    choice | load-balance | Load balance.

    choice | server-load-balance | Server load balance.

    choice | dns-translation | DNS translation.

    choice | fqdn | FQDN Translation

  • Required: False

  • choices: [‘static-nat’, ‘load-balance’, ‘server-load-balance’, ‘dns-translation’, ‘fqdn’]

weblogic_server
  • Description: Enable to add an HTTP header to indicate SSL offloading for a WebLogic server.

    choice | disable | Do not add HTTP header indicating SSL offload for WebLogic server.

    choice | enable | Add HTTP header indicating SSL offload for WebLogic server.

  • Required: False

  • choices: [‘disable’, ‘enable’]

websphere_server
  • Description: Enable to add an HTTP header to indicate SSL offloading for a WebSphere server.

    choice | disable | Do not add HTTP header indicating SSL offload for WebSphere server.

    choice | enable | Add HTTP header indicating SSL offload for WebSphere server.

  • Required: False

  • choices: [‘disable’, ‘enable’]

Functions
  • fmgr_firewall_vip_modify
def fmgr_firewall_vip_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/firewall/vip'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/firewall/vip/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


#############
# END METHODS
#############
  • main
def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        websphere_server=dict(required=False, type="str", choices=["disable", "enable"]),
        weblogic_server=dict(required=False, type="str", choices=["disable", "enable"]),
        type=dict(required=False, type="str",
                  choices=["static-nat", "load-balance", "server-load-balance", "dns-translation", "fqdn"]),
        ssl_server_session_state_type=dict(required=False, type="str", choices=["disable", "time", "count", "both"]),
        ssl_server_session_state_timeout=dict(required=False, type="int"),
        ssl_server_session_state_max=dict(required=False, type="int"),
        ssl_server_min_version=dict(required=False, type="str",
                                    choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"]),
        ssl_server_max_version=dict(required=False, type="str",
                                    choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"]),
        ssl_server_algorithm=dict(required=False, type="str", choices=["high", "low", "medium", "custom", "client"]),
        ssl_send_empty_frags=dict(required=False, type="str", choices=["disable", "enable"]),
        ssl_pfs=dict(required=False, type="str", choices=["require", "deny", "allow"]),
        ssl_mode=dict(required=False, type="str", choices=["half", "full"]),
        ssl_min_version=dict(required=False, type="str", choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
        ssl_max_version=dict(required=False, type="str", choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
        ssl_http_match_host=dict(required=False, type="str", choices=["disable", "enable"]),
        ssl_http_location_conversion=dict(required=False, type="str", choices=["disable", "enable"]),
        ssl_hsts_include_subdomains=dict(required=False, type="str", choices=["disable", "enable"]),
        ssl_hsts_age=dict(required=False, type="int"),
        ssl_hsts=dict(required=False, type="str", choices=["disable", "enable"]),
        ssl_hpkp_report_uri=dict(required=False, type="str"),
        ssl_hpkp_primary=dict(required=False, type="str"),
        ssl_hpkp_include_subdomains=dict(required=False, type="str", choices=["disable", "enable"]),
        ssl_hpkp_backup=dict(required=False, type="str"),
        ssl_hpkp_age=dict(required=False, type="int"),
        ssl_hpkp=dict(required=False, type="str", choices=["disable", "enable", "report-only"]),
        ssl_dh_bits=dict(required=False, type="str", choices=["768", "1024", "1536", "2048", "3072", "4096"]),
        ssl_client_session_state_type=dict(required=False, type="str", choices=["disable", "time", "count", "both"]),
        ssl_client_session_state_timeout=dict(required=False, type="int"),
        ssl_client_session_state_max=dict(required=False, type="int"),
        ssl_client_renegotiation=dict(required=False, type="str", choices=["deny", "allow", "secure"]),
        ssl_client_fallback=dict(required=False, type="str", choices=["disable", "enable"]),
        ssl_certificate=dict(required=False, type="str"),
        ssl_algorithm=dict(required=False, type="str", choices=["high", "medium", "low", "custom"]),
        srcintf_filter=dict(required=False, type="str"),
        src_filter=dict(required=False, type="str"),
        service=dict(required=False, type="str"),
        server_type=dict(required=False, type="str",
                         choices=["http", "https", "ssl", "tcp", "udp", "ip", "imaps", "pop3s", "smtps"]),
        protocol=dict(required=False, type="str", choices=["tcp", "udp", "sctp", "icmp"]),
        portmapping_type=dict(required=False, type="str", choices=["1-to-1", "m-to-n"]),
        portforward=dict(required=False, type="str", choices=["disable", "enable"]),
        persistence=dict(required=False, type="str", choices=["none", "http-cookie", "ssl-session-id"]),
        outlook_web_access=dict(required=False, type="str", choices=["disable", "enable"]),
        nat_source_vip=dict(required=False, type="str", choices=["disable", "enable"]),
        name=dict(required=False, type="str"),
        monitor=dict(required=False, type="str"),
        max_embryonic_connections=dict(required=False, type="int"),
        mappedport=dict(required=False, type="str"),
        mappedip=dict(required=False, type="str"),
        mapped_addr=dict(required=False, type="str"),
        ldb_method=dict(required=False, type="str",
                        choices=["static", "round-robin", "weighted", "least-session", "least-rtt", "first-alive",
                                 "http-host"]),
        https_cookie_secure=dict(required=False, type="str", choices=["disable", "enable"]),
        http_multiplex=dict(required=False, type="str", choices=["disable", "enable"]),
        http_ip_header_name=dict(required=False, type="str"),
        http_ip_header=dict(required=False, type="str", choices=["disable", "enable"]),
        http_cookie_share=dict(required=False, type="str", choices=["disable", "same-ip"]),
        http_cookie_path=dict(required=False, type="str"),
        http_cookie_generation=dict(required=False, type="int"),
        http_cookie_domain_from_host=dict(required=False, type="str", choices=["disable", "enable"]),
        http_cookie_domain=dict(required=False, type="str"),
        http_cookie_age=dict(required=False, type="int"),
        gratuitous_arp_interval=dict(required=False, type="int"),
        extport=dict(required=False, type="str"),
        extip=dict(required=False, type="str"),
        extintf=dict(required=False, type="str"),
        extaddr=dict(required=False, type="str"),
        dns_mapping_ttl=dict(required=False, type="int"),
        comment=dict(required=False, type="str"),
        color=dict(required=False, type="int"),
        arp_reply=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping=dict(required=False, type="list"),
        dynamic_mapping_arp_reply=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_color=dict(required=False, type="int"),
        dynamic_mapping_comment=dict(required=False, type="str"),
        dynamic_mapping_dns_mapping_ttl=dict(required=False, type="int"),
        dynamic_mapping_extaddr=dict(required=False, type="str"),
        dynamic_mapping_extintf=dict(required=False, type="str"),
        dynamic_mapping_extip=dict(required=False, type="str"),
        dynamic_mapping_extport=dict(required=False, type="str"),
        dynamic_mapping_gratuitous_arp_interval=dict(required=False, type="int"),
        dynamic_mapping_http_cookie_age=dict(required=False, type="int"),
        dynamic_mapping_http_cookie_domain=dict(required=False, type="str"),
        dynamic_mapping_http_cookie_domain_from_host=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_http_cookie_generation=dict(required=False, type="int"),
        dynamic_mapping_http_cookie_path=dict(required=False, type="str"),
        dynamic_mapping_http_cookie_share=dict(required=False, type="str", choices=["disable", "same-ip"]),
        dynamic_mapping_http_ip_header=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_http_ip_header_name=dict(required=False, type="str"),
        dynamic_mapping_http_multiplex=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_https_cookie_secure=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_ldb_method=dict(required=False, type="str", choices=["static",
                                                                             "round-robin",
                                                                             "weighted",
                                                                             "least-session",
                                                                             "least-rtt",
                                                                             "first-alive",
                                                                             "http-host"]),
        dynamic_mapping_mapped_addr=dict(required=False, type="str"),
        dynamic_mapping_mappedip=dict(required=False, type="str"),
        dynamic_mapping_mappedport=dict(required=False, type="str"),
        dynamic_mapping_max_embryonic_connections=dict(required=False, type="int"),
        dynamic_mapping_monitor=dict(required=False, type="str"),
        dynamic_mapping_nat_source_vip=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_outlook_web_access=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_persistence=dict(required=False, type="str", choices=["none", "http-cookie", "ssl-session-id"]),
        dynamic_mapping_portforward=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_portmapping_type=dict(required=False, type="str", choices=["1-to-1", "m-to-n"]),
        dynamic_mapping_protocol=dict(required=False, type="str", choices=["tcp", "udp", "sctp", "icmp"]),
        dynamic_mapping_server_type=dict(required=False, type="str",
                                         choices=["http", "https", "ssl", "tcp", "udp", "ip", "imaps", "pop3s",
                                                  "smtps"]),
        dynamic_mapping_service=dict(required=False, type="str"),
        dynamic_mapping_src_filter=dict(required=False, type="str"),
        dynamic_mapping_srcintf_filter=dict(required=False, type="str"),
        dynamic_mapping_ssl_algorithm=dict(required=False, type="str", choices=["high", "medium", "low", "custom"]),
        dynamic_mapping_ssl_certificate=dict(required=False, type="str"),
        dynamic_mapping_ssl_client_fallback=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_ssl_client_renegotiation=dict(required=False, type="str", choices=["deny", "allow", "secure"]),
        dynamic_mapping_ssl_client_session_state_max=dict(required=False, type="int"),
        dynamic_mapping_ssl_client_session_state_timeout=dict(required=False, type="int"),
        dynamic_mapping_ssl_client_session_state_type=dict(required=False, type="str",
                                                           choices=["disable", "time", "count", "both"]),
        dynamic_mapping_ssl_dh_bits=dict(required=False, type="str",
                                         choices=["768", "1024", "1536", "2048", "3072", "4096"]),
        dynamic_mapping_ssl_hpkp=dict(required=False, type="str", choices=["disable", "enable", "report-only"]),
        dynamic_mapping_ssl_hpkp_age=dict(required=False, type="int"),
        dynamic_mapping_ssl_hpkp_backup=dict(required=False, type="str"),
        dynamic_mapping_ssl_hpkp_include_subdomains=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_ssl_hpkp_primary=dict(required=False, type="str"),
        dynamic_mapping_ssl_hpkp_report_uri=dict(required=False, type="str"),
        dynamic_mapping_ssl_hsts=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_ssl_hsts_age=dict(required=False, type="int"),
        dynamic_mapping_ssl_hsts_include_subdomains=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_ssl_http_location_conversion=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_ssl_http_match_host=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_ssl_max_version=dict(required=False, type="str",
                                             choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
        dynamic_mapping_ssl_min_version=dict(required=False, type="str",
                                             choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
        dynamic_mapping_ssl_mode=dict(required=False, type="str", choices=["half", "full"]),
        dynamic_mapping_ssl_pfs=dict(required=False, type="str", choices=["require", "deny", "allow"]),
        dynamic_mapping_ssl_send_empty_frags=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_ssl_server_algorithm=dict(required=False, type="str",
                                                  choices=["high", "low", "medium", "custom", "client"]),
        dynamic_mapping_ssl_server_max_version=dict(required=False, type="str",
                                                    choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"]),
        dynamic_mapping_ssl_server_min_version=dict(required=False, type="str",
                                                    choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"]),
        dynamic_mapping_ssl_server_session_state_max=dict(required=False, type="int"),
        dynamic_mapping_ssl_server_session_state_timeout=dict(required=False, type="int"),
        dynamic_mapping_ssl_server_session_state_type=dict(required=False, type="str",
                                                           choices=["disable", "time", "count", "both"]),
        dynamic_mapping_type=dict(required=False, type="str",
                                  choices=["static-nat", "load-balance", "server-load-balance", "dns-translation",
                                           "fqdn"]),
        dynamic_mapping_weblogic_server=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_websphere_server=dict(required=False, type="str", choices=["disable", "enable"]),

        dynamic_mapping_realservers_client_ip=dict(required=False, type="str"),
        dynamic_mapping_realservers_healthcheck=dict(required=False, type="str", choices=["disable", "enable", "vip"]),
        dynamic_mapping_realservers_holddown_interval=dict(required=False, type="int"),
        dynamic_mapping_realservers_http_host=dict(required=False, type="str"),
        dynamic_mapping_realservers_ip=dict(required=False, type="str"),
        dynamic_mapping_realservers_max_connections=dict(required=False, type="int"),
        dynamic_mapping_realservers_monitor=dict(required=False, type="str"),
        dynamic_mapping_realservers_port=dict(required=False, type="int"),
        dynamic_mapping_realservers_seq=dict(required=False, type="str"),
        dynamic_mapping_realservers_status=dict(required=False, type="str", choices=["active", "standby", "disable"]),
        dynamic_mapping_realservers_weight=dict(required=False, type="int"),

        dynamic_mapping_ssl_cipher_suites_cipher=dict(required=False,
                                                      type="str",
                                                      choices=["TLS-RSA-WITH-RC4-128-MD5",
                                                               "TLS-RSA-WITH-RC4-128-SHA",
                                                               "TLS-RSA-WITH-DES-CBC-SHA",
                                                               "TLS-RSA-WITH-3DES-EDE-CBC-SHA",
                                                               "TLS-RSA-WITH-AES-128-CBC-SHA",
                                                               "TLS-RSA-WITH-AES-256-CBC-SHA",
                                                               "TLS-RSA-WITH-AES-128-CBC-SHA256",
                                                               "TLS-RSA-WITH-AES-256-CBC-SHA256",
                                                               "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA",
                                                               "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA",
                                                               "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256",
                                                               "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256",
                                                               "TLS-RSA-WITH-SEED-CBC-SHA",
                                                               "TLS-RSA-WITH-ARIA-128-CBC-SHA256",
                                                               "TLS-RSA-WITH-ARIA-256-CBC-SHA384",
                                                               "TLS-DHE-RSA-WITH-DES-CBC-SHA",
                                                               "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA",
                                                               "TLS-DHE-RSA-WITH-AES-128-CBC-SHA",
                                                               "TLS-DHE-RSA-WITH-AES-256-CBC-SHA",
                                                               "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256",
                                                               "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256",
                                                               "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA",
                                                               "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA",
                                                               "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256",
                                                               "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256",
                                                               "TLS-DHE-RSA-WITH-SEED-CBC-SHA",
                                                               "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256",
                                                               "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384",
                                                               "TLS-ECDHE-RSA-WITH-RC4-128-SHA",
                                                               "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA",
                                                               "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA",
                                                               "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA",
                                                               "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
                                                               "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256",
                                                               "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
                                                               "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256",
                                                               "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384",
                                                               "TLS-DHE-DSS-WITH-AES-128-CBC-SHA",
                                                               "TLS-DHE-DSS-WITH-AES-256-CBC-SHA",
                                                               "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256",
                                                               "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256",
                                                               "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256",
                                                               "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384",
                                                               "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256",
                                                               "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256",
                                                               "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384",
                                                               "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384",
                                                               "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA",
                                                               "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256",
                                                               "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256",
                                                               "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384",
                                                               "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384",
                                                               "TLS-RSA-WITH-AES-128-GCM-SHA256",
                                                               "TLS-RSA-WITH-AES-256-GCM-SHA384",
                                                               "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA",
                                                               "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA",
                                                               "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256",
                                                               "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256",
                                                               "TLS-DHE-DSS-WITH-SEED-CBC-SHA",
                                                               "TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256",
                                                               "TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384",
                                                               "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256",
                                                               "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384",
                                                               "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256",
                                                               "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384",
                                                               "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA",
                                                               "TLS-DHE-DSS-WITH-DES-CBC-SHA"]),
        dynamic_mapping_ssl_cipher_suites_versions=dict(required=False, type="str",
                                                        choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
        realservers=dict(required=False, type="list"),
        realservers_client_ip=dict(required=False, type="str"),
        realservers_healthcheck=dict(required=False, type="str", choices=["disable", "enable", "vip"]),
        realservers_holddown_interval=dict(required=False, type="int"),
        realservers_http_host=dict(required=False, type="str"),
        realservers_ip=dict(required=False, type="str"),
        realservers_max_connections=dict(required=False, type="int"),
        realservers_monitor=dict(required=False, type="str"),
        realservers_port=dict(required=False, type="int"),
        realservers_seq=dict(required=False, type="str"),
        realservers_status=dict(required=False, type="str", choices=["active", "standby", "disable"]),
        realservers_weight=dict(required=False, type="int"),
        ssl_cipher_suites=dict(required=False, type="list"),
        ssl_cipher_suites_cipher=dict(required=False,
                                      type="str",
                                      choices=["TLS-RSA-WITH-RC4-128-MD5",
                                               "TLS-RSA-WITH-RC4-128-SHA",
                                               "TLS-RSA-WITH-DES-CBC-SHA",
                                               "TLS-RSA-WITH-3DES-EDE-CBC-SHA",
                                               "TLS-RSA-WITH-AES-128-CBC-SHA",
                                               "TLS-RSA-WITH-AES-256-CBC-SHA",
                                               "TLS-RSA-WITH-AES-128-CBC-SHA256",
                                               "TLS-RSA-WITH-AES-256-CBC-SHA256",
                                               "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA",
                                               "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA",
                                               "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256",
                                               "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256",
                                               "TLS-RSA-WITH-SEED-CBC-SHA",
                                               "TLS-RSA-WITH-ARIA-128-CBC-SHA256",
                                               "TLS-RSA-WITH-ARIA-256-CBC-SHA384",
                                               "TLS-DHE-RSA-WITH-DES-CBC-SHA",
                                               "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA",
                                               "TLS-DHE-RSA-WITH-AES-128-CBC-SHA",
                                               "TLS-DHE-RSA-WITH-AES-256-CBC-SHA",
                                               "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256",
                                               "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256",
                                               "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA",
                                               "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA",
                                               "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256",
                                               "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256",
                                               "TLS-DHE-RSA-WITH-SEED-CBC-SHA",
                                               "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256",
                                               "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384",
                                               "TLS-ECDHE-RSA-WITH-RC4-128-SHA",
                                               "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA",
                                               "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA",
                                               "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA",
                                               "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
                                               "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256",
                                               "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
                                               "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256",
                                               "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384",
                                               "TLS-DHE-DSS-WITH-AES-128-CBC-SHA",
                                               "TLS-DHE-DSS-WITH-AES-256-CBC-SHA",
                                               "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256",
                                               "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256",
                                               "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256",
                                               "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384",
                                               "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256",
                                               "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256",
                                               "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384",
                                               "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384",
                                               "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA",
                                               "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256",
                                               "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256",
                                               "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384",
                                               "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384",
                                               "TLS-RSA-WITH-AES-128-GCM-SHA256",
                                               "TLS-RSA-WITH-AES-256-GCM-SHA384",
                                               "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA",
                                               "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA",
                                               "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256",
                                               "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256",
                                               "TLS-DHE-DSS-WITH-SEED-CBC-SHA",
                                               "TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256",
                                               "TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384",
                                               "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256",
                                               "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384",
                                               "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256",
                                               "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384",
                                               "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA",
                                               "TLS-DHE-DSS-WITH-DES-CBC-SHA"]),
        ssl_cipher_suites_versions=dict(required=False, type="str",
                                        choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
        ssl_server_cipher_suites=dict(required=False, type="list"),
        ssl_server_cipher_suites_cipher=dict(required=False,
                                             type="str",
                                             choices=["TLS-RSA-WITH-RC4-128-MD5",
                                                      "TLS-RSA-WITH-RC4-128-SHA",
                                                      "TLS-RSA-WITH-DES-CBC-SHA",
                                                      "TLS-RSA-WITH-3DES-EDE-CBC-SHA",
                                                      "TLS-RSA-WITH-AES-128-CBC-SHA",
                                                      "TLS-RSA-WITH-AES-256-CBC-SHA",
                                                      "TLS-RSA-WITH-AES-128-CBC-SHA256",
                                                      "TLS-RSA-WITH-AES-256-CBC-SHA256",
                                                      "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA",
                                                      "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA",
                                                      "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256",
                                                      "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256",
                                                      "TLS-RSA-WITH-SEED-CBC-SHA",
                                                      "TLS-RSA-WITH-ARIA-128-CBC-SHA256",
                                                      "TLS-RSA-WITH-ARIA-256-CBC-SHA384",
                                                      "TLS-DHE-RSA-WITH-DES-CBC-SHA",
                                                      "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA",
                                                      "TLS-DHE-RSA-WITH-AES-128-CBC-SHA",
                                                      "TLS-DHE-RSA-WITH-AES-256-CBC-SHA",
                                                      "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256",
                                                      "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256",
                                                      "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA",
                                                      "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA",
                                                      "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256",
                                                      "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256",
                                                      "TLS-DHE-RSA-WITH-SEED-CBC-SHA",
                                                      "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256",
                                                      "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384",
                                                      "TLS-ECDHE-RSA-WITH-RC4-128-SHA",
                                                      "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA",
                                                      "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA",
                                                      "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA",
                                                      "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
                                                      "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256",
                                                      "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
                                                      "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256",
                                                      "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384",
                                                      "TLS-DHE-DSS-WITH-AES-128-CBC-SHA",
                                                      "TLS-DHE-DSS-WITH-AES-256-CBC-SHA",
                                                      "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256",
                                                      "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256",
                                                      "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256",
                                                      "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384",
                                                      "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256",
                                                      "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256",
                                                      "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384",
                                                      "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384",
                                                      "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA",
                                                      "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256",
                                                      "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256",
                                                      "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384",
                                                      "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384",
                                                      "TLS-RSA-WITH-AES-128-GCM-SHA256",
                                                      "TLS-RSA-WITH-AES-256-GCM-SHA384",
                                                      "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA",
                                                      "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA",
                                                      "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256",
                                                      "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256",
                                                      "TLS-DHE-DSS-WITH-SEED-CBC-SHA",
                                                      "TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256",
                                                      "TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384",
                                                      "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256",
                                                      "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384",
                                                      "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256",
                                                      "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384",
                                                      "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA",
                                                      "TLS-DHE-DSS-WITH-DES-CBC-SHA"]),
        ssl_server_cipher_suites_priority=dict(required=False, type="str"),
        ssl_server_cipher_suites_versions=dict(required=False, type="str",
                                               choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "websphere-server": module.params["websphere_server"],
        "weblogic-server": module.params["weblogic_server"],
        "type": module.params["type"],
        "ssl-server-session-state-type": module.params["ssl_server_session_state_type"],
        "ssl-server-session-state-timeout": module.params["ssl_server_session_state_timeout"],
        "ssl-server-session-state-max": module.params["ssl_server_session_state_max"],
        "ssl-server-min-version": module.params["ssl_server_min_version"],
        "ssl-server-max-version": module.params["ssl_server_max_version"],
        "ssl-server-algorithm": module.params["ssl_server_algorithm"],
        "ssl-send-empty-frags": module.params["ssl_send_empty_frags"],
        "ssl-pfs": module.params["ssl_pfs"],
        "ssl-mode": module.params["ssl_mode"],
        "ssl-min-version": module.params["ssl_min_version"],
        "ssl-max-version": module.params["ssl_max_version"],
        "ssl-http-match-host": module.params["ssl_http_match_host"],
        "ssl-http-location-conversion": module.params["ssl_http_location_conversion"],
        "ssl-hsts-include-subdomains": module.params["ssl_hsts_include_subdomains"],
        "ssl-hsts-age": module.params["ssl_hsts_age"],
        "ssl-hsts": module.params["ssl_hsts"],
        "ssl-hpkp-report-uri": module.params["ssl_hpkp_report_uri"],
        "ssl-hpkp-primary": module.params["ssl_hpkp_primary"],
        "ssl-hpkp-include-subdomains": module.params["ssl_hpkp_include_subdomains"],
        "ssl-hpkp-backup": module.params["ssl_hpkp_backup"],
        "ssl-hpkp-age": module.params["ssl_hpkp_age"],
        "ssl-hpkp": module.params["ssl_hpkp"],
        "ssl-dh-bits": module.params["ssl_dh_bits"],
        "ssl-client-session-state-type": module.params["ssl_client_session_state_type"],
        "ssl-client-session-state-timeout": module.params["ssl_client_session_state_timeout"],
        "ssl-client-session-state-max": module.params["ssl_client_session_state_max"],
        "ssl-client-renegotiation": module.params["ssl_client_renegotiation"],
        "ssl-client-fallback": module.params["ssl_client_fallback"],
        "ssl-certificate": module.params["ssl_certificate"],
        "ssl-algorithm": module.params["ssl_algorithm"],
        "srcintf-filter": module.params["srcintf_filter"],
        "src-filter": module.params["src_filter"],
        "service": module.params["service"],
        "server-type": module.params["server_type"],
        "protocol": module.params["protocol"],
        "portmapping-type": module.params["portmapping_type"],
        "portforward": module.params["portforward"],
        "persistence": module.params["persistence"],
        "outlook-web-access": module.params["outlook_web_access"],
        "nat-source-vip": module.params["nat_source_vip"],
        "name": module.params["name"],
        "monitor": module.params["monitor"],
        "max-embryonic-connections": module.params["max_embryonic_connections"],
        "mappedport": module.params["mappedport"],
        "mappedip": module.params["mappedip"],
        "mapped-addr": module.params["mapped_addr"],
        "ldb-method": module.params["ldb_method"],
        "https-cookie-secure": module.params["https_cookie_secure"],
        "http-multiplex": module.params["http_multiplex"],
        "http-ip-header-name": module.params["http_ip_header_name"],
        "http-ip-header": module.params["http_ip_header"],
        "http-cookie-share": module.params["http_cookie_share"],
        "http-cookie-path": module.params["http_cookie_path"],
        "http-cookie-generation": module.params["http_cookie_generation"],
        "http-cookie-domain-from-host": module.params["http_cookie_domain_from_host"],
        "http-cookie-domain": module.params["http_cookie_domain"],
        "http-cookie-age": module.params["http_cookie_age"],
        "gratuitous-arp-interval": module.params["gratuitous_arp_interval"],
        "extport": module.params["extport"],
        "extip": module.params["extip"],
        "extintf": module.params["extintf"],
        "extaddr": module.params["extaddr"],
        "dns-mapping-ttl": module.params["dns_mapping_ttl"],
        "comment": module.params["comment"],
        "color": module.params["color"],
        "arp-reply": module.params["arp_reply"],
        "dynamic_mapping": {
            "arp-reply": module.params["dynamic_mapping_arp_reply"],
            "color": module.params["dynamic_mapping_color"],
            "comment": module.params["dynamic_mapping_comment"],
            "dns-mapping-ttl": module.params["dynamic_mapping_dns_mapping_ttl"],
            "extaddr": module.params["dynamic_mapping_extaddr"],
            "extintf": module.params["dynamic_mapping_extintf"],
            "extip": module.params["dynamic_mapping_extip"],
            "extport": module.params["dynamic_mapping_extport"],
            "gratuitous-arp-interval": module.params["dynamic_mapping_gratuitous_arp_interval"],
            "http-cookie-age": module.params["dynamic_mapping_http_cookie_age"],
            "http-cookie-domain": module.params["dynamic_mapping_http_cookie_domain"],
            "http-cookie-domain-from-host": module.params["dynamic_mapping_http_cookie_domain_from_host"],
            "http-cookie-generation": module.params["dynamic_mapping_http_cookie_generation"],
            "http-cookie-path": module.params["dynamic_mapping_http_cookie_path"],
            "http-cookie-share": module.params["dynamic_mapping_http_cookie_share"],
            "http-ip-header": module.params["dynamic_mapping_http_ip_header"],
            "http-ip-header-name": module.params["dynamic_mapping_http_ip_header_name"],
            "http-multiplex": module.params["dynamic_mapping_http_multiplex"],
            "https-cookie-secure": module.params["dynamic_mapping_https_cookie_secure"],
            "ldb-method": module.params["dynamic_mapping_ldb_method"],
            "mapped-addr": module.params["dynamic_mapping_mapped_addr"],
            "mappedip": module.params["dynamic_mapping_mappedip"],
            "mappedport": module.params["dynamic_mapping_mappedport"],
            "max-embryonic-connections": module.params["dynamic_mapping_max_embryonic_connections"],
            "monitor": module.params["dynamic_mapping_monitor"],
            "nat-source-vip": module.params["dynamic_mapping_nat_source_vip"],
            "outlook-web-access": module.params["dynamic_mapping_outlook_web_access"],
            "persistence": module.params["dynamic_mapping_persistence"],
            "portforward": module.params["dynamic_mapping_portforward"],
            "portmapping-type": module.params["dynamic_mapping_portmapping_type"],
            "protocol": module.params["dynamic_mapping_protocol"],
            "server-type": module.params["dynamic_mapping_server_type"],
            "service": module.params["dynamic_mapping_service"],
            "src-filter": module.params["dynamic_mapping_src_filter"],
            "srcintf-filter": module.params["dynamic_mapping_srcintf_filter"],
            "ssl-algorithm": module.params["dynamic_mapping_ssl_algorithm"],
            "ssl-certificate": module.params["dynamic_mapping_ssl_certificate"],
            "ssl-client-fallback": module.params["dynamic_mapping_ssl_client_fallback"],
            "ssl-client-renegotiation": module.params["dynamic_mapping_ssl_client_renegotiation"],
            "ssl-client-session-state-max": module.params["dynamic_mapping_ssl_client_session_state_max"],
            "ssl-client-session-state-timeout": module.params["dynamic_mapping_ssl_client_session_state_timeout"],
            "ssl-client-session-state-type": module.params["dynamic_mapping_ssl_client_session_state_type"],
            "ssl-dh-bits": module.params["dynamic_mapping_ssl_dh_bits"],
            "ssl-hpkp": module.params["dynamic_mapping_ssl_hpkp"],
            "ssl-hpkp-age": module.params["dynamic_mapping_ssl_hpkp_age"],
            "ssl-hpkp-backup": module.params["dynamic_mapping_ssl_hpkp_backup"],
            "ssl-hpkp-include-subdomains": module.params["dynamic_mapping_ssl_hpkp_include_subdomains"],
            "ssl-hpkp-primary": module.params["dynamic_mapping_ssl_hpkp_primary"],
            "ssl-hpkp-report-uri": module.params["dynamic_mapping_ssl_hpkp_report_uri"],
            "ssl-hsts": module.params["dynamic_mapping_ssl_hsts"],
            "ssl-hsts-age": module.params["dynamic_mapping_ssl_hsts_age"],
            "ssl-hsts-include-subdomains": module.params["dynamic_mapping_ssl_hsts_include_subdomains"],
            "ssl-http-location-conversion": module.params["dynamic_mapping_ssl_http_location_conversion"],
            "ssl-http-match-host": module.params["dynamic_mapping_ssl_http_match_host"],
            "ssl-max-version": module.params["dynamic_mapping_ssl_max_version"],
            "ssl-min-version": module.params["dynamic_mapping_ssl_min_version"],
            "ssl-mode": module.params["dynamic_mapping_ssl_mode"],
            "ssl-pfs": module.params["dynamic_mapping_ssl_pfs"],
            "ssl-send-empty-frags": module.params["dynamic_mapping_ssl_send_empty_frags"],
            "ssl-server-algorithm": module.params["dynamic_mapping_ssl_server_algorithm"],
            "ssl-server-max-version": module.params["dynamic_mapping_ssl_server_max_version"],
            "ssl-server-min-version": module.params["dynamic_mapping_ssl_server_min_version"],
            "ssl-server-session-state-max": module.params["dynamic_mapping_ssl_server_session_state_max"],
            "ssl-server-session-state-timeout": module.params["dynamic_mapping_ssl_server_session_state_timeout"],
            "ssl-server-session-state-type": module.params["dynamic_mapping_ssl_server_session_state_type"],
            "type": module.params["dynamic_mapping_type"],
            "weblogic-server": module.params["dynamic_mapping_weblogic_server"],
            "websphere-server": module.params["dynamic_mapping_websphere_server"],
            "realservers": {
                "client-ip": module.params["dynamic_mapping_realservers_client_ip"],
                "healthcheck": module.params["dynamic_mapping_realservers_healthcheck"],
                "holddown-interval": module.params["dynamic_mapping_realservers_holddown_interval"],
                "http-host": module.params["dynamic_mapping_realservers_http_host"],
                "ip": module.params["dynamic_mapping_realservers_ip"],
                "max-connections": module.params["dynamic_mapping_realservers_max_connections"],
                "monitor": module.params["dynamic_mapping_realservers_monitor"],
                "port": module.params["dynamic_mapping_realservers_port"],
                "seq": module.params["dynamic_mapping_realservers_seq"],
                "status": module.params["dynamic_mapping_realservers_status"],
                "weight": module.params["dynamic_mapping_realservers_weight"],
            },
            "ssl-cipher-suites": {
                "cipher": module.params["dynamic_mapping_ssl_cipher_suites_cipher"],
                "versions": module.params["dynamic_mapping_ssl_cipher_suites_versions"],
            },
        },
        "realservers": {
            "client-ip": module.params["realservers_client_ip"],
            "healthcheck": module.params["realservers_healthcheck"],
            "holddown-interval": module.params["realservers_holddown_interval"],
            "http-host": module.params["realservers_http_host"],
            "ip": module.params["realservers_ip"],
            "max-connections": module.params["realservers_max_connections"],
            "monitor": module.params["realservers_monitor"],
            "port": module.params["realservers_port"],
            "seq": module.params["realservers_seq"],
            "status": module.params["realservers_status"],
            "weight": module.params["realservers_weight"],
        },
        "ssl-cipher-suites": {
            "cipher": module.params["ssl_cipher_suites_cipher"],
            "versions": module.params["ssl_cipher_suites_versions"],
        },
        "ssl-server-cipher-suites": {
            "cipher": module.params["ssl_server_cipher_suites_cipher"],
            "priority": module.params["ssl_server_cipher_suites_priority"],
            "versions": module.params["ssl_server_cipher_suites_versions"],
        }
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['dynamic_mapping', 'realservers', 'ssl-cipher-suites', 'ssl-server-cipher-suites']
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)

    results = DEFAULT_RESULT_OBJ
    try:
        results = fmgr_firewall_vip_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function

__metaclass__ = type

ANSIBLE_METADATA = {'status': ['preview'],
                    'supported_by': 'community',
                    'metadata_version': '1.1'}

DOCUMENTATION = '''
---
module: fmgr_fwobj_vip
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author:
    - Luke Weighall (@lweighall)
    - Andrew Welsh (@Ghilli3)
    - Jim Huber (@p4r4n0y1ng)
short_description: Manages Virtual IPs objects in FortiManager
description:
  -  Manages Virtual IP objects in FortiManager for IPv4

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: false
    default: root

  mode:
    description:
      - Sets one of three modes for managing the object.
      - Allows use of soft-adds instead of overwriting existing values
    choices: ['add', 'set', 'delete', 'update']
    required: false
    default: add

  websphere_server:
    description:
      - Enable to add an HTTP header to indicate SSL offloading for a WebSphere server.
      - choice | disable | Do not add HTTP header indicating SSL offload for WebSphere server.
      - choice | enable | Add HTTP header indicating SSL offload for WebSphere server.
    required: false
    choices: ["disable", "enable"]

  weblogic_server:
    description:
      - Enable to add an HTTP header to indicate SSL offloading for a WebLogic server.
      - choice | disable | Do not add HTTP header indicating SSL offload for WebLogic server.
      - choice | enable | Add HTTP header indicating SSL offload for WebLogic server.
    required: false
    choices: ["disable", "enable"]

  type:
    description:
      - Configure a static NAT, load balance, server load balance, DNS translation, or FQDN VIP.
      - choice | static-nat | Static NAT.
      - choice | load-balance | Load balance.
      - choice | server-load-balance | Server load balance.
      - choice | dns-translation | DNS translation.
      - choice | fqdn | FQDN Translation
    required: false
    choices: ["static-nat", "load-balance", "server-load-balance", "dns-translation", "fqdn"]

  ssl_server_session_state_type:
    description:
      - How to expire SSL sessions for the segment of the SSL connection between the server and the FortiGate.
      - choice | disable | Do not keep session states.
      - choice | time | Expire session states after this many minutes.
      - choice | count | Expire session states when this maximum is reached.
      - choice | both | Expire session states based on time or count, whichever occurs first.
    required: false
    choices: ["disable", "time", "count", "both"]

  ssl_server_session_state_timeout:
    description:
      - Number of minutes to keep FortiGate to Server SSL session state.
    required: false

  ssl_server_session_state_max:
    description:
      - Maximum number of FortiGate to Server SSL session states to keep.
    required: false

  ssl_server_min_version:
    description:
      - Lowest SSL/TLS version acceptable from a server. Use the client setting by default.
      - choice | ssl-3.0 | SSL 3.0.
      - choice | tls-1.0 | TLS 1.0.
      - choice | tls-1.1 | TLS 1.1.
      - choice | tls-1.2 | TLS 1.2.
      - choice | client | Use same value as client configuration.
    required: false
    choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"]

  ssl_server_max_version:
    description:
      - Highest SSL/TLS version acceptable from a server. Use the client setting by default.
      - choice | ssl-3.0 | SSL 3.0.
      - choice | tls-1.0 | TLS 1.0.
      - choice | tls-1.1 | TLS 1.1.
      - choice | tls-1.2 | TLS 1.2.
      - choice | client | Use same value as client configuration.
    required: false
    choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"]

  ssl_server_algorithm:
    description:
      - Permitted encryption algorithms for the server side of SSL full mode sessions according to encryption strength
      - choice | high | High encryption. Allow only AES and ChaCha.
      - choice | low | Low encryption. Allow AES, ChaCha, 3DES, RC4, and DES.
      - choice | medium | Medium encryption. Allow AES, ChaCha, 3DES, and RC4.
      - choice | custom | Custom encryption. Use ssl-server-cipher-suites to select the cipher suites that are allowed.
      - choice | client | Use the same encryption algorithms for both client and server sessions.
    required: false
    choices: ["high", "low", "medium", "custom", "client"]

  ssl_send_empty_frags:
    description:
      - Enable/disable sending empty fragments to avoid CBC IV attacks (SSL 3.0 &amp; TLS 1.0 only).
      - choice | disable | Do not send empty fragments.
      - choice | enable | Send empty fragments.
    required: false
    choices: ["disable", "enable"]

  ssl_pfs:
    description:
      - Select the cipher suites that can be used for SSL perfect forward secrecy (PFS).
      - choice | require | Allow only Diffie-Hellman cipher-suites, so PFS is applied.
      - choice | deny | Allow only non-Diffie-Hellman cipher-suites, so PFS is not applied.
      - choice | allow | Allow use of any cipher suite so PFS may or may not be used depending on the cipher suite
    required: false
    choices: ["require", "deny", "allow"]

  ssl_mode:
    description:
      - Apply SSL offloading mode
      - choice | half | Client to FortiGate SSL.
      - choice | full | Client to FortiGate and FortiGate to Server SSL.
    required: false
    choices: ["half", "full"]

  ssl_min_version:
    description:
      - Lowest SSL/TLS version acceptable from a client.
      - choice | ssl-3.0 | SSL 3.0.
      - choice | tls-1.0 | TLS 1.0.
      - choice | tls-1.1 | TLS 1.1.
      - choice | tls-1.2 | TLS 1.2.
    required: false
    choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]

  ssl_max_version:
    description:
      - Highest SSL/TLS version acceptable from a client.
      - choice | ssl-3.0 | SSL 3.0.
      - choice | tls-1.0 | TLS 1.0.
      - choice | tls-1.1 | TLS 1.1.
      - choice | tls-1.2 | TLS 1.2.
    required: false
    choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]

  ssl_http_match_host:
    description:
      - Enable/disable HTTP host matching for location conversion.
      - choice | disable | Do not match HTTP host.
      - choice | enable | Match HTTP host in response header.
    required: false
    choices: ["disable", "enable"]

  ssl_http_location_conversion:
    description:
      - Enable to replace HTTP with HTTPS in the reply's Location HTTP header field.
      - choice | disable | Disable HTTP location conversion.
      - choice | enable | Enable HTTP location conversion.
    required: false
    choices: ["disable", "enable"]

  ssl_hsts_include_subdomains:
    description:
      - Indicate that HSTS header applies to all subdomains.
      - choice | disable | HSTS header does not apply to subdomains.
      - choice | enable | HSTS header applies to subdomains.
    required: false
    choices: ["disable", "enable"]

  ssl_hsts_age:
    description:
      - Number of seconds the client should honour the HSTS setting.
    required: false

  ssl_hsts:
    description:
      - Enable/disable including HSTS header in response.
      - choice | disable | Do not add a HSTS header to each a HTTP response.
      - choice | enable | Add a HSTS header to each HTTP response.
    required: false
    choices: ["disable", "enable"]

  ssl_hpkp_report_uri:
    description:
      - URL to report HPKP violations to.
    required: false

  ssl_hpkp_primary:
    description:
      - Certificate to generate primary HPKP pin from.
    required: false

  ssl_hpkp_include_subdomains:
    description:
      - Indicate that HPKP header applies to all subdomains.
      - choice | disable | HPKP header does not apply to subdomains.
      - choice | enable | HPKP header applies to subdomains.
    required: false
    choices: ["disable", "enable"]

  ssl_hpkp_backup:
    description:
      - Certificate to generate backup HPKP pin from.
    required: false

  ssl_hpkp_age:
    description:
      - Number of seconds the client should honour the HPKP setting.
    required: false

  ssl_hpkp:
    description:
      - Enable/disable including HPKP header in response.
      - choice | disable | Do not add a HPKP header to each HTTP response.
      - choice | enable | Add a HPKP header to each a HTTP response.
      - choice | report-only | Add a HPKP Report-Only header to each HTTP response.
    required: false
    choices: ["disable", "enable", "report-only"]

  ssl_dh_bits:
    description:
      - Number of bits to use in the Diffie-Hellman exchange for RSA encryption of SSL sessions.
      - choice | 768 | 768-bit Diffie-Hellman prime.
      - choice | 1024 | 1024-bit Diffie-Hellman prime.
      - choice | 1536 | 1536-bit Diffie-Hellman prime.
      - choice | 2048 | 2048-bit Diffie-Hellman prime.
      - choice | 3072 | 3072-bit Diffie-Hellman prime.
      - choice | 4096 | 4096-bit Diffie-Hellman prime.
    required: false
    choices: ["768", "1024", "1536", "2048", "3072", "4096"]

  ssl_client_session_state_type:
    description:
      - How to expire SSL sessions for the segment of the SSL connection between the client and the FortiGate.
      - choice | disable | Do not keep session states.
      - choice | time | Expire session states after this many minutes.
      - choice | count | Expire session states when this maximum is reached.
      - choice | both | Expire session states based on time or count, whichever occurs first.
    required: false
    choices: ["disable", "time", "count", "both"]

  ssl_client_session_state_timeout:
    description:
      - Number of minutes to keep client to FortiGate SSL session state.
    required: false

  ssl_client_session_state_max:
    description:
      - Maximum number of client to FortiGate SSL session states to keep.
    required: false

  ssl_client_renegotiation:
    description:
      - Allow, deny, or require secure renegotiation of client sessions to comply with RFC 5746.
      - choice | deny | Abort any client initiated SSL re-negotiation attempt.
      - choice | allow | Allow a SSL client to renegotiate.
      - choice | secure | Abort any client initiated SSL re-negotiation attempt that does not use RFC 5746.
    required: false
    choices: ["deny", "allow", "secure"]

  ssl_client_fallback:
    description:
      - Enable/disable support for preventing Downgrade Attacks on client connections (RFC 7507).
      - choice | disable | Disable.
      - choice | enable | Enable.
    required: false
    choices: ["disable", "enable"]

  ssl_certificate:
    description:
      - The name of the SSL certificate to use for SSL acceleration.
    required: false

  ssl_algorithm:
    description:
      - Permitted encryption algorithms for SSL sessions according to encryption strength.
      - choice | high | High encryption. Allow only AES and ChaCha.
      - choice | medium | Medium encryption. Allow AES, ChaCha, 3DES, and RC4.
      - choice | low | Low encryption. Allow AES, ChaCha, 3DES, RC4, and DES.
      - choice | custom | Custom encryption. Use config ssl-cipher-suites to select the cipher suites that are allowed.
    required: false
    choices: ["high", "medium", "low", "custom"]

  srcintf_filter:
    description:
      - Interfaces to which the VIP applies. Separate the names with spaces.
    required: false

  src_filter:
    description:
      - Source address filter. Each address must be either an IP/subnet (x.x.x.x/n) or a range (x.x.x.x-y.y.y.y).
      - Separate addresses with spaces.
    required: false

  service:
    description:
      - Service name.
    required: false

  server_type:
    description:
      - Protocol to be load balanced by the virtual server (also called the server load balance virtual IP).
      - choice | http | HTTP
      - choice | https | HTTPS
      - choice | ssl | SSL
      - choice | tcp | TCP
      - choice | udp | UDP
      - choice | ip | IP
      - choice | imaps | IMAPS
      - choice | pop3s | POP3S
      - choice | smtps | SMTPS
    required: false
    choices: ["http", "https", "ssl", "tcp", "udp", "ip", "imaps", "pop3s", "smtps"]

  protocol:
    description:
      - Protocol to use when forwarding packets.
      - choice | tcp | TCP.
      - choice | udp | UDP.
      - choice | sctp | SCTP.
      - choice | icmp | ICMP.
    required: false
    choices: ["tcp", "udp", "sctp", "icmp"]

  portmapping_type:
    description:
      - Port mapping type.
      - choice | 1-to-1 | One to one.
      - choice | m-to-n | Many to many.
    required: false
    choices: ["1-to-1", "m-to-n"]

  portforward:
    description:
      - Enable/disable port forwarding.
      - choice | disable | Disable port forward.
      - choice | enable | Enable port forward.
    required: false
    choices: ["disable", "enable"]

  persistence:
    description:
      - Configure how to make sure that clients connect to the same server every time they make a request that is part
      - of the same session.
      - choice | none | None.
      - choice | http-cookie | HTTP cookie.
      - choice | ssl-session-id | SSL session ID.
    required: false
    choices: ["none", "http-cookie", "ssl-session-id"]

  outlook_web_access:
    description:
      - Enable to add the Front-End-Https header for Microsoft Outlook Web Access.
      - choice | disable | Disable Outlook Web Access support.
      - choice | enable | Enable Outlook Web Access support.
    required: false
    choices: ["disable", "enable"]

  nat_source_vip:
    description:
      - Enable to prevent unintended servers from using a virtual IP.
      - Disable to use the actual IP address of the server as the source address.
      - choice | disable | Do not force to NAT as VIP.
      - choice | enable | Force to NAT as VIP.
    required: false
    choices: ["disable", "enable"]

  name:
    description:
      - Virtual IP name.
    required: false

  monitor:
    description:
      - Name of the health check monitor to use when polling to determine a virtual server's connectivity status.
    required: false

  max_embryonic_connections:
    description:
      - Maximum number of incomplete connections.
    required: false

  mappedport:
    description:
      - Port number range on the destination network to which the external port number range is mapped.
    required: false

  mappedip:
    description:
      - IP address or address range on the destination network to which the external IP address is mapped.
    required: false

  mapped_addr:
    description:
      - Mapped FQDN address name.
    required: false

  ldb_method:
    description:
      - Method used to distribute sessions to real servers.
      - choice | static | Distribute to server based on source IP.
      - choice | round-robin | Distribute to server based round robin order.
      - choice | weighted | Distribute to server based on weight.
      - choice | least-session | Distribute to server with lowest session count.
      - choice | least-rtt | Distribute to server with lowest Round-Trip-Time.
      - choice | first-alive | Distribute to the first server that is alive.
      - choice | http-host | Distribute to server based on host field in HTTP header.
    required: false
    choices: ["static", "round-robin", "weighted", "least-session", "least-rtt", "first-alive", "http-host"]

  https_cookie_secure:
    description:
      - Enable/disable verification that inserted HTTPS cookies are secure.
      - choice | disable | Do not mark cookie as secure, allow sharing between an HTTP and HTTPS connection.
      - choice | enable | Mark inserted cookie as secure, cookie can only be used for HTTPS a connection.
    required: false
    choices: ["disable", "enable"]

  http_multiplex:
    description:
      - Enable/disable HTTP multiplexing.
      - choice | disable | Disable HTTP session multiplexing.
      - choice | enable | Enable HTTP session multiplexing.
    required: false
    choices: ["disable", "enable"]

  http_ip_header_name:
    description:
      - For HTTP multiplexing, enter a custom HTTPS header name. The orig client IP address is added to this header.
      - If empty, X-Forwarded-For is used.
    required: false

  http_ip_header:
    description:
      - For HTTP multiplexing, enable to add the original client IP address in the XForwarded-For HTTP header.
      - choice | disable | Disable adding HTTP header.
      - choice | enable | Enable adding HTTP header.
    required: false
    choices: ["disable", "enable"]

  http_cookie_share:
    description:
      - Control sharing of cookies across virtual servers. same-ip means a cookie from one virtual server can be used
      - by another. Disable stops cookie sharing.
      - choice | disable | Only allow HTTP cookie to match this virtual server.
      - choice | same-ip | Allow HTTP cookie to match any virtual server with same IP.
    required: false
    choices: ["disable", "same-ip"]

  http_cookie_path:
    description:
      - Limit HTTP cookie persistence to the specified path.
    required: false

  http_cookie_generation:
    description:
      - Generation of HTTP cookie to be accepted. Changing invalidates all existing cookies.
    required: false

  http_cookie_domain_from_host:
    description:
      - Enable/disable use of HTTP cookie domain from host field in HTTP.
      - choice | disable | Disable use of HTTP cookie domain from host field in HTTP (use http-cooke-domain setting).
      - choice | enable | Enable use of HTTP cookie domain from host field in HTTP.
    required: false
    choices: ["disable", "enable"]

  http_cookie_domain:
    description:
      - Domain that HTTP cookie persistence should apply to.
    required: false

  http_cookie_age:
    description:
      - Time in minutes that client web browsers should keep a cookie. Default is 60 seconds. 0 = no time limit.
    required: false

  gratuitous_arp_interval:
    description:
      - Enable to have the VIP send gratuitous ARPs. 0=disabled. Set from 5 up to 8640000 seconds to enable.
    required: false

  extport:
    description:
      - Incoming port number range that you want to map to a port number range on the destination network.
    required: false

  extip:
    description:
      - IP address or address range on the external interface that you want to map to an address or address range on t
      - he destination network.
    required: false

  extintf:
    description:
      - Interface connected to the source network that receives the packets that will be forwarded to the destination
      - network.
    required: false

  extaddr:
    description:
      - External FQDN address name.
    required: false

  dns_mapping_ttl:
    description:
      - DNS mapping TTL (Set to zero to use TTL in DNS response, default = 0).
    required: false

  comment:
    description:
      - Comment.
    required: false

  color:
    description:
      - Color of icon on the GUI.
    required: false

  arp_reply:
    description:
      - Enable to respond to ARP requests for this virtual IP address. Enabled by default.
      - choice | disable | Disable ARP reply.
      - choice | enable | Enable ARP reply.
    required: false
    choices: ["disable", "enable"]

  dynamic_mapping:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  dynamic_mapping_arp_reply:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | disable |
      - choice | enable |
    required: false
    choices: ["disable", "enable"]

  dynamic_mapping_color:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_comment:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_dns_mapping_ttl:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_extaddr:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_extintf:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_extip:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_extport:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_gratuitous_arp_interval:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_http_cookie_age:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_http_cookie_domain:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_http_cookie_domain_from_host:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | disable |
      - choice | enable |
    required: false
    choices: ["disable", "enable"]

  dynamic_mapping_http_cookie_generation:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_http_cookie_path:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_http_cookie_share:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | disable |
      - choice | same-ip |
    required: false
    choices: ["disable", "same-ip"]

  dynamic_mapping_http_ip_header:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | disable |
      - choice | enable |
    required: false
    choices: ["disable", "enable"]

  dynamic_mapping_http_ip_header_name:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_http_multiplex:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | disable |
      - choice | enable |
    required: false
    choices: ["disable", "enable"]

  dynamic_mapping_https_cookie_secure:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | disable |
      - choice | enable |
    required: false
    choices: ["disable", "enable"]

  dynamic_mapping_ldb_method:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | static |
      - choice | round-robin |
      - choice | weighted |
      - choice | least-session |
      - choice | least-rtt |
      - choice | first-alive |
      - choice | http-host |
    required: false
    choices: ["static", "round-robin", "weighted", "least-session", "least-rtt", "first-alive", "http-host"]

  dynamic_mapping_mapped_addr:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_mappedip:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_mappedport:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_max_embryonic_connections:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_monitor:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_nat_source_vip:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | disable |
      - choice | enable |
    required: false
    choices: ["disable", "enable"]

  dynamic_mapping_outlook_web_access:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | disable |
      - choice | enable |
    required: false
    choices: ["disable", "enable"]

  dynamic_mapping_persistence:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | none |
      - choice | http-cookie |
      - choice | ssl-session-id |
    required: false
    choices: ["none", "http-cookie", "ssl-session-id"]

  dynamic_mapping_portforward:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | disable |
      - choice | enable |
    required: false
    choices: ["disable", "enable"]

  dynamic_mapping_portmapping_type:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | 1-to-1 |
      - choice | m-to-n |
    required: false
    choices: ["1-to-1", "m-to-n"]

  dynamic_mapping_protocol:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | tcp |
      - choice | udp |
      - choice | sctp |
      - choice | icmp |
    required: false
    choices: ["tcp", "udp", "sctp", "icmp"]

  dynamic_mapping_server_type:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | http |
      - choice | https |
      - choice | ssl |
      - choice | tcp |
      - choice | udp |
      - choice | ip |
      - choice | imaps |
      - choice | pop3s |
      - choice | smtps |
    required: false
    choices: ["http", "https", "ssl", "tcp", "udp", "ip", "imaps", "pop3s", "smtps"]

  dynamic_mapping_service:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_src_filter:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_srcintf_filter:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_ssl_algorithm:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | high |
      - choice | medium |
      - choice | low |
      - choice | custom |
    required: false
    choices: ["high", "medium", "low", "custom"]

  dynamic_mapping_ssl_certificate:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_ssl_client_fallback:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | disable |
      - choice | enable |
    required: false
    choices: ["disable", "enable"]

  dynamic_mapping_ssl_client_renegotiation:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | deny |
      - choice | allow |
      - choice | secure |
    required: false
    choices: ["deny", "allow", "secure"]

  dynamic_mapping_ssl_client_session_state_max:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_ssl_client_session_state_timeout:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_ssl_client_session_state_type:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | disable |
      - choice | time |
      - choice | count |
      - choice | both |
    required: false
    choices: ["disable", "time", "count", "both"]

  dynamic_mapping_ssl_dh_bits:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | 768 |
      - choice | 1024 |
      - choice | 1536 |
      - choice | 2048 |
      - choice | 3072 |
      - choice | 4096 |
    required: false
    choices: ["768", "1024", "1536", "2048", "3072", "4096"]

  dynamic_mapping_ssl_hpkp:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | disable |
      - choice | enable |
      - choice | report-only |
    required: false
    choices: ["disable", "enable", "report-only"]

  dynamic_mapping_ssl_hpkp_age:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_ssl_hpkp_backup:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_ssl_hpkp_include_subdomains:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | disable |
      - choice | enable |
    required: false
    choices: ["disable", "enable"]

  dynamic_mapping_ssl_hpkp_primary:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_ssl_hpkp_report_uri:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_ssl_hsts:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | disable |
      - choice | enable |
    required: false
    choices: ["disable", "enable"]

  dynamic_mapping_ssl_hsts_age:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_ssl_hsts_include_subdomains:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | disable |
      - choice | enable |
    required: false
    choices: ["disable", "enable"]

  dynamic_mapping_ssl_http_location_conversion:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | disable |
      - choice | enable |
    required: false
    choices: ["disable", "enable"]

  dynamic_mapping_ssl_http_match_host:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | disable |
      - choice | enable |
    required: false
    choices: ["disable", "enable"]

  dynamic_mapping_ssl_max_version:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | ssl-3.0 |
      - choice | tls-1.0 |
      - choice | tls-1.1 |
      - choice | tls-1.2 |
    required: false
    choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]

  dynamic_mapping_ssl_min_version:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | ssl-3.0 |
      - choice | tls-1.0 |
      - choice | tls-1.1 |
      - choice | tls-1.2 |
    required: false
    choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]

  dynamic_mapping_ssl_mode:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | half |
      - choice | full |
    required: false
    choices: ["half", "full"]

  dynamic_mapping_ssl_pfs:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | require |
      - choice | deny |
      - choice | allow |
    required: false
    choices: ["require", "deny", "allow"]

  dynamic_mapping_ssl_send_empty_frags:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | disable |
      - choice | enable |
    required: false
    choices: ["disable", "enable"]

  dynamic_mapping_ssl_server_algorithm:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | high |
      - choice | low |
      - choice | medium |
      - choice | custom |
      - choice | client |
    required: false
    choices: ["high", "low", "medium", "custom", "client"]

  dynamic_mapping_ssl_server_max_version:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | ssl-3.0 |
      - choice | tls-1.0 |
      - choice | tls-1.1 |
      - choice | tls-1.2 |
      - choice | client |
    required: false
    choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"]

  dynamic_mapping_ssl_server_min_version:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | ssl-3.0 |
      - choice | tls-1.0 |
      - choice | tls-1.1 |
      - choice | tls-1.2 |
      - choice | client |
    required: false
    choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"]

  dynamic_mapping_ssl_server_session_state_max:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_ssl_server_session_state_timeout:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_ssl_server_session_state_type:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | disable |
      - choice | time |
      - choice | count |
      - choice | both |
    required: false
    choices: ["disable", "time", "count", "both"]

  dynamic_mapping_type:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | static-nat |
      - choice | load-balance |
      - choice | server-load-balance |
      - choice | dns-translation |
      - choice | fqdn |
    required: false
    choices: ["static-nat", "load-balance", "server-load-balance", "dns-translation", "fqdn"]

  dynamic_mapping_weblogic_server:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | disable |
      - choice | enable |
    required: false
    choices: ["disable", "enable"]

  dynamic_mapping_websphere_server:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | disable |
      - choice | enable |
    required: false
    choices: ["disable", "enable"]

  dynamic_mapping_realservers_client_ip:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_realservers_healthcheck:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | disable |
      - choice | enable |
      - choice | vip |
    required: false
    choices: ["disable", "enable", "vip"]

  dynamic_mapping_realservers_holddown_interval:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_realservers_http_host:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_realservers_ip:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_realservers_max_connections:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_realservers_monitor:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_realservers_port:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_realservers_seq:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_realservers_status:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | active |
      - choice | standby |
      - choice | disable |
    required: false
    choices: ["active", "standby", "disable"]

  dynamic_mapping_realservers_weight:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
    required: false

  dynamic_mapping_ssl_cipher_suites_cipher:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - choice | TLS-RSA-WITH-RC4-128-MD5 |
      - choice | TLS-RSA-WITH-RC4-128-SHA |
      - choice | TLS-RSA-WITH-DES-CBC-SHA |
      - choice | TLS-RSA-WITH-3DES-EDE-CBC-SHA |
      - choice | TLS-RSA-WITH-AES-128-CBC-SHA |
      - choice | TLS-RSA-WITH-AES-256-CBC-SHA |
      - choice | TLS-RSA-WITH-AES-128-CBC-SHA256 |
      - choice | TLS-RSA-WITH-AES-256-CBC-SHA256 |
      - choice | TLS-RSA-WITH-CAMELLIA-128-CBC-SHA |
      - choice | TLS-RSA-WITH-CAMELLIA-256-CBC-SHA |
      - choice | TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256 |
      - choice | TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256 |
      - choice | TLS-RSA-WITH-SEED-CBC-SHA |
      - choice | TLS-RSA-WITH-ARIA-128-CBC-SHA256 |
      - choice | TLS-RSA-WITH-ARIA-256-CBC-SHA384 |
      - choice | TLS-DHE-RSA-WITH-DES-CBC-SHA |
      - choice | TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA |
      - choice | TLS-DHE-RSA-WITH-AES-128-CBC-SHA |
      - choice | TLS-DHE-RSA-WITH-AES-256-CBC-SHA |
      - choice | TLS-DHE-RSA-WITH-AES-128-CBC-SHA256 |
      - choice | TLS-DHE-RSA-WITH-AES-256-CBC-SHA256 |
      - choice | TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA |
      - choice | TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA |
      - choice | TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256 |
      - choice | TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256 |
      - choice | TLS-DHE-RSA-WITH-SEED-CBC-SHA |
      - choice | TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256 |
      - choice | TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384 |
      - choice | TLS-ECDHE-RSA-WITH-RC4-128-SHA |
      - choice | TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA |
      - choice | TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA |
      - choice | TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA |
      - choice | TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256 |
      - choice | TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256 |
      - choice | TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256 |
      - choice | TLS-DHE-RSA-WITH-AES-128-GCM-SHA256 |
      - choice | TLS-DHE-RSA-WITH-AES-256-GCM-SHA384 |
      - choice | TLS-DHE-DSS-WITH-AES-128-CBC-SHA |
      - choice | TLS-DHE-DSS-WITH-AES-256-CBC-SHA |
      - choice | TLS-DHE-DSS-WITH-AES-128-CBC-SHA256 |
      - choice | TLS-DHE-DSS-WITH-AES-128-GCM-SHA256 |
      - choice | TLS-DHE-DSS-WITH-AES-256-CBC-SHA256 |
      - choice | TLS-DHE-DSS-WITH-AES-256-GCM-SHA384 |
      - choice | TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256 |
      - choice | TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256 |
      - choice | TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384 |
      - choice | TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384 |
      - choice | TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA |
      - choice | TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256 |
      - choice | TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 |
      - choice | TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384 |
      - choice | TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384 |
      - choice | TLS-RSA-WITH-AES-128-GCM-SHA256 |
      - choice | TLS-RSA-WITH-AES-256-GCM-SHA384 |
      - choice | TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA |
      - choice | TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA |
      - choice | TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256 |
      - choice | TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256 |
      - choice | TLS-DHE-DSS-WITH-SEED-CBC-SHA |
      - choice | TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256 |
      - choice | TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384 |
      - choice | TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256 |
      - choice | TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384 |
      - choice | TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256 |
      - choice | TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384 |
      - choice | TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA |
      - choice | TLS-DHE-DSS-WITH-DES-CBC-SHA |
    required: false
    choices: ["TLS-RSA-WITH-RC4-128-MD5",
                "TLS-RSA-WITH-RC4-128-SHA",
                "TLS-RSA-WITH-DES-CBC-SHA",
                "TLS-RSA-WITH-3DES-EDE-CBC-SHA",
                "TLS-RSA-WITH-AES-128-CBC-SHA",
                "TLS-RSA-WITH-AES-256-CBC-SHA",
                "TLS-RSA-WITH-AES-128-CBC-SHA256",
                "TLS-RSA-WITH-AES-256-CBC-SHA256",
                "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA",
                "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA",
                "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256",
                "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256",
                "TLS-RSA-WITH-SEED-CBC-SHA",
                "TLS-RSA-WITH-ARIA-128-CBC-SHA256",
                "TLS-RSA-WITH-ARIA-256-CBC-SHA384",
                "TLS-DHE-RSA-WITH-DES-CBC-SHA",
                "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA",
                "TLS-DHE-RSA-WITH-AES-128-CBC-SHA",
                "TLS-DHE-RSA-WITH-AES-256-CBC-SHA",
                "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256",
                "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256",
                "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA",
                "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA",
                "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256",
                "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256",
                "TLS-DHE-RSA-WITH-SEED-CBC-SHA",
                "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256",
                "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384",
                "TLS-ECDHE-RSA-WITH-RC4-128-SHA",
                "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA",
                "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA",
                "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA",
                "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
                "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256",
                "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
                "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256",
                "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384",
                "TLS-DHE-DSS-WITH-AES-128-CBC-SHA",
                "TLS-DHE-DSS-WITH-AES-256-CBC-SHA",
                "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256",
                "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256",
                "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256",
                "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384",
                "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256",
                "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256",
                "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384",
                "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384",
                "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA",
                "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256",
                "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256",
                "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384",
                "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384",
                "TLS-RSA-WITH-AES-128-GCM-SHA256",
                "TLS-RSA-WITH-AES-256-GCM-SHA384",
                "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA",
                "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA",
                "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256",
                "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256",
                "TLS-DHE-DSS-WITH-SEED-CBC-SHA",
                "TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256",
                "TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384",
                "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256",
                "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384",
                "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256",
                "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384",
                "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA",
                "TLS-DHE-DSS-WITH-DES-CBC-SHA"]

  dynamic_mapping_ssl_cipher_suites_versions:
    description:
      - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
      - FLAG Based Options. Specify multiple in list form.
      - flag | ssl-3.0 |
      - flag | tls-1.0 |
      - flag | tls-1.1 |
      - flag | tls-1.2 |
    required: false
    choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]

  realservers:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  realservers_client_ip:
    description:
      - Only clients in this IP range can connect to this real server.
    required: false

  realservers_healthcheck:
    description:
      - Enable to check the responsiveness of the real server before forwarding traffic.
      - choice | disable | Disable per server health check.
      - choice | enable | Enable per server health check.
      - choice | vip | Use health check defined in VIP.
    required: false
    choices: ["disable", "enable", "vip"]

  realservers_holddown_interval:
    description:
      - Time in seconds that the health check monitor monitors an unresponsive server that should be active.
    required: false

  realservers_http_host:
    description:
      - HTTP server domain name in HTTP header.
    required: false

  realservers_ip:
    description:
      - IP address of the real server.
    required: false

  realservers_max_connections:
    description:
      - Max number of active connections that can be directed to the real server. When reached, sessions are sent to
      - their real servers.
    required: false

  realservers_monitor:
    description:
      - Name of the health check monitor to use when polling to determine a virtual server's connectivity status.
    required: false

  realservers_port:
    description:
      - Port for communicating with the real server. Required if port forwarding is enabled.
    required: false

  realservers_seq:
    description:
      - Real Server Sequence Number
    required: false

  realservers_status:
    description:
      - Set the status of the real server to active so that it can accept traffic.
      - Or on standby or disabled so no traffic is sent.
      - choice | active | Server status active.
      - choice | standby | Server status standby.
      - choice | disable | Server status disable.
    required: false
    choices: ["active", "standby", "disable"]

  realservers_weight:
    description:
      - Weight of the real server. If weighted load balancing is enabled, the server with the highest weight gets more
      - connections.
    required: false

  ssl_cipher_suites:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  ssl_cipher_suites_cipher:
    description:
      - Cipher suite name.
      - choice | TLS-RSA-WITH-RC4-128-MD5 | Cipher suite TLS-RSA-WITH-RC4-128-MD5.
      - choice | TLS-RSA-WITH-RC4-128-SHA | Cipher suite TLS-RSA-WITH-RC4-128-SHA.
      - choice | TLS-RSA-WITH-DES-CBC-SHA | Cipher suite TLS-RSA-WITH-DES-CBC-SHA.
      - choice | TLS-RSA-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-RSA-WITH-3DES-EDE-CBC-SHA.
      - choice | TLS-RSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-RSA-WITH-AES-128-CBC-SHA.
      - choice | TLS-RSA-WITH-AES-256-CBC-SHA | Cipher suite TLS-RSA-WITH-AES-256-CBC-SHA.
      - choice | TLS-RSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-RSA-WITH-AES-128-CBC-SHA256.
      - choice | TLS-RSA-WITH-AES-256-CBC-SHA256 | Cipher suite TLS-RSA-WITH-AES-256-CBC-SHA256.
      - choice | TLS-RSA-WITH-CAMELLIA-128-CBC-SHA | Cipher suite TLS-RSA-WITH-CAMELLIA-128-CBC-SHA.
      - choice | TLS-RSA-WITH-CAMELLIA-256-CBC-SHA | Cipher suite TLS-RSA-WITH-CAMELLIA-256-CBC-SHA.
      - choice | TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256 | Cipher suite TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256.
      - choice | TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256 | Cipher suite TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256.
      - choice | TLS-RSA-WITH-SEED-CBC-SHA | Cipher suite TLS-RSA-WITH-SEED-CBC-SHA.
      - choice | TLS-RSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-RSA-WITH-ARIA-128-CBC-SHA256.
      - choice | TLS-RSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-RSA-WITH-ARIA-256-CBC-SHA384.
      - choice | TLS-DHE-RSA-WITH-DES-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-DES-CBC-SHA.
      - choice | TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA.
      - choice | TLS-DHE-RSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-AES-128-CBC-SHA.
      - choice | TLS-DHE-RSA-WITH-AES-256-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-AES-256-CBC-SHA.
      - choice | TLS-DHE-RSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-AES-128-CBC-SHA256.
      - choice | TLS-DHE-RSA-WITH-AES-256-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-AES-256-CBC-SHA256.
      - choice | TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA.
      - choice | TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA.
      - choice | TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256.
      - choice | TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256.
      - choice | TLS-DHE-RSA-WITH-SEED-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-SEED-CBC-SHA.
      - choice | TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256.
      - choice | TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384.
      - choice | TLS-ECDHE-RSA-WITH-RC4-128-SHA | Cipher suite TLS-ECDHE-RSA-WITH-RC4-128-SHA.
      - choice | TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA.
      - choice | TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA.
      - choice | TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA | Cipher suite TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA.
      - choice | TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256.
      - choice | TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256.
      - choice | TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256 | Cipher suite TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256.
      - choice | TLS-DHE-RSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-DHE-RSA-WITH-AES-128-GCM-SHA256.
      - choice | TLS-DHE-RSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-DHE-RSA-WITH-AES-256-GCM-SHA384.
      - choice | TLS-DHE-DSS-WITH-AES-128-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-AES-128-CBC-SHA.
      - choice | TLS-DHE-DSS-WITH-AES-256-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-AES-256-CBC-SHA.
      - choice | TLS-DHE-DSS-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-AES-128-CBC-SHA256.
      - choice | TLS-DHE-DSS-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-DHE-DSS-WITH-AES-128-GCM-SHA256.
      - choice | TLS-DHE-DSS-WITH-AES-256-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-AES-256-CBC-SHA256.
      - choice | TLS-DHE-DSS-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-DHE-DSS-WITH-AES-256-GCM-SHA384.
      - choice | TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256.
      - choice | TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256.
      - choice | TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384 | Cipher suite TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384.
      - choice | TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384.
      - choice | TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA.
      - choice | TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256.
      - choice | TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256.
      - choice | TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384.
      - choice | TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384.
      - choice | TLS-RSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-RSA-WITH-AES-128-GCM-SHA256.
      - choice | TLS-RSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-RSA-WITH-AES-256-GCM-SHA384.
      - choice | TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA | Cipher suite TLS-DSS-RSA-WITH-CAMELLIA-128-CBC-SHA.
      - choice | TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA.
      - choice | TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256.
      - choice | TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256.
      - choice | TLS-DHE-DSS-WITH-SEED-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-SEED-CBC-SHA.
      - choice | TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256.
      - choice | TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384.
      - choice | TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256.
      - choice | TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384.
      - choice | TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC_SHA256.
      - choice | TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC_SHA384.
      - choice | TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA.
      - choice | TLS-DHE-DSS-WITH-DES-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-DES-CBC-SHA.
    required: false
    choices: ["TLS-RSA-WITH-RC4-128-MD5",
            "TLS-RSA-WITH-RC4-128-SHA",
            "TLS-RSA-WITH-DES-CBC-SHA",
            "TLS-RSA-WITH-3DES-EDE-CBC-SHA",
            "TLS-RSA-WITH-AES-128-CBC-SHA",
            "TLS-RSA-WITH-AES-256-CBC-SHA",
            "TLS-RSA-WITH-AES-128-CBC-SHA256",
            "TLS-RSA-WITH-AES-256-CBC-SHA256",
            "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA",
            "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA",
            "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256",
            "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256",
            "TLS-RSA-WITH-SEED-CBC-SHA",
            "TLS-RSA-WITH-ARIA-128-CBC-SHA256",
            "TLS-RSA-WITH-ARIA-256-CBC-SHA384",
            "TLS-DHE-RSA-WITH-DES-CBC-SHA",
            "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA",
            "TLS-DHE-RSA-WITH-AES-128-CBC-SHA",
            "TLS-DHE-RSA-WITH-AES-256-CBC-SHA",
            "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256",
            "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256",
            "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA",
            "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA",
            "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256",
            "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256",
            "TLS-DHE-RSA-WITH-SEED-CBC-SHA",
            "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256",
            "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384",
            "TLS-ECDHE-RSA-WITH-RC4-128-SHA",
            "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA",
            "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA",
            "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA",
            "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
            "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256",
            "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
            "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256",
            "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384",
            "TLS-DHE-DSS-WITH-AES-128-CBC-SHA",
            "TLS-DHE-DSS-WITH-AES-256-CBC-SHA",
            "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256",
            "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256",
            "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256",
            "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384",
            "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256",
            "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256",
            "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384",
            "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384",
            "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA",
            "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256",
            "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256",
            "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384",
            "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384",
            "TLS-RSA-WITH-AES-128-GCM-SHA256",
            "TLS-RSA-WITH-AES-256-GCM-SHA384",
            "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA",
            "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA",
            "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256",
            "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256",
            "TLS-DHE-DSS-WITH-SEED-CBC-SHA",
            "TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256",
            "TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384",
            "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256",
            "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384",
            "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256",
            "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384",
            "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA",
            "TLS-DHE-DSS-WITH-DES-CBC-SHA"]

  ssl_cipher_suites_versions:
    description:
      - SSL/TLS versions that the cipher suite can be used with.
      - FLAG Based Options. Specify multiple in list form.
      - flag | ssl-3.0 | SSL 3.0.
      - flag | tls-1.0 | TLS 1.0.
      - flag | tls-1.1 | TLS 1.1.
      - flag | tls-1.2 | TLS 1.2.
    required: false
    choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]

  ssl_server_cipher_suites:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  ssl_server_cipher_suites_cipher:
    description:
      - Cipher suite name.
      - choice | TLS-RSA-WITH-RC4-128-MD5 | Cipher suite TLS-RSA-WITH-RC4-128-MD5.
      - choice | TLS-RSA-WITH-RC4-128-SHA | Cipher suite TLS-RSA-WITH-RC4-128-SHA.
      - choice | TLS-RSA-WITH-DES-CBC-SHA | Cipher suite TLS-RSA-WITH-DES-CBC-SHA.
      - choice | TLS-RSA-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-RSA-WITH-3DES-EDE-CBC-SHA.
      - choice | TLS-RSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-RSA-WITH-AES-128-CBC-SHA.
      - choice | TLS-RSA-WITH-AES-256-CBC-SHA | Cipher suite TLS-RSA-WITH-AES-256-CBC-SHA.
      - choice | TLS-RSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-RSA-WITH-AES-128-CBC-SHA256.
      - choice | TLS-RSA-WITH-AES-256-CBC-SHA256 | Cipher suite TLS-RSA-WITH-AES-256-CBC-SHA256.
      - choice | TLS-RSA-WITH-CAMELLIA-128-CBC-SHA | Cipher suite TLS-RSA-WITH-CAMELLIA-128-CBC-SHA.
      - choice | TLS-RSA-WITH-CAMELLIA-256-CBC-SHA | Cipher suite TLS-RSA-WITH-CAMELLIA-256-CBC-SHA.
      - choice | TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256 | Cipher suite TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256.
      - choice | TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256 | Cipher suite TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256.
      - choice | TLS-RSA-WITH-SEED-CBC-SHA | Cipher suite TLS-RSA-WITH-SEED-CBC-SHA.
      - choice | TLS-RSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-RSA-WITH-ARIA-128-CBC-SHA256.
      - choice | TLS-RSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-RSA-WITH-ARIA-256-CBC-SHA384.
      - choice | TLS-DHE-RSA-WITH-DES-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-DES-CBC-SHA.
      - choice | TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA.
      - choice | TLS-DHE-RSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-AES-128-CBC-SHA.
      - choice | TLS-DHE-RSA-WITH-AES-256-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-AES-256-CBC-SHA.
      - choice | TLS-DHE-RSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-AES-128-CBC-SHA256.
      - choice | TLS-DHE-RSA-WITH-AES-256-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-AES-256-CBC-SHA256.
      - choice | TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA.
      - choice | TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA.
      - choice | TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256.
      - choice | TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256.
      - choice | TLS-DHE-RSA-WITH-SEED-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-SEED-CBC-SHA.
      - choice | TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256.
      - choice | TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384.
      - choice | TLS-ECDHE-RSA-WITH-RC4-128-SHA | Cipher suite TLS-ECDHE-RSA-WITH-RC4-128-SHA.
      - choice | TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA.
      - choice | TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA.
      - choice | TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA | Cipher suite TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA.
      - choice | TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256.
      - choice | TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256 | Suite TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256.
      - choice | TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256 | Cipher suite TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256.
      - choice | TLS-DHE-RSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-DHE-RSA-WITH-AES-128-GCM-SHA256.
      - choice | TLS-DHE-RSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-DHE-RSA-WITH-AES-256-GCM-SHA384.
      - choice | TLS-DHE-DSS-WITH-AES-128-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-AES-128-CBC-SHA.
      - choice | TLS-DHE-DSS-WITH-AES-256-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-AES-256-CBC-SHA.
      - choice | TLS-DHE-DSS-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-AES-128-CBC-SHA256.
      - choice | TLS-DHE-DSS-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-DHE-DSS-WITH-AES-128-GCM-SHA256.
      - choice | TLS-DHE-DSS-WITH-AES-256-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-AES-256-CBC-SHA256.
      - choice | TLS-DHE-DSS-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-DHE-DSS-WITH-AES-256-GCM-SHA384.
      - choice | TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256.
      - choice | TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256.
      - choice | TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384 | Cipher suite TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384.
      - choice | TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384.
      - choice | TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA.
      - choice | TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256.
      - choice | TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256.
      - choice | TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384.
      - choice | TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384.
      - choice | TLS-RSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-RSA-WITH-AES-128-GCM-SHA256.
      - choice | TLS-RSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-RSA-WITH-AES-256-GCM-SHA384.
      - choice | TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA | Cipher suite TLS-DSS-RSA-WITH-CAMELLIA-128-CBC-SHA.
      - choice | TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA.
      - choice | TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256.
      - choice | TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256.
      - choice | TLS-DHE-DSS-WITH-SEED-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-SEED-CBC-SHA.
      - choice | TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256.
      - choice | TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384.
      - choice | TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256.
      - choice | TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384.
      - choice | TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC_SHA256.
      - choice | TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC_SHA384.
      - choice | TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA.
      - choice | TLS-DHE-DSS-WITH-DES-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-DES-CBC-SHA.
    required: false
    choices: ["TLS-RSA-WITH-RC4-128-MD5",
            "TLS-RSA-WITH-RC4-128-SHA",
            "TLS-RSA-WITH-DES-CBC-SHA",
            "TLS-RSA-WITH-3DES-EDE-CBC-SHA",
            "TLS-RSA-WITH-AES-128-CBC-SHA",
            "TLS-RSA-WITH-AES-256-CBC-SHA",
            "TLS-RSA-WITH-AES-128-CBC-SHA256",
            "TLS-RSA-WITH-AES-256-CBC-SHA256",
            "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA",
            "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA",
            "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256",
            "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256",
            "TLS-RSA-WITH-SEED-CBC-SHA",
            "TLS-RSA-WITH-ARIA-128-CBC-SHA256",
            "TLS-RSA-WITH-ARIA-256-CBC-SHA384",
            "TLS-DHE-RSA-WITH-DES-CBC-SHA",
            "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA",
            "TLS-DHE-RSA-WITH-AES-128-CBC-SHA",
            "TLS-DHE-RSA-WITH-AES-256-CBC-SHA",
            "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256",
            "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256",
            "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA",
            "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA",
            "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256",
            "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256",
            "TLS-DHE-RSA-WITH-SEED-CBC-SHA",
            "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256",
            "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384",
            "TLS-ECDHE-RSA-WITH-RC4-128-SHA",
            "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA",
            "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA",
            "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA",
            "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
            "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256",
            "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
            "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256",
            "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384",
            "TLS-DHE-DSS-WITH-AES-128-CBC-SHA",
            "TLS-DHE-DSS-WITH-AES-256-CBC-SHA",
            "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256",
            "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256",
            "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256",
            "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384",
            "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256",
            "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256",
            "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384",
            "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384",
            "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA",
            "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256",
            "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256",
            "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384",
            "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384",
            "TLS-RSA-WITH-AES-128-GCM-SHA256",
            "TLS-RSA-WITH-AES-256-GCM-SHA384",
            "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA",
            "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA",
            "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256",
            "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256",
            "TLS-DHE-DSS-WITH-SEED-CBC-SHA",
            "TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256",
            "TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384",
            "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256",
            "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384",
            "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256",
            "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384",
            "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA",
            "TLS-DHE-DSS-WITH-DES-CBC-SHA"]

  ssl_server_cipher_suites_priority:
    description:
      - SSL/TLS cipher suites priority.
    required: false

  ssl_server_cipher_suites_versions:
    description:
      - SSL/TLS versions that the cipher suite can be used with.
      - FLAG Based Options. Specify multiple in list form.
      - flag | ssl-3.0 | SSL 3.0.
      - flag | tls-1.0 | TLS 1.0.
      - flag | tls-1.1 | TLS 1.1.
      - flag | tls-1.2 | TLS 1.2.
    required: false
    choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]


'''

EXAMPLES = '''
# BASIC FULL STATIC NAT MAPPING
- name: EDIT FMGR_FIREWALL_VIP SNAT
  fmgr_fwobj_vip:
    name: "Basic StaticNAT Map"
    mode: "set"
    adom: "ansible"
    type: "static-nat"
    extip: "82.72.192.185"
    extintf: "any"
    mappedip: "10.7.220.25"
    comment: "Created by Ansible"
    color: "17"

# BASIC PORT PNAT MAPPING
- name: EDIT FMGR_FIREWALL_VIP PNAT
  fmgr_fwobj_vip:
    name: "Basic PNAT Map Port 10443"
    mode: "set"
    adom: "ansible"
    type: "static-nat"
    extip: "82.72.192.185"
    extport: "10443"
    extintf: "any"
    portforward: "enable"
    protocol: "tcp"
    mappedip: "10.7.220.25"
    mappedport: "443"
    comment: "Created by Ansible"
    color: "17"

# BASIC DNS TRANSLATION NAT
- name: EDIT FMGR_FIREWALL_DNST
  fmgr_fwobj_vip:
    name: "Basic DNS Translation"
    mode: "set"
    adom: "ansible"
    type: "dns-translation"
    extip: "192.168.0.1-192.168.0.100"
    extintf: "dmz"
    mappedip: "3.3.3.0/24, 4.0.0.0/24"
    comment: "Created by Ansible"
    color: "12"

# BASIC FQDN NAT
- name: EDIT FMGR_FIREWALL_FQDN
  fmgr_fwobj_vip:
    name: "Basic FQDN Translation"
    mode: "set"
    adom: "ansible"
    type: "fqdn"
    mapped_addr: "google-play"
    comment: "Created by Ansible"
    color: "5"

# DELETE AN ENTRY
- name: DELETE FMGR_FIREWALL_VIP PNAT
  fmgr_fwobj_vip:
    name: "Basic PNAT Map Port 10443"
    mode: "delete"
    adom: "ansible"
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import FMGRMethods
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
from ansible.module_utils.network.fortimanager.common import prepare_dict
from ansible.module_utils.network.fortimanager.common import scrub_dict


def fmgr_firewall_vip_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/firewall/vip'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/firewall/vip/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


#############
# END METHODS
#############


def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        websphere_server=dict(required=False, type="str", choices=["disable", "enable"]),
        weblogic_server=dict(required=False, type="str", choices=["disable", "enable"]),
        type=dict(required=False, type="str",
                  choices=["static-nat", "load-balance", "server-load-balance", "dns-translation", "fqdn"]),
        ssl_server_session_state_type=dict(required=False, type="str", choices=["disable", "time", "count", "both"]),
        ssl_server_session_state_timeout=dict(required=False, type="int"),
        ssl_server_session_state_max=dict(required=False, type="int"),
        ssl_server_min_version=dict(required=False, type="str",
                                    choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"]),
        ssl_server_max_version=dict(required=False, type="str",
                                    choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"]),
        ssl_server_algorithm=dict(required=False, type="str", choices=["high", "low", "medium", "custom", "client"]),
        ssl_send_empty_frags=dict(required=False, type="str", choices=["disable", "enable"]),
        ssl_pfs=dict(required=False, type="str", choices=["require", "deny", "allow"]),
        ssl_mode=dict(required=False, type="str", choices=["half", "full"]),
        ssl_min_version=dict(required=False, type="str", choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
        ssl_max_version=dict(required=False, type="str", choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
        ssl_http_match_host=dict(required=False, type="str", choices=["disable", "enable"]),
        ssl_http_location_conversion=dict(required=False, type="str", choices=["disable", "enable"]),
        ssl_hsts_include_subdomains=dict(required=False, type="str", choices=["disable", "enable"]),
        ssl_hsts_age=dict(required=False, type="int"),
        ssl_hsts=dict(required=False, type="str", choices=["disable", "enable"]),
        ssl_hpkp_report_uri=dict(required=False, type="str"),
        ssl_hpkp_primary=dict(required=False, type="str"),
        ssl_hpkp_include_subdomains=dict(required=False, type="str", choices=["disable", "enable"]),
        ssl_hpkp_backup=dict(required=False, type="str"),
        ssl_hpkp_age=dict(required=False, type="int"),
        ssl_hpkp=dict(required=False, type="str", choices=["disable", "enable", "report-only"]),
        ssl_dh_bits=dict(required=False, type="str", choices=["768", "1024", "1536", "2048", "3072", "4096"]),
        ssl_client_session_state_type=dict(required=False, type="str", choices=["disable", "time", "count", "both"]),
        ssl_client_session_state_timeout=dict(required=False, type="int"),
        ssl_client_session_state_max=dict(required=False, type="int"),
        ssl_client_renegotiation=dict(required=False, type="str", choices=["deny", "allow", "secure"]),
        ssl_client_fallback=dict(required=False, type="str", choices=["disable", "enable"]),
        ssl_certificate=dict(required=False, type="str"),
        ssl_algorithm=dict(required=False, type="str", choices=["high", "medium", "low", "custom"]),
        srcintf_filter=dict(required=False, type="str"),
        src_filter=dict(required=False, type="str"),
        service=dict(required=False, type="str"),
        server_type=dict(required=False, type="str",
                         choices=["http", "https", "ssl", "tcp", "udp", "ip", "imaps", "pop3s", "smtps"]),
        protocol=dict(required=False, type="str", choices=["tcp", "udp", "sctp", "icmp"]),
        portmapping_type=dict(required=False, type="str", choices=["1-to-1", "m-to-n"]),
        portforward=dict(required=False, type="str", choices=["disable", "enable"]),
        persistence=dict(required=False, type="str", choices=["none", "http-cookie", "ssl-session-id"]),
        outlook_web_access=dict(required=False, type="str", choices=["disable", "enable"]),
        nat_source_vip=dict(required=False, type="str", choices=["disable", "enable"]),
        name=dict(required=False, type="str"),
        monitor=dict(required=False, type="str"),
        max_embryonic_connections=dict(required=False, type="int"),
        mappedport=dict(required=False, type="str"),
        mappedip=dict(required=False, type="str"),
        mapped_addr=dict(required=False, type="str"),
        ldb_method=dict(required=False, type="str",
                        choices=["static", "round-robin", "weighted", "least-session", "least-rtt", "first-alive",
                                 "http-host"]),
        https_cookie_secure=dict(required=False, type="str", choices=["disable", "enable"]),
        http_multiplex=dict(required=False, type="str", choices=["disable", "enable"]),
        http_ip_header_name=dict(required=False, type="str"),
        http_ip_header=dict(required=False, type="str", choices=["disable", "enable"]),
        http_cookie_share=dict(required=False, type="str", choices=["disable", "same-ip"]),
        http_cookie_path=dict(required=False, type="str"),
        http_cookie_generation=dict(required=False, type="int"),
        http_cookie_domain_from_host=dict(required=False, type="str", choices=["disable", "enable"]),
        http_cookie_domain=dict(required=False, type="str"),
        http_cookie_age=dict(required=False, type="int"),
        gratuitous_arp_interval=dict(required=False, type="int"),
        extport=dict(required=False, type="str"),
        extip=dict(required=False, type="str"),
        extintf=dict(required=False, type="str"),
        extaddr=dict(required=False, type="str"),
        dns_mapping_ttl=dict(required=False, type="int"),
        comment=dict(required=False, type="str"),
        color=dict(required=False, type="int"),
        arp_reply=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping=dict(required=False, type="list"),
        dynamic_mapping_arp_reply=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_color=dict(required=False, type="int"),
        dynamic_mapping_comment=dict(required=False, type="str"),
        dynamic_mapping_dns_mapping_ttl=dict(required=False, type="int"),
        dynamic_mapping_extaddr=dict(required=False, type="str"),
        dynamic_mapping_extintf=dict(required=False, type="str"),
        dynamic_mapping_extip=dict(required=False, type="str"),
        dynamic_mapping_extport=dict(required=False, type="str"),
        dynamic_mapping_gratuitous_arp_interval=dict(required=False, type="int"),
        dynamic_mapping_http_cookie_age=dict(required=False, type="int"),
        dynamic_mapping_http_cookie_domain=dict(required=False, type="str"),
        dynamic_mapping_http_cookie_domain_from_host=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_http_cookie_generation=dict(required=False, type="int"),
        dynamic_mapping_http_cookie_path=dict(required=False, type="str"),
        dynamic_mapping_http_cookie_share=dict(required=False, type="str", choices=["disable", "same-ip"]),
        dynamic_mapping_http_ip_header=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_http_ip_header_name=dict(required=False, type="str"),
        dynamic_mapping_http_multiplex=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_https_cookie_secure=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_ldb_method=dict(required=False, type="str", choices=["static",
                                                                             "round-robin",
                                                                             "weighted",
                                                                             "least-session",
                                                                             "least-rtt",
                                                                             "first-alive",
                                                                             "http-host"]),
        dynamic_mapping_mapped_addr=dict(required=False, type="str"),
        dynamic_mapping_mappedip=dict(required=False, type="str"),
        dynamic_mapping_mappedport=dict(required=False, type="str"),
        dynamic_mapping_max_embryonic_connections=dict(required=False, type="int"),
        dynamic_mapping_monitor=dict(required=False, type="str"),
        dynamic_mapping_nat_source_vip=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_outlook_web_access=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_persistence=dict(required=False, type="str", choices=["none", "http-cookie", "ssl-session-id"]),
        dynamic_mapping_portforward=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_portmapping_type=dict(required=False, type="str", choices=["1-to-1", "m-to-n"]),
        dynamic_mapping_protocol=dict(required=False, type="str", choices=["tcp", "udp", "sctp", "icmp"]),
        dynamic_mapping_server_type=dict(required=False, type="str",
                                         choices=["http", "https", "ssl", "tcp", "udp", "ip", "imaps", "pop3s",
                                                  "smtps"]),
        dynamic_mapping_service=dict(required=False, type="str"),
        dynamic_mapping_src_filter=dict(required=False, type="str"),
        dynamic_mapping_srcintf_filter=dict(required=False, type="str"),
        dynamic_mapping_ssl_algorithm=dict(required=False, type="str", choices=["high", "medium", "low", "custom"]),
        dynamic_mapping_ssl_certificate=dict(required=False, type="str"),
        dynamic_mapping_ssl_client_fallback=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_ssl_client_renegotiation=dict(required=False, type="str", choices=["deny", "allow", "secure"]),
        dynamic_mapping_ssl_client_session_state_max=dict(required=False, type="int"),
        dynamic_mapping_ssl_client_session_state_timeout=dict(required=False, type="int"),
        dynamic_mapping_ssl_client_session_state_type=dict(required=False, type="str",
                                                           choices=["disable", "time", "count", "both"]),
        dynamic_mapping_ssl_dh_bits=dict(required=False, type="str",
                                         choices=["768", "1024", "1536", "2048", "3072", "4096"]),
        dynamic_mapping_ssl_hpkp=dict(required=False, type="str", choices=["disable", "enable", "report-only"]),
        dynamic_mapping_ssl_hpkp_age=dict(required=False, type="int"),
        dynamic_mapping_ssl_hpkp_backup=dict(required=False, type="str"),
        dynamic_mapping_ssl_hpkp_include_subdomains=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_ssl_hpkp_primary=dict(required=False, type="str"),
        dynamic_mapping_ssl_hpkp_report_uri=dict(required=False, type="str"),
        dynamic_mapping_ssl_hsts=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_ssl_hsts_age=dict(required=False, type="int"),
        dynamic_mapping_ssl_hsts_include_subdomains=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_ssl_http_location_conversion=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_ssl_http_match_host=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_ssl_max_version=dict(required=False, type="str",
                                             choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
        dynamic_mapping_ssl_min_version=dict(required=False, type="str",
                                             choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
        dynamic_mapping_ssl_mode=dict(required=False, type="str", choices=["half", "full"]),
        dynamic_mapping_ssl_pfs=dict(required=False, type="str", choices=["require", "deny", "allow"]),
        dynamic_mapping_ssl_send_empty_frags=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_ssl_server_algorithm=dict(required=False, type="str",
                                                  choices=["high", "low", "medium", "custom", "client"]),
        dynamic_mapping_ssl_server_max_version=dict(required=False, type="str",
                                                    choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"]),
        dynamic_mapping_ssl_server_min_version=dict(required=False, type="str",
                                                    choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"]),
        dynamic_mapping_ssl_server_session_state_max=dict(required=False, type="int"),
        dynamic_mapping_ssl_server_session_state_timeout=dict(required=False, type="int"),
        dynamic_mapping_ssl_server_session_state_type=dict(required=False, type="str",
                                                           choices=["disable", "time", "count", "both"]),
        dynamic_mapping_type=dict(required=False, type="str",
                                  choices=["static-nat", "load-balance", "server-load-balance", "dns-translation",
                                           "fqdn"]),
        dynamic_mapping_weblogic_server=dict(required=False, type="str", choices=["disable", "enable"]),
        dynamic_mapping_websphere_server=dict(required=False, type="str", choices=["disable", "enable"]),

        dynamic_mapping_realservers_client_ip=dict(required=False, type="str"),
        dynamic_mapping_realservers_healthcheck=dict(required=False, type="str", choices=["disable", "enable", "vip"]),
        dynamic_mapping_realservers_holddown_interval=dict(required=False, type="int"),
        dynamic_mapping_realservers_http_host=dict(required=False, type="str"),
        dynamic_mapping_realservers_ip=dict(required=False, type="str"),
        dynamic_mapping_realservers_max_connections=dict(required=False, type="int"),
        dynamic_mapping_realservers_monitor=dict(required=False, type="str"),
        dynamic_mapping_realservers_port=dict(required=False, type="int"),
        dynamic_mapping_realservers_seq=dict(required=False, type="str"),
        dynamic_mapping_realservers_status=dict(required=False, type="str", choices=["active", "standby", "disable"]),
        dynamic_mapping_realservers_weight=dict(required=False, type="int"),

        dynamic_mapping_ssl_cipher_suites_cipher=dict(required=False,
                                                      type="str",
                                                      choices=["TLS-RSA-WITH-RC4-128-MD5",
                                                               "TLS-RSA-WITH-RC4-128-SHA",
                                                               "TLS-RSA-WITH-DES-CBC-SHA",
                                                               "TLS-RSA-WITH-3DES-EDE-CBC-SHA",
                                                               "TLS-RSA-WITH-AES-128-CBC-SHA",
                                                               "TLS-RSA-WITH-AES-256-CBC-SHA",
                                                               "TLS-RSA-WITH-AES-128-CBC-SHA256",
                                                               "TLS-RSA-WITH-AES-256-CBC-SHA256",
                                                               "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA",
                                                               "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA",
                                                               "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256",
                                                               "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256",
                                                               "TLS-RSA-WITH-SEED-CBC-SHA",
                                                               "TLS-RSA-WITH-ARIA-128-CBC-SHA256",
                                                               "TLS-RSA-WITH-ARIA-256-CBC-SHA384",
                                                               "TLS-DHE-RSA-WITH-DES-CBC-SHA",
                                                               "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA",
                                                               "TLS-DHE-RSA-WITH-AES-128-CBC-SHA",
                                                               "TLS-DHE-RSA-WITH-AES-256-CBC-SHA",
                                                               "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256",
                                                               "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256",
                                                               "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA",
                                                               "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA",
                                                               "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256",
                                                               "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256",
                                                               "TLS-DHE-RSA-WITH-SEED-CBC-SHA",
                                                               "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256",
                                                               "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384",
                                                               "TLS-ECDHE-RSA-WITH-RC4-128-SHA",
                                                               "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA",
                                                               "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA",
                                                               "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA",
                                                               "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
                                                               "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256",
                                                               "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
                                                               "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256",
                                                               "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384",
                                                               "TLS-DHE-DSS-WITH-AES-128-CBC-SHA",
                                                               "TLS-DHE-DSS-WITH-AES-256-CBC-SHA",
                                                               "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256",
                                                               "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256",
                                                               "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256",
                                                               "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384",
                                                               "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256",
                                                               "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256",
                                                               "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384",
                                                               "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384",
                                                               "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA",
                                                               "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256",
                                                               "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256",
                                                               "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384",
                                                               "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384",
                                                               "TLS-RSA-WITH-AES-128-GCM-SHA256",
                                                               "TLS-RSA-WITH-AES-256-GCM-SHA384",
                                                               "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA",
                                                               "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA",
                                                               "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256",
                                                               "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256",
                                                               "TLS-DHE-DSS-WITH-SEED-CBC-SHA",
                                                               "TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256",
                                                               "TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384",
                                                               "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256",
                                                               "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384",
                                                               "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256",
                                                               "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384",
                                                               "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA",
                                                               "TLS-DHE-DSS-WITH-DES-CBC-SHA"]),
        dynamic_mapping_ssl_cipher_suites_versions=dict(required=False, type="str",
                                                        choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
        realservers=dict(required=False, type="list"),
        realservers_client_ip=dict(required=False, type="str"),
        realservers_healthcheck=dict(required=False, type="str", choices=["disable", "enable", "vip"]),
        realservers_holddown_interval=dict(required=False, type="int"),
        realservers_http_host=dict(required=False, type="str"),
        realservers_ip=dict(required=False, type="str"),
        realservers_max_connections=dict(required=False, type="int"),
        realservers_monitor=dict(required=False, type="str"),
        realservers_port=dict(required=False, type="int"),
        realservers_seq=dict(required=False, type="str"),
        realservers_status=dict(required=False, type="str", choices=["active", "standby", "disable"]),
        realservers_weight=dict(required=False, type="int"),
        ssl_cipher_suites=dict(required=False, type="list"),
        ssl_cipher_suites_cipher=dict(required=False,
                                      type="str",
                                      choices=["TLS-RSA-WITH-RC4-128-MD5",
                                               "TLS-RSA-WITH-RC4-128-SHA",
                                               "TLS-RSA-WITH-DES-CBC-SHA",
                                               "TLS-RSA-WITH-3DES-EDE-CBC-SHA",
                                               "TLS-RSA-WITH-AES-128-CBC-SHA",
                                               "TLS-RSA-WITH-AES-256-CBC-SHA",
                                               "TLS-RSA-WITH-AES-128-CBC-SHA256",
                                               "TLS-RSA-WITH-AES-256-CBC-SHA256",
                                               "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA",
                                               "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA",
                                               "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256",
                                               "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256",
                                               "TLS-RSA-WITH-SEED-CBC-SHA",
                                               "TLS-RSA-WITH-ARIA-128-CBC-SHA256",
                                               "TLS-RSA-WITH-ARIA-256-CBC-SHA384",
                                               "TLS-DHE-RSA-WITH-DES-CBC-SHA",
                                               "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA",
                                               "TLS-DHE-RSA-WITH-AES-128-CBC-SHA",
                                               "TLS-DHE-RSA-WITH-AES-256-CBC-SHA",
                                               "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256",
                                               "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256",
                                               "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA",
                                               "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA",
                                               "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256",
                                               "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256",
                                               "TLS-DHE-RSA-WITH-SEED-CBC-SHA",
                                               "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256",
                                               "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384",
                                               "TLS-ECDHE-RSA-WITH-RC4-128-SHA",
                                               "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA",
                                               "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA",
                                               "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA",
                                               "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
                                               "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256",
                                               "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
                                               "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256",
                                               "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384",
                                               "TLS-DHE-DSS-WITH-AES-128-CBC-SHA",
                                               "TLS-DHE-DSS-WITH-AES-256-CBC-SHA",
                                               "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256",
                                               "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256",
                                               "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256",
                                               "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384",
                                               "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256",
                                               "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256",
                                               "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384",
                                               "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384",
                                               "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA",
                                               "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256",
                                               "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256",
                                               "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384",
                                               "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384",
                                               "TLS-RSA-WITH-AES-128-GCM-SHA256",
                                               "TLS-RSA-WITH-AES-256-GCM-SHA384",
                                               "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA",
                                               "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA",
                                               "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256",
                                               "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256",
                                               "TLS-DHE-DSS-WITH-SEED-CBC-SHA",
                                               "TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256",
                                               "TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384",
                                               "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256",
                                               "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384",
                                               "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256",
                                               "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384",
                                               "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA",
                                               "TLS-DHE-DSS-WITH-DES-CBC-SHA"]),
        ssl_cipher_suites_versions=dict(required=False, type="str",
                                        choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
        ssl_server_cipher_suites=dict(required=False, type="list"),
        ssl_server_cipher_suites_cipher=dict(required=False,
                                             type="str",
                                             choices=["TLS-RSA-WITH-RC4-128-MD5",
                                                      "TLS-RSA-WITH-RC4-128-SHA",
                                                      "TLS-RSA-WITH-DES-CBC-SHA",
                                                      "TLS-RSA-WITH-3DES-EDE-CBC-SHA",
                                                      "TLS-RSA-WITH-AES-128-CBC-SHA",
                                                      "TLS-RSA-WITH-AES-256-CBC-SHA",
                                                      "TLS-RSA-WITH-AES-128-CBC-SHA256",
                                                      "TLS-RSA-WITH-AES-256-CBC-SHA256",
                                                      "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA",
                                                      "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA",
                                                      "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256",
                                                      "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256",
                                                      "TLS-RSA-WITH-SEED-CBC-SHA",
                                                      "TLS-RSA-WITH-ARIA-128-CBC-SHA256",
                                                      "TLS-RSA-WITH-ARIA-256-CBC-SHA384",
                                                      "TLS-DHE-RSA-WITH-DES-CBC-SHA",
                                                      "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA",
                                                      "TLS-DHE-RSA-WITH-AES-128-CBC-SHA",
                                                      "TLS-DHE-RSA-WITH-AES-256-CBC-SHA",
                                                      "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256",
                                                      "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256",
                                                      "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA",
                                                      "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA",
                                                      "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256",
                                                      "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256",
                                                      "TLS-DHE-RSA-WITH-SEED-CBC-SHA",
                                                      "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256",
                                                      "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384",
                                                      "TLS-ECDHE-RSA-WITH-RC4-128-SHA",
                                                      "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA",
                                                      "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA",
                                                      "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA",
                                                      "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
                                                      "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256",
                                                      "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
                                                      "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256",
                                                      "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384",
                                                      "TLS-DHE-DSS-WITH-AES-128-CBC-SHA",
                                                      "TLS-DHE-DSS-WITH-AES-256-CBC-SHA",
                                                      "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256",
                                                      "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256",
                                                      "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256",
                                                      "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384",
                                                      "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256",
                                                      "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256",
                                                      "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384",
                                                      "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384",
                                                      "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA",
                                                      "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256",
                                                      "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256",
                                                      "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384",
                                                      "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384",
                                                      "TLS-RSA-WITH-AES-128-GCM-SHA256",
                                                      "TLS-RSA-WITH-AES-256-GCM-SHA384",
                                                      "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA",
                                                      "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA",
                                                      "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256",
                                                      "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256",
                                                      "TLS-DHE-DSS-WITH-SEED-CBC-SHA",
                                                      "TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256",
                                                      "TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384",
                                                      "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256",
                                                      "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384",
                                                      "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256",
                                                      "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384",
                                                      "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA",
                                                      "TLS-DHE-DSS-WITH-DES-CBC-SHA"]),
        ssl_server_cipher_suites_priority=dict(required=False, type="str"),
        ssl_server_cipher_suites_versions=dict(required=False, type="str",
                                               choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "websphere-server": module.params["websphere_server"],
        "weblogic-server": module.params["weblogic_server"],
        "type": module.params["type"],
        "ssl-server-session-state-type": module.params["ssl_server_session_state_type"],
        "ssl-server-session-state-timeout": module.params["ssl_server_session_state_timeout"],
        "ssl-server-session-state-max": module.params["ssl_server_session_state_max"],
        "ssl-server-min-version": module.params["ssl_server_min_version"],
        "ssl-server-max-version": module.params["ssl_server_max_version"],
        "ssl-server-algorithm": module.params["ssl_server_algorithm"],
        "ssl-send-empty-frags": module.params["ssl_send_empty_frags"],
        "ssl-pfs": module.params["ssl_pfs"],
        "ssl-mode": module.params["ssl_mode"],
        "ssl-min-version": module.params["ssl_min_version"],
        "ssl-max-version": module.params["ssl_max_version"],
        "ssl-http-match-host": module.params["ssl_http_match_host"],
        "ssl-http-location-conversion": module.params["ssl_http_location_conversion"],
        "ssl-hsts-include-subdomains": module.params["ssl_hsts_include_subdomains"],
        "ssl-hsts-age": module.params["ssl_hsts_age"],
        "ssl-hsts": module.params["ssl_hsts"],
        "ssl-hpkp-report-uri": module.params["ssl_hpkp_report_uri"],
        "ssl-hpkp-primary": module.params["ssl_hpkp_primary"],
        "ssl-hpkp-include-subdomains": module.params["ssl_hpkp_include_subdomains"],
        "ssl-hpkp-backup": module.params["ssl_hpkp_backup"],
        "ssl-hpkp-age": module.params["ssl_hpkp_age"],
        "ssl-hpkp": module.params["ssl_hpkp"],
        "ssl-dh-bits": module.params["ssl_dh_bits"],
        "ssl-client-session-state-type": module.params["ssl_client_session_state_type"],
        "ssl-client-session-state-timeout": module.params["ssl_client_session_state_timeout"],
        "ssl-client-session-state-max": module.params["ssl_client_session_state_max"],
        "ssl-client-renegotiation": module.params["ssl_client_renegotiation"],
        "ssl-client-fallback": module.params["ssl_client_fallback"],
        "ssl-certificate": module.params["ssl_certificate"],
        "ssl-algorithm": module.params["ssl_algorithm"],
        "srcintf-filter": module.params["srcintf_filter"],
        "src-filter": module.params["src_filter"],
        "service": module.params["service"],
        "server-type": module.params["server_type"],
        "protocol": module.params["protocol"],
        "portmapping-type": module.params["portmapping_type"],
        "portforward": module.params["portforward"],
        "persistence": module.params["persistence"],
        "outlook-web-access": module.params["outlook_web_access"],
        "nat-source-vip": module.params["nat_source_vip"],
        "name": module.params["name"],
        "monitor": module.params["monitor"],
        "max-embryonic-connections": module.params["max_embryonic_connections"],
        "mappedport": module.params["mappedport"],
        "mappedip": module.params["mappedip"],
        "mapped-addr": module.params["mapped_addr"],
        "ldb-method": module.params["ldb_method"],
        "https-cookie-secure": module.params["https_cookie_secure"],
        "http-multiplex": module.params["http_multiplex"],
        "http-ip-header-name": module.params["http_ip_header_name"],
        "http-ip-header": module.params["http_ip_header"],
        "http-cookie-share": module.params["http_cookie_share"],
        "http-cookie-path": module.params["http_cookie_path"],
        "http-cookie-generation": module.params["http_cookie_generation"],
        "http-cookie-domain-from-host": module.params["http_cookie_domain_from_host"],
        "http-cookie-domain": module.params["http_cookie_domain"],
        "http-cookie-age": module.params["http_cookie_age"],
        "gratuitous-arp-interval": module.params["gratuitous_arp_interval"],
        "extport": module.params["extport"],
        "extip": module.params["extip"],
        "extintf": module.params["extintf"],
        "extaddr": module.params["extaddr"],
        "dns-mapping-ttl": module.params["dns_mapping_ttl"],
        "comment": module.params["comment"],
        "color": module.params["color"],
        "arp-reply": module.params["arp_reply"],
        "dynamic_mapping": {
            "arp-reply": module.params["dynamic_mapping_arp_reply"],
            "color": module.params["dynamic_mapping_color"],
            "comment": module.params["dynamic_mapping_comment"],
            "dns-mapping-ttl": module.params["dynamic_mapping_dns_mapping_ttl"],
            "extaddr": module.params["dynamic_mapping_extaddr"],
            "extintf": module.params["dynamic_mapping_extintf"],
            "extip": module.params["dynamic_mapping_extip"],
            "extport": module.params["dynamic_mapping_extport"],
            "gratuitous-arp-interval": module.params["dynamic_mapping_gratuitous_arp_interval"],
            "http-cookie-age": module.params["dynamic_mapping_http_cookie_age"],
            "http-cookie-domain": module.params["dynamic_mapping_http_cookie_domain"],
            "http-cookie-domain-from-host": module.params["dynamic_mapping_http_cookie_domain_from_host"],
            "http-cookie-generation": module.params["dynamic_mapping_http_cookie_generation"],
            "http-cookie-path": module.params["dynamic_mapping_http_cookie_path"],
            "http-cookie-share": module.params["dynamic_mapping_http_cookie_share"],
            "http-ip-header": module.params["dynamic_mapping_http_ip_header"],
            "http-ip-header-name": module.params["dynamic_mapping_http_ip_header_name"],
            "http-multiplex": module.params["dynamic_mapping_http_multiplex"],
            "https-cookie-secure": module.params["dynamic_mapping_https_cookie_secure"],
            "ldb-method": module.params["dynamic_mapping_ldb_method"],
            "mapped-addr": module.params["dynamic_mapping_mapped_addr"],
            "mappedip": module.params["dynamic_mapping_mappedip"],
            "mappedport": module.params["dynamic_mapping_mappedport"],
            "max-embryonic-connections": module.params["dynamic_mapping_max_embryonic_connections"],
            "monitor": module.params["dynamic_mapping_monitor"],
            "nat-source-vip": module.params["dynamic_mapping_nat_source_vip"],
            "outlook-web-access": module.params["dynamic_mapping_outlook_web_access"],
            "persistence": module.params["dynamic_mapping_persistence"],
            "portforward": module.params["dynamic_mapping_portforward"],
            "portmapping-type": module.params["dynamic_mapping_portmapping_type"],
            "protocol": module.params["dynamic_mapping_protocol"],
            "server-type": module.params["dynamic_mapping_server_type"],
            "service": module.params["dynamic_mapping_service"],
            "src-filter": module.params["dynamic_mapping_src_filter"],
            "srcintf-filter": module.params["dynamic_mapping_srcintf_filter"],
            "ssl-algorithm": module.params["dynamic_mapping_ssl_algorithm"],
            "ssl-certificate": module.params["dynamic_mapping_ssl_certificate"],
            "ssl-client-fallback": module.params["dynamic_mapping_ssl_client_fallback"],
            "ssl-client-renegotiation": module.params["dynamic_mapping_ssl_client_renegotiation"],
            "ssl-client-session-state-max": module.params["dynamic_mapping_ssl_client_session_state_max"],
            "ssl-client-session-state-timeout": module.params["dynamic_mapping_ssl_client_session_state_timeout"],
            "ssl-client-session-state-type": module.params["dynamic_mapping_ssl_client_session_state_type"],
            "ssl-dh-bits": module.params["dynamic_mapping_ssl_dh_bits"],
            "ssl-hpkp": module.params["dynamic_mapping_ssl_hpkp"],
            "ssl-hpkp-age": module.params["dynamic_mapping_ssl_hpkp_age"],
            "ssl-hpkp-backup": module.params["dynamic_mapping_ssl_hpkp_backup"],
            "ssl-hpkp-include-subdomains": module.params["dynamic_mapping_ssl_hpkp_include_subdomains"],
            "ssl-hpkp-primary": module.params["dynamic_mapping_ssl_hpkp_primary"],
            "ssl-hpkp-report-uri": module.params["dynamic_mapping_ssl_hpkp_report_uri"],
            "ssl-hsts": module.params["dynamic_mapping_ssl_hsts"],
            "ssl-hsts-age": module.params["dynamic_mapping_ssl_hsts_age"],
            "ssl-hsts-include-subdomains": module.params["dynamic_mapping_ssl_hsts_include_subdomains"],
            "ssl-http-location-conversion": module.params["dynamic_mapping_ssl_http_location_conversion"],
            "ssl-http-match-host": module.params["dynamic_mapping_ssl_http_match_host"],
            "ssl-max-version": module.params["dynamic_mapping_ssl_max_version"],
            "ssl-min-version": module.params["dynamic_mapping_ssl_min_version"],
            "ssl-mode": module.params["dynamic_mapping_ssl_mode"],
            "ssl-pfs": module.params["dynamic_mapping_ssl_pfs"],
            "ssl-send-empty-frags": module.params["dynamic_mapping_ssl_send_empty_frags"],
            "ssl-server-algorithm": module.params["dynamic_mapping_ssl_server_algorithm"],
            "ssl-server-max-version": module.params["dynamic_mapping_ssl_server_max_version"],
            "ssl-server-min-version": module.params["dynamic_mapping_ssl_server_min_version"],
            "ssl-server-session-state-max": module.params["dynamic_mapping_ssl_server_session_state_max"],
            "ssl-server-session-state-timeout": module.params["dynamic_mapping_ssl_server_session_state_timeout"],
            "ssl-server-session-state-type": module.params["dynamic_mapping_ssl_server_session_state_type"],
            "type": module.params["dynamic_mapping_type"],
            "weblogic-server": module.params["dynamic_mapping_weblogic_server"],
            "websphere-server": module.params["dynamic_mapping_websphere_server"],
            "realservers": {
                "client-ip": module.params["dynamic_mapping_realservers_client_ip"],
                "healthcheck": module.params["dynamic_mapping_realservers_healthcheck"],
                "holddown-interval": module.params["dynamic_mapping_realservers_holddown_interval"],
                "http-host": module.params["dynamic_mapping_realservers_http_host"],
                "ip": module.params["dynamic_mapping_realservers_ip"],
                "max-connections": module.params["dynamic_mapping_realservers_max_connections"],
                "monitor": module.params["dynamic_mapping_realservers_monitor"],
                "port": module.params["dynamic_mapping_realservers_port"],
                "seq": module.params["dynamic_mapping_realservers_seq"],
                "status": module.params["dynamic_mapping_realservers_status"],
                "weight": module.params["dynamic_mapping_realservers_weight"],
            },
            "ssl-cipher-suites": {
                "cipher": module.params["dynamic_mapping_ssl_cipher_suites_cipher"],
                "versions": module.params["dynamic_mapping_ssl_cipher_suites_versions"],
            },
        },
        "realservers": {
            "client-ip": module.params["realservers_client_ip"],
            "healthcheck": module.params["realservers_healthcheck"],
            "holddown-interval": module.params["realservers_holddown_interval"],
            "http-host": module.params["realservers_http_host"],
            "ip": module.params["realservers_ip"],
            "max-connections": module.params["realservers_max_connections"],
            "monitor": module.params["realservers_monitor"],
            "port": module.params["realservers_port"],
            "seq": module.params["realservers_seq"],
            "status": module.params["realservers_status"],
            "weight": module.params["realservers_weight"],
        },
        "ssl-cipher-suites": {
            "cipher": module.params["ssl_cipher_suites_cipher"],
            "versions": module.params["ssl_cipher_suites_versions"],
        },
        "ssl-server-cipher-suites": {
            "cipher": module.params["ssl_server_cipher_suites_cipher"],
            "priority": module.params["ssl_server_cipher_suites_priority"],
            "versions": module.params["ssl_server_cipher_suites_versions"],
        }
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['dynamic_mapping', 'realservers', 'ssl-cipher-suites', 'ssl-server-cipher-suites']
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)

    results = DEFAULT_RESULT_OBJ
    try:
        results = fmgr_firewall_vip_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_fwpol_ipv4

Metadata

Name: fmgr_fwpol_ipv4

Description: Allows the add/delete of Firewall Policies on Packages in FortiManager.

Author(s):

  • Luke Weighall (github: @lweighall)
  • Andrew Welsh (github: @Ghilli3)
  • Jim Huber (github: @p4r4n0y1ng)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Luke Weighall

Module Github Link

Parameters
action
  • Description: Policy action (allow/deny/ipsec).

    choice | deny | Blocks sessions that match the firewall policy.

    choice | accept | Allows session that match the firewall policy.

    choice | ipsec | Firewall policy becomes a policy-based IPsec VPN policy.

  • Required: False

  • choices: [‘deny’, ‘accept’, ‘ipsec’]

adom
  • Description: The ADOM the configuration should belong to.
  • Required: False
  • default: root
app_category
  • Description: Application category ID list.
  • Required: False
app_group
  • Description: Application group names.
  • Required: False
application
  • Description: Application ID list.
  • Required: False
application_list
  • Description: Name of an existing Application list.
  • Required: False
auth_cert
  • Description: HTTPS server certificate for policy authentication.
  • Required: False
auth_path
  • Description: Enable/disable authentication-based routing.

    choice | disable | Disable authentication-based routing.

    choice | enable | Enable authentication-based routing.

  • Required: False

  • choices: [‘disable’, ‘enable’]

auth_redirect_addr
  • Description: HTTP-to-HTTPS redirect address for firewall authentication.
  • Required: False
auto_asic_offload
  • Description: Enable/disable offloading security profile processing to CP processors.

    choice | disable | Disable ASIC offloading.

    choice | enable | Enable auto ASIC offloading.

  • Required: False

  • choices: [‘disable’, ‘enable’]

av_profile
  • Description: Name of an existing Antivirus profile.
  • Required: False
block_notification
  • Description: Enable/disable block notification.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

captive_portal_exempt
  • Description: Enable to exempt some users from the captive portal.

    choice | disable | Disable exemption of captive portal.

    choice | enable | Enable exemption of captive portal.

  • Required: False

  • choices: [‘disable’, ‘enable’]

capture_packet
  • Description: Enable/disable capture packets.

    choice | disable | Disable capture packets.

    choice | enable | Enable capture packets.

  • Required: False

  • choices: [‘disable’, ‘enable’]

comments
  • Description: Comment.
  • Required: False
custom_log_fields
  • Description: Custom fields to append to log messages for this policy.
  • Required: False
delay_tcp_npu_session
  • Description: Enable TCP NPU session delay to guarantee packet order of 3-way handshake.

    choice | disable | Disable TCP NPU session delay in order to guarantee packet order of 3-way handshake.

    choice | enable | Enable TCP NPU session delay in order to guarantee packet order of 3-way handshake.

  • Required: False

  • choices: [‘disable’, ‘enable’]

devices
  • Description: Names of devices or device groups that can be matched by the policy.
  • Required: False
diffserv_forward
  • Description: Enable to change packet’s DiffServ values to the specified diffservcode-forward value.

    choice | disable | Disable WAN optimization.

    choice | enable | Enable WAN optimization.

  • Required: False

  • choices: [‘disable’, ‘enable’]

diffserv_reverse
  • Description: Enable to change packet’s reverse (reply) DiffServ values to the specified diffservcode-rev value.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

diffservcode_forward
  • Description: Change packet’s DiffServ to this value.
  • Required: False
diffservcode_rev
  • Description: Change packet’s reverse (reply) DiffServ to this value.
  • Required: False
disclaimer
  • Description: Enable/disable user authentication disclaimer.

    choice | disable | Disable user authentication disclaimer.

    choice | enable | Enable user authentication disclaimer.

  • Required: False

  • choices: [‘disable’, ‘enable’]

dlp_sensor
  • Description: Name of an existing DLP sensor.
  • Required: False
dnsfilter_profile
  • Description: Name of an existing DNS filter profile.
  • Required: False
dscp_match
  • Description: Enable DSCP check.

    choice | disable | Disable DSCP check.

    choice | enable | Enable DSCP check.

  • Required: False

  • choices: [‘disable’, ‘enable’]

dscp_negate
  • Description: Enable negated DSCP match.

    choice | disable | Disable DSCP negate.

    choice | enable | Enable DSCP negate.

  • Required: False

  • choices: [‘disable’, ‘enable’]

dscp_value
  • Description: DSCP value.
  • Required: False
dsri
  • Description: Enable DSRI to ignore HTTP server responses.

    choice | disable | Disable DSRI.

    choice | enable | Enable DSRI.

  • Required: False

  • choices: [‘disable’, ‘enable’]

dstaddr
  • Description: Destination address and address group names.
  • Required: False
dstaddr_negate
  • Description: When enabled dstaddr specifies what the destination address must NOT be.

    choice | disable | Disable destination address negate.

    choice | enable | Enable destination address negate.

  • Required: False

  • choices: [‘disable’, ‘enable’]

dstintf
  • Description: Outgoing (egress) interface.
  • Required: False
firewall_session_dirty
  • Description: How to handle sessions if the configuration of this firewall policy changes.

    choice | check-all | Flush all current sessions accepted by this policy.

    choice | check-new | Continue to allow sessions already accepted by this policy.

  • Required: False

  • choices: [‘check-all’, ‘check-new’]

fixedport
  • Description: Enable to prevent source NAT from changing a session’s source port.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

fsso
  • Description: Enable/disable Fortinet Single Sign-On.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

fsso_agent_for_ntlm
  • Description: FSSO agent to use for NTLM authentication.
  • Required: False
global_label
  • Description: Label for the policy that appears when the GUI is in Global View mode.
  • Required: False
groups
  • Description: Names of user groups that can authenticate with this policy.
  • Required: False
gtp_profile
  • Description: GTP profile.
  • Required: False
icap_profile
  • Description: Name of an existing ICAP profile.
  • Required: False
identity_based_route
  • Description: Name of identity-based routing rule.
  • Required: False
inbound
  • Description: Policy-based IPsec VPN | only traffic from the remote network can initiate a VPN.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

internet_service
  • Description: Enable/disable use of Internet Services for this policy. If enabled, dstaddr and service are not used.

    choice | disable | Disable use of Internet Services in policy.

    choice | enable | Enable use of Internet Services in policy.

  • Required: False

  • choices: [‘disable’, ‘enable’]

internet_service_custom
  • Description: Custom Internet Service name.
  • Required: False
internet_service_id
  • Description: Internet Service ID.
  • Required: False
internet_service_negate
  • Description: When enabled internet-service specifies what the service must NOT be.

    choice | disable | Disable negated Internet Service match.

    choice | enable | Enable negated Internet Service match.

  • Required: False

  • choices: [‘disable’, ‘enable’]

internet_service_src
  • Description: Enable/disable use of Internet Services in source for this policy. If enabled, source address is not used.

    choice | disable | Disable use of Internet Services source in policy.

    choice | enable | Enable use of Internet Services source in policy.

  • Required: False

  • choices: [‘disable’, ‘enable’]

internet_service_src_custom
  • Description: Custom Internet Service source name.
  • Required: False
internet_service_src_id
  • Description: Internet Service source ID.
  • Required: False
internet_service_src_negate
  • Description: When enabled internet-service-src specifies what the service must NOT be.

    choice | disable | Disable negated Internet Service source match.

    choice | enable | Enable negated Internet Service source match.

  • Required: False

  • choices: [‘disable’, ‘enable’]

ippool
  • Description: Enable to use IP Pools for source NAT.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

ips_sensor
  • Description: Name of an existing IPS sensor.
  • Required: False
label
  • Description: Label for the policy that appears when the GUI is in Section View mode.
  • Required: False
learning_mode
  • Description: Enable to allow everything, but log all of the meaningful data for security information gathering.

    choice | disable | Disable learning mode in firewall policy.

    choice | enable | Enable learning mode in firewall policy.

  • Required: False

  • choices: [‘disable’, ‘enable’]

logtraffic
  • Description: Enable or disable logging. Log all sessions or security profile sessions.

    choice | disable | Disable all logging for this policy.

    choice | all | Log all sessions accepted or denied by this policy.

    choice | utm | Log traffic that has a security profile applied to it.

  • Required: False

  • choices: [‘disable’, ‘all’, ‘utm’]

logtraffic_start
  • Description: Record logs when a session starts and ends.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

match_vip
  • Description: Enable to match packets that have had their destination addresses changed by a VIP.

    choice | disable | Do not match DNATed packet.

    choice | enable | Match DNATed packet.

  • Required: False

  • choices: [‘disable’, ‘enable’]

mms_profile
  • Description: Name of an existing MMS profile.
  • Required: False
mode
  • Description: Sets one of three modes for managing the object.

    Allows use of soft-adds instead of overwriting existing values

  • Required: False

  • default: add

  • choices: [‘add’, ‘set’, ‘delete’, ‘update’]

name
  • Description: Policy name.
  • Required: False
nat
  • Description: Enable/disable source NAT.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

natinbound
  • Description: Policy-based IPsec VPN | apply destination NAT to inbound traffic.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

natip
  • Description: Policy-based IPsec VPN | source NAT IP address for outgoing traffic.
  • Required: False
natoutbound
  • Description: Policy-based IPsec VPN | apply source NAT to outbound traffic.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

np_acceleration
  • Description: Enable/disable UTM Network Processor acceleration.

    choice | disable | Disable UTM Network Processor acceleration.

    choice | enable | Enable UTM Network Processor acceleration.

  • Required: False

  • choices: [‘disable’, ‘enable’]

ntlm
  • Description: Enable/disable NTLM authentication.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

ntlm_enabled_browsers
  • Description: HTTP-User-Agent value of supported browsers.
  • Required: False
ntlm_guest
  • Description: Enable/disable NTLM guest user access.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

outbound
  • Description: Policy-based IPsec VPN | only traffic from the internal network can initiate a VPN.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

package_name
  • Description: The policy package you want to modify
  • Required: False
  • default: default
per_ip_shaper
  • Description: Per-IP traffic shaper.
  • Required: False
permit_any_host
  • Description: Accept UDP packets from any host.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

permit_stun_host
  • Description: Accept UDP packets from any Session Traversal Utilities for NAT (STUN) host.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

policyid
  • Description: Policy ID.
  • Required: False
poolname
  • Description: IP Pool names.
  • Required: False
profile_group
  • Description: Name of profile group.
  • Required: False
profile_protocol_options
  • Description: Name of an existing Protocol options profile.
  • Required: False
profile_type
  • Description: Determine whether the firewall policy allows security profile groups or single profiles only.

    choice | single | Do not allow security profile groups.

    choice | group | Allow security profile groups.

  • Required: False

  • choices: [‘single’, ‘group’]

radius_mac_auth_bypass
  • Description: Enable MAC authentication bypass. The bypassed MAC address must be received from RADIUS server.

    choice | disable | Disable MAC authentication bypass.

    choice | enable | Enable MAC authentication bypass.

  • Required: False

  • choices: [‘disable’, ‘enable’]

redirect_url
  • Description: URL users are directed to after seeing and accepting the disclaimer or authenticating.
  • Required: False
replacemsg_override_group
  • Description: Override the default replacement message group for this policy.
  • Required: False
rsso
  • Description: Enable/disable RADIUS single sign-on (RSSO).

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

rtp_addr
  • Description: Address names if this is an RTP NAT policy.
  • Required: False
rtp_nat
  • Description: Enable Real Time Protocol (RTP) NAT.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

scan_botnet_connections
  • Description: Block or monitor connections to Botnet servers or disable Botnet scanning.

    choice | disable | Do not scan connections to botnet servers.

    choice | block | Block connections to botnet servers.

    choice | monitor | Log connections to botnet servers.

  • Required: False

  • choices: [‘disable’, ‘block’, ‘monitor’]

schedule
  • Description: Schedule name.
  • Required: False
schedule_timeout
  • Description: Enable to force current sessions to end when the schedule object times out.

    choice | disable | Disable schedule timeout.

    choice | enable | Enable schedule timeout.

  • Required: False

  • choices: [‘disable’, ‘enable’]

send_deny_packet
  • Description: Enable to send a reply when a session is denied or blocked by a firewall policy.

    choice | disable | Disable deny-packet sending.

    choice | enable | Enable deny-packet sending.

  • Required: False

  • choices: [‘disable’, ‘enable’]

service
  • Description: Service and service group names.
  • Required: False
service_negate
  • Description: When enabled service specifies what the service must NOT be.

    choice | disable | Disable negated service match.

    choice | enable | Enable negated service match.

  • Required: False

  • choices: [‘disable’, ‘enable’]

session_ttl
  • Description: TTL in seconds for sessions accepted by this policy (0 means use the system default session TTL).
  • Required: False
spamfilter_profile
  • Description: Name of an existing Spam filter profile.
  • Required: False
srcaddr
  • Description: Source address and address group names.
  • Required: False
srcaddr_negate
  • Description: When enabled srcaddr specifies what the source address must NOT be.

    choice | disable | Disable source address negate.

    choice | enable | Enable source address negate.

  • Required: False

  • choices: [‘disable’, ‘enable’]

srcintf
  • Description: Incoming (ingress) interface.
  • Required: False
ssh_filter_profile
  • Description: Name of an existing SSH filter profile.
  • Required: False
ssl_mirror
  • Description: Enable to copy decrypted SSL traffic to a FortiGate interface (called SSL mirroring).

    choice | disable | Disable SSL mirror.

    choice | enable | Enable SSL mirror.

  • Required: False

  • choices: [‘disable’, ‘enable’]

ssl_mirror_intf
  • Description: SSL mirror interface name.
  • Required: False
ssl_ssh_profile
  • Description: Name of an existing SSL SSH profile.
  • Required: False
status
  • Description: Enable or disable this policy.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

tcp_mss_receiver
  • Description: Receiver TCP maximum segment size (MSS).
  • Required: False
tcp_mss_sender
  • Description: Sender TCP maximum segment size (MSS).
  • Required: False
tcp_session_without_syn
  • Description: Enable/disable creation of TCP session without SYN flag.

    choice | all | Enable TCP session without SYN.

    choice | data-only | Enable TCP session data only.

    choice | disable | Disable TCP session without SYN.

  • Required: False

  • choices: [‘all’, ‘data-only’, ‘disable’]

timeout_send_rst
  • Description: Enable/disable sending RST packets when TCP sessions expire.

    choice | disable | Disable sending of RST packet upon TCP session expiration.

    choice | enable | Enable sending of RST packet upon TCP session expiration.

  • Required: False

  • choices: [‘disable’, ‘enable’]

traffic_shaper
  • Description: Traffic shaper.
  • Required: False
traffic_shaper_reverse
  • Description: Reverse traffic shaper.
  • Required: False
url_category
  • Description: URL category ID list.
  • Required: False
users
  • Description: Names of individual users that can authenticate with this policy.
  • Required: False
utm_status
  • Description: Enable to add one or more security profiles (AV, IPS, etc.) to the firewall policy.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

vlan_cos_fwd
  • Description: VLAN forward direction user priority | 255 passthrough, 0 lowest, 7 highest.
  • Required: False
vlan_cos_rev
  • Description: VLAN reverse direction user priority | 255 passthrough, 0 lowest, 7 highest..
  • Required: False
vlan_filter
  • Description: Set VLAN filters.
  • Required: False
voip_profile
  • Description: Name of an existing VoIP profile.
  • Required: False
vpn_dst_node
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED. This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

  • Required: False

vpn_dst_node_host
  • Description: VPN Destination Node Host.
  • Required: False
vpn_dst_node_seq
  • Description: VPN Destination Node Seq.
  • Required: False
vpn_dst_node_subnet
  • Description: VPN Destination Node Seq.
  • Required: False
vpn_src_node
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED. This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

  • Required: False

vpn_src_node_host
  • Description: VPN Source Node Host.
  • Required: False
vpn_src_node_seq
  • Description: VPN Source Node Seq.
  • Required: False
vpn_src_node_subnet
  • Description: VPN Source Node.
  • Required: False
vpntunnel
  • Description: Policy-based IPsec VPN | name of the IPsec VPN Phase 1.
  • Required: False
waf_profile
  • Description: Name of an existing Web application firewall profile.
  • Required: False
wanopt
  • Description: Enable/disable WAN optimization.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

wanopt_detection
  • Description: WAN optimization auto-detection mode.

    choice | active | Active WAN optimization peer auto-detection.

    choice | passive | Passive WAN optimization peer auto-detection.

    choice | off | Turn off WAN optimization peer auto-detection.

  • Required: False

  • choices: [‘active’, ‘passive’, ‘off’]

wanopt_passive_opt
  • Description: WAN optimization passive mode options. This option decides what IP address will be used to connect server.

    choice | default | Allow client side WAN opt peer to decide.

    choice | transparent | Use address of client to connect to server.

    choice | non-transparent | Use local FortiGate address to connect to server.

  • Required: False

  • choices: [‘default’, ‘transparent’, ‘non-transparent’]

wanopt_peer
  • Description: WAN optimization peer.
  • Required: False
wanopt_profile
  • Description: WAN optimization profile.
  • Required: False
wccp
  • Description: Enable/disable forwarding traffic matching this policy to a configured WCCP server.

    choice | disable | Disable WCCP setting.

    choice | enable | Enable WCCP setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

webcache
  • Description: Enable/disable web cache.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

webcache_https
  • Description: Enable/disable web cache for HTTPS.

    choice | disable | Disable web cache for HTTPS.

    choice | enable | Enable web cache for HTTPS.

  • Required: False

  • choices: [‘disable’, ‘enable’]

webfilter_profile
  • Description: Name of an existing Web filter profile.
  • Required: False
wsso
  • Description: Enable/disable WiFi Single Sign On (WSSO).

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

Functions
  • fmgr_firewall_policy_modify
def fmgr_firewall_policy_modify(fmgr, paramgram):
    """
    fmgr_firewall_policy -- Add/Set/Deletes Firewall Policy Objects defined in the "paramgram"

    :param fmgr: The fmgr object instance from fmgr_utils.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict

    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/pkg/{pkg}/firewall/policy'.format(adom=adom, pkg=paramgram["package_name"])
        datagram = scrub_dict((prepare_dict(paramgram)))
        del datagram["package_name"]
        datagram = fmgr._tools.split_comma_strings_into_lists(datagram)

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        url = '/pm/config/adom/{adom}/pkg/{pkg}/firewall' \
              '/policy/{policyid}'.format(adom=paramgram["adom"],
                                          pkg=paramgram["package_name"],
                                          policyid=paramgram["policyid"])
        datagram = {
            "policyid": paramgram["policyid"]
        }

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


#############
# END METHODS
#############
  • main
def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),
        package_name=dict(type="str", required=False, default="default"),

        wsso=dict(required=False, type="str", choices=["disable", "enable"]),
        webfilter_profile=dict(required=False, type="str"),
        webcache_https=dict(required=False, type="str", choices=["disable", "enable"]),
        webcache=dict(required=False, type="str", choices=["disable", "enable"]),
        wccp=dict(required=False, type="str", choices=["disable", "enable"]),
        wanopt_profile=dict(required=False, type="str"),
        wanopt_peer=dict(required=False, type="str"),
        wanopt_passive_opt=dict(required=False, type="str", choices=["default", "transparent", "non-transparent"]),
        wanopt_detection=dict(required=False, type="str", choices=["active", "passive", "off"]),
        wanopt=dict(required=False, type="str", choices=["disable", "enable"]),
        waf_profile=dict(required=False, type="str"),
        vpntunnel=dict(required=False, type="str"),
        voip_profile=dict(required=False, type="str"),
        vlan_filter=dict(required=False, type="str"),
        vlan_cos_rev=dict(required=False, type="int"),
        vlan_cos_fwd=dict(required=False, type="int"),
        utm_status=dict(required=False, type="str", choices=["disable", "enable"]),
        users=dict(required=False, type="str"),
        url_category=dict(required=False, type="str"),
        traffic_shaper_reverse=dict(required=False, type="str"),
        traffic_shaper=dict(required=False, type="str"),
        timeout_send_rst=dict(required=False, type="str", choices=["disable", "enable"]),
        tcp_session_without_syn=dict(required=False, type="str", choices=["all", "data-only", "disable"]),
        tcp_mss_sender=dict(required=False, type="int"),
        tcp_mss_receiver=dict(required=False, type="int"),
        status=dict(required=False, type="str", choices=["disable", "enable"]),
        ssl_ssh_profile=dict(required=False, type="str"),
        ssl_mirror_intf=dict(required=False, type="str"),
        ssl_mirror=dict(required=False, type="str", choices=["disable", "enable"]),
        ssh_filter_profile=dict(required=False, type="str"),
        srcintf=dict(required=False, type="str"),
        srcaddr_negate=dict(required=False, type="str", choices=["disable", "enable"]),
        srcaddr=dict(required=False, type="str"),
        spamfilter_profile=dict(required=False, type="str"),
        session_ttl=dict(required=False, type="int"),
        service_negate=dict(required=False, type="str", choices=["disable", "enable"]),
        service=dict(required=False, type="str"),
        send_deny_packet=dict(required=False, type="str", choices=["disable", "enable"]),
        schedule_timeout=dict(required=False, type="str", choices=["disable", "enable"]),
        schedule=dict(required=False, type="str"),
        scan_botnet_connections=dict(required=False, type="str", choices=["disable", "block", "monitor"]),
        rtp_nat=dict(required=False, type="str", choices=["disable", "enable"]),
        rtp_addr=dict(required=False, type="str"),
        rsso=dict(required=False, type="str", choices=["disable", "enable"]),
        replacemsg_override_group=dict(required=False, type="str"),
        redirect_url=dict(required=False, type="str"),
        radius_mac_auth_bypass=dict(required=False, type="str", choices=["disable", "enable"]),
        profile_type=dict(required=False, type="str", choices=["single", "group"]),
        profile_protocol_options=dict(required=False, type="str"),
        profile_group=dict(required=False, type="str"),
        poolname=dict(required=False, type="str"),
        policyid=dict(required=False, type="str"),
        permit_stun_host=dict(required=False, type="str", choices=["disable", "enable"]),
        permit_any_host=dict(required=False, type="str", choices=["disable", "enable"]),
        per_ip_shaper=dict(required=False, type="str"),
        outbound=dict(required=False, type="str", choices=["disable", "enable"]),
        ntlm_guest=dict(required=False, type="str", choices=["disable", "enable"]),
        ntlm_enabled_browsers=dict(required=False, type="str"),
        ntlm=dict(required=False, type="str", choices=["disable", "enable"]),
        np_acceleration=dict(required=False, type="str", choices=["disable", "enable"]),
        natoutbound=dict(required=False, type="str", choices=["disable", "enable"]),
        natip=dict(required=False, type="str"),
        natinbound=dict(required=False, type="str", choices=["disable", "enable"]),
        nat=dict(required=False, type="str", choices=["disable", "enable"]),
        name=dict(required=False, type="str"),
        mms_profile=dict(required=False, type="str"),
        match_vip=dict(required=False, type="str", choices=["disable", "enable"]),
        logtraffic_start=dict(required=False, type="str", choices=["disable", "enable"]),
        logtraffic=dict(required=False, type="str", choices=["disable", "all", "utm"]),
        learning_mode=dict(required=False, type="str", choices=["disable", "enable"]),
        label=dict(required=False, type="str"),
        ips_sensor=dict(required=False, type="str"),
        ippool=dict(required=False, type="str", choices=["disable", "enable"]),
        internet_service_src_negate=dict(required=False, type="str", choices=["disable", "enable"]),
        internet_service_src_id=dict(required=False, type="str"),
        internet_service_src_custom=dict(required=False, type="str"),
        internet_service_src=dict(required=False, type="str", choices=["disable", "enable"]),
        internet_service_negate=dict(required=False, type="str", choices=["disable", "enable"]),
        internet_service_id=dict(required=False, type="str"),
        internet_service_custom=dict(required=False, type="str"),
        internet_service=dict(required=False, type="str", choices=["disable", "enable"]),
        inbound=dict(required=False, type="str", choices=["disable", "enable"]),
        identity_based_route=dict(required=False, type="str"),
        icap_profile=dict(required=False, type="str"),
        gtp_profile=dict(required=False, type="str"),
        groups=dict(required=False, type="str"),
        global_label=dict(required=False, type="str"),
        fsso_agent_for_ntlm=dict(required=False, type="str"),
        fsso=dict(required=False, type="str", choices=["disable", "enable"]),
        fixedport=dict(required=False, type="str", choices=["disable", "enable"]),
        firewall_session_dirty=dict(required=False, type="str", choices=["check-all", "check-new"]),
        dstintf=dict(required=False, type="str"),
        dstaddr_negate=dict(required=False, type="str", choices=["disable", "enable"]),
        dstaddr=dict(required=False, type="str"),
        dsri=dict(required=False, type="str", choices=["disable", "enable"]),
        dscp_value=dict(required=False, type="str"),
        dscp_negate=dict(required=False, type="str", choices=["disable", "enable"]),
        dscp_match=dict(required=False, type="str", choices=["disable", "enable"]),
        dnsfilter_profile=dict(required=False, type="str"),
        dlp_sensor=dict(required=False, type="str"),
        disclaimer=dict(required=False, type="str", choices=["disable", "enable"]),
        diffservcode_rev=dict(required=False, type="str"),
        diffservcode_forward=dict(required=False, type="str"),
        diffserv_reverse=dict(required=False, type="str", choices=["disable", "enable"]),
        diffserv_forward=dict(required=False, type="str", choices=["disable", "enable"]),
        devices=dict(required=False, type="str"),
        delay_tcp_npu_session=dict(required=False, type="str", choices=["disable", "enable"]),
        custom_log_fields=dict(required=False, type="str"),
        comments=dict(required=False, type="str"),
        capture_packet=dict(required=False, type="str", choices=["disable", "enable"]),
        captive_portal_exempt=dict(required=False, type="str", choices=["disable", "enable"]),
        block_notification=dict(required=False, type="str", choices=["disable", "enable"]),
        av_profile=dict(required=False, type="str"),
        auto_asic_offload=dict(required=False, type="str", choices=["disable", "enable"]),
        auth_redirect_addr=dict(required=False, type="str"),
        auth_path=dict(required=False, type="str", choices=["disable", "enable"]),
        auth_cert=dict(required=False, type="str"),
        application_list=dict(required=False, type="str"),
        application=dict(required=False, type="str"),
        app_group=dict(required=False, type="str"),
        app_category=dict(required=False, type="str"),
        action=dict(required=False, type="str", choices=["deny", "accept", "ipsec"]),
        vpn_dst_node=dict(required=False, type="list"),
        vpn_dst_node_host=dict(required=False, type="str"),
        vpn_dst_node_seq=dict(required=False, type="str"),
        vpn_dst_node_subnet=dict(required=False, type="str"),
        vpn_src_node=dict(required=False, type="list"),
        vpn_src_node_host=dict(required=False, type="str"),
        vpn_src_node_seq=dict(required=False, type="str"),
        vpn_src_node_subnet=dict(required=False, type="str"),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "package_name": module.params["package_name"],
        "wsso": module.params["wsso"],
        "webfilter-profile": module.params["webfilter_profile"],
        "webcache-https": module.params["webcache_https"],
        "webcache": module.params["webcache"],
        "wccp": module.params["wccp"],
        "wanopt-profile": module.params["wanopt_profile"],
        "wanopt-peer": module.params["wanopt_peer"],
        "wanopt-passive-opt": module.params["wanopt_passive_opt"],
        "wanopt-detection": module.params["wanopt_detection"],
        "wanopt": module.params["wanopt"],
        "waf-profile": module.params["waf_profile"],
        "vpntunnel": module.params["vpntunnel"],
        "voip-profile": module.params["voip_profile"],
        "vlan-filter": module.params["vlan_filter"],
        "vlan-cos-rev": module.params["vlan_cos_rev"],
        "vlan-cos-fwd": module.params["vlan_cos_fwd"],
        "utm-status": module.params["utm_status"],
        "users": module.params["users"],
        "url-category": module.params["url_category"],
        "traffic-shaper-reverse": module.params["traffic_shaper_reverse"],
        "traffic-shaper": module.params["traffic_shaper"],
        "timeout-send-rst": module.params["timeout_send_rst"],
        "tcp-session-without-syn": module.params["tcp_session_without_syn"],
        "tcp-mss-sender": module.params["tcp_mss_sender"],
        "tcp-mss-receiver": module.params["tcp_mss_receiver"],
        "status": module.params["status"],
        "ssl-ssh-profile": module.params["ssl_ssh_profile"],
        "ssl-mirror-intf": module.params["ssl_mirror_intf"],
        "ssl-mirror": module.params["ssl_mirror"],
        "ssh-filter-profile": module.params["ssh_filter_profile"],
        "srcintf": module.params["srcintf"],
        "srcaddr-negate": module.params["srcaddr_negate"],
        "srcaddr": module.params["srcaddr"],
        "spamfilter-profile": module.params["spamfilter_profile"],
        "session-ttl": module.params["session_ttl"],
        "service-negate": module.params["service_negate"],
        "service": module.params["service"],
        "send-deny-packet": module.params["send_deny_packet"],
        "schedule-timeout": module.params["schedule_timeout"],
        "schedule": module.params["schedule"],
        "scan-botnet-connections": module.params["scan_botnet_connections"],
        "rtp-nat": module.params["rtp_nat"],
        "rtp-addr": module.params["rtp_addr"],
        "rsso": module.params["rsso"],
        "replacemsg-override-group": module.params["replacemsg_override_group"],
        "redirect-url": module.params["redirect_url"],
        "radius-mac-auth-bypass": module.params["radius_mac_auth_bypass"],
        "profile-type": module.params["profile_type"],
        "profile-protocol-options": module.params["profile_protocol_options"],
        "profile-group": module.params["profile_group"],
        "poolname": module.params["poolname"],
        "policyid": module.params["policyid"],
        "permit-stun-host": module.params["permit_stun_host"],
        "permit-any-host": module.params["permit_any_host"],
        "per-ip-shaper": module.params["per_ip_shaper"],
        "outbound": module.params["outbound"],
        "ntlm-guest": module.params["ntlm_guest"],
        "ntlm-enabled-browsers": module.params["ntlm_enabled_browsers"],
        "ntlm": module.params["ntlm"],
        "np-acceleration": module.params["np_acceleration"],
        "natoutbound": module.params["natoutbound"],
        "natip": module.params["natip"],
        "natinbound": module.params["natinbound"],
        "nat": module.params["nat"],
        "name": module.params["name"],
        "mms-profile": module.params["mms_profile"],
        "match-vip": module.params["match_vip"],
        "logtraffic-start": module.params["logtraffic_start"],
        "logtraffic": module.params["logtraffic"],
        "learning-mode": module.params["learning_mode"],
        "label": module.params["label"],
        "ips-sensor": module.params["ips_sensor"],
        "ippool": module.params["ippool"],
        "internet-service-src-negate": module.params["internet_service_src_negate"],
        "internet-service-src-id": module.params["internet_service_src_id"],
        "internet-service-src-custom": module.params["internet_service_src_custom"],
        "internet-service-src": module.params["internet_service_src"],
        "internet-service-negate": module.params["internet_service_negate"],
        "internet-service-id": module.params["internet_service_id"],
        "internet-service-custom": module.params["internet_service_custom"],
        "internet-service": module.params["internet_service"],
        "inbound": module.params["inbound"],
        "identity-based-route": module.params["identity_based_route"],
        "icap-profile": module.params["icap_profile"],
        "gtp-profile": module.params["gtp_profile"],
        "groups": module.params["groups"],
        "global-label": module.params["global_label"],
        "fsso-agent-for-ntlm": module.params["fsso_agent_for_ntlm"],
        "fsso": module.params["fsso"],
        "fixedport": module.params["fixedport"],
        "firewall-session-dirty": module.params["firewall_session_dirty"],
        "dstintf": module.params["dstintf"],
        "dstaddr-negate": module.params["dstaddr_negate"],
        "dstaddr": module.params["dstaddr"],
        "dsri": module.params["dsri"],
        "dscp-value": module.params["dscp_value"],
        "dscp-negate": module.params["dscp_negate"],
        "dscp-match": module.params["dscp_match"],
        "dnsfilter-profile": module.params["dnsfilter_profile"],
        "dlp-sensor": module.params["dlp_sensor"],
        "disclaimer": module.params["disclaimer"],
        "diffservcode-rev": module.params["diffservcode_rev"],
        "diffservcode-forward": module.params["diffservcode_forward"],
        "diffserv-reverse": module.params["diffserv_reverse"],
        "diffserv-forward": module.params["diffserv_forward"],
        "devices": module.params["devices"],
        "delay-tcp-npu-session": module.params["delay_tcp_npu_session"],
        "custom-log-fields": module.params["custom_log_fields"],
        "comments": module.params["comments"],
        "capture-packet": module.params["capture_packet"],
        "captive-portal-exempt": module.params["captive_portal_exempt"],
        "block-notification": module.params["block_notification"],
        "av-profile": module.params["av_profile"],
        "auto-asic-offload": module.params["auto_asic_offload"],
        "auth-redirect-addr": module.params["auth_redirect_addr"],
        "auth-path": module.params["auth_path"],
        "auth-cert": module.params["auth_cert"],
        "application-list": module.params["application_list"],
        "application": module.params["application"],
        "app-group": module.params["app_group"],
        "app-category": module.params["app_category"],
        "action": module.params["action"],
        "vpn_dst_node": {
            "host": module.params["vpn_dst_node_host"],
            "seq": module.params["vpn_dst_node_seq"],
            "subnet": module.params["vpn_dst_node_subnet"],
        },
        "vpn_src_node": {
            "host": module.params["vpn_src_node_host"],
            "seq": module.params["vpn_src_node_seq"],
            "subnet": module.params["vpn_src_node_subnet"],
        }
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['vpn_dst_node', 'vpn_src_node']
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)

    # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION
    results = DEFAULT_RESULT_OBJ
    try:
        if paramgram["mode"] == "delete":
            # WE NEED TO GET THE POLICY ID FROM THE NAME OF THE POLICY TO DELETE IT
            url = '/pm/config/adom/{adom}/pkg/{pkg}/firewall' \
                  '/policy/'.format(adom=paramgram["adom"],
                                    pkg=paramgram["package_name"])
            datagram = {
                "filter": ["name", "==", paramgram["name"]]
            }
            response = fmgr.process_request(url, datagram, FMGRMethods.GET)
            try:
                if response[1][0]["policyid"]:
                    policy_id = response[1][0]["policyid"]
                    paramgram["policyid"] = policy_id
            except BaseException:
                fmgr.return_response(module=module, results=response, good_codes=[0, ], stop_on_success=True,
                                     ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram),
                                     msg="Couldn't find policy ID number for policy name specified.")
    except Exception as err:
        raise FMGBaseException(err)

    try:
        results = fmgr_firewall_policy_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results, good_codes=[0, -9998],
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function

__metaclass__ = type

ANSIBLE_METADATA = {'status': ['preview'],
                    'supported_by': 'community',
                    'metadata_version': '1.1'}

DOCUMENTATION = '''
---
module: fmgr_fwpol_ipv4
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author:
    - Luke Weighall (@lweighall)
    - Andrew Welsh (@Ghilli3)
    - Jim Huber (@p4r4n0y1ng)
short_description: Allows the add/delete of Firewall Policies on Packages in FortiManager.
description:
  -  Allows the add/delete of Firewall Policies on Packages in FortiManager.

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: false
    default: root

  mode:
    description:
      - Sets one of three modes for managing the object.
      - Allows use of soft-adds instead of overwriting existing values
    choices: ['add', 'set', 'delete', 'update']
    required: false
    default: add

  package_name:
    description:
      - The policy package you want to modify
    required: false
    default: "default"

  wsso:
    description:
      - Enable/disable WiFi Single Sign On (WSSO).
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  webfilter_profile:
    description:
      - Name of an existing Web filter profile.
    required: false

  webcache_https:
    description:
      - Enable/disable web cache for HTTPS.
      - choice | disable | Disable web cache for HTTPS.
      - choice | enable | Enable web cache for HTTPS.
    required: false
    choices: ["disable", "enable"]

  webcache:
    description:
      - Enable/disable web cache.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  wccp:
    description:
      - Enable/disable forwarding traffic matching this policy to a configured WCCP server.
      - choice | disable | Disable WCCP setting.
      - choice | enable | Enable WCCP setting.
    required: false
    choices: ["disable", "enable"]

  wanopt_profile:
    description:
      - WAN optimization profile.
    required: false

  wanopt_peer:
    description:
      - WAN optimization peer.
    required: false

  wanopt_passive_opt:
    description:
      - WAN optimization passive mode options. This option decides what IP address will be used to connect server.
      - choice | default | Allow client side WAN opt peer to decide.
      - choice | transparent | Use address of client to connect to server.
      - choice | non-transparent | Use local FortiGate address to connect to server.
    required: false
    choices: ["default", "transparent", "non-transparent"]

  wanopt_detection:
    description:
      - WAN optimization auto-detection mode.
      - choice | active | Active WAN optimization peer auto-detection.
      - choice | passive | Passive WAN optimization peer auto-detection.
      - choice | off | Turn off WAN optimization peer auto-detection.
    required: false
    choices: ["active", "passive", "off"]

  wanopt:
    description:
      - Enable/disable WAN optimization.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  waf_profile:
    description:
      - Name of an existing Web application firewall profile.
    required: false

  vpntunnel:
    description:
      - Policy-based IPsec VPN |  name of the IPsec VPN Phase 1.
    required: false

  voip_profile:
    description:
      - Name of an existing VoIP profile.
    required: false

  vlan_filter:
    description:
      - Set VLAN filters.
    required: false

  vlan_cos_rev:
    description:
      - VLAN reverse direction user priority | 255 passthrough, 0 lowest, 7 highest..
    required: false

  vlan_cos_fwd:
    description:
      - VLAN forward direction user priority | 255 passthrough, 0 lowest, 7 highest.
    required: false

  utm_status:
    description:
      - Enable to add one or more security profiles (AV, IPS, etc.) to the firewall policy.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  users:
    description:
      - Names of individual users that can authenticate with this policy.
    required: false

  url_category:
    description:
      - URL category ID list.
    required: false

  traffic_shaper_reverse:
    description:
      - Reverse traffic shaper.
    required: false

  traffic_shaper:
    description:
      - Traffic shaper.
    required: false

  timeout_send_rst:
    description:
      - Enable/disable sending RST packets when TCP sessions expire.
      - choice | disable | Disable sending of RST packet upon TCP session expiration.
      - choice | enable | Enable sending of RST packet upon TCP session expiration.
    required: false
    choices: ["disable", "enable"]

  tcp_session_without_syn:
    description:
      - Enable/disable creation of TCP session without SYN flag.
      - choice | all | Enable TCP session without SYN.
      - choice | data-only | Enable TCP session data only.
      - choice | disable | Disable TCP session without SYN.
    required: false
    choices: ["all", "data-only", "disable"]

  tcp_mss_sender:
    description:
      - Sender TCP maximum segment size (MSS).
    required: false

  tcp_mss_receiver:
    description:
      - Receiver TCP maximum segment size (MSS).
    required: false

  status:
    description:
      - Enable or disable this policy.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  ssl_ssh_profile:
    description:
      - Name of an existing SSL SSH profile.
    required: false

  ssl_mirror_intf:
    description:
      - SSL mirror interface name.
    required: false

  ssl_mirror:
    description:
      - Enable to copy decrypted SSL traffic to a FortiGate interface (called SSL mirroring).
      - choice | disable | Disable SSL mirror.
      - choice | enable | Enable SSL mirror.
    required: false
    choices: ["disable", "enable"]

  ssh_filter_profile:
    description:
      - Name of an existing SSH filter profile.
    required: false

  srcintf:
    description:
      - Incoming (ingress) interface.
    required: false

  srcaddr_negate:
    description:
      - When enabled srcaddr specifies what the source address must NOT be.
      - choice | disable | Disable source address negate.
      - choice | enable | Enable source address negate.
    required: false
    choices: ["disable", "enable"]

  srcaddr:
    description:
      - Source address and address group names.
    required: false

  spamfilter_profile:
    description:
      - Name of an existing Spam filter profile.
    required: false

  session_ttl:
    description:
      - TTL in seconds for sessions accepted by this policy (0 means use the system default session TTL).
    required: false

  service_negate:
    description:
      - When enabled service specifies what the service must NOT be.
      - choice | disable | Disable negated service match.
      - choice | enable | Enable negated service match.
    required: false
    choices: ["disable", "enable"]

  service:
    description:
      - Service and service group names.
    required: false

  send_deny_packet:
    description:
      - Enable to send a reply when a session is denied or blocked by a firewall policy.
      - choice | disable | Disable deny-packet sending.
      - choice | enable | Enable deny-packet sending.
    required: false
    choices: ["disable", "enable"]

  schedule_timeout:
    description:
      - Enable to force current sessions to end when the schedule object times out.
      - choice | disable | Disable schedule timeout.
      - choice | enable | Enable schedule timeout.
    required: false
    choices: ["disable", "enable"]

  schedule:
    description:
      - Schedule name.
    required: false

  scan_botnet_connections:
    description:
      - Block or monitor connections to Botnet servers or disable Botnet scanning.
      - choice | disable | Do not scan connections to botnet servers.
      - choice | block | Block connections to botnet servers.
      - choice | monitor | Log connections to botnet servers.
    required: false
    choices: ["disable", "block", "monitor"]

  rtp_nat:
    description:
      - Enable Real Time Protocol (RTP) NAT.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  rtp_addr:
    description:
      - Address names if this is an RTP NAT policy.
    required: false

  rsso:
    description:
      - Enable/disable RADIUS single sign-on (RSSO).
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  replacemsg_override_group:
    description:
      - Override the default replacement message group for this policy.
    required: false

  redirect_url:
    description:
      - URL users are directed to after seeing and accepting the disclaimer or authenticating.
    required: false

  radius_mac_auth_bypass:
    description:
      - Enable MAC authentication bypass. The bypassed MAC address must be received from RADIUS server.
      - choice | disable | Disable MAC authentication bypass.
      - choice | enable | Enable MAC authentication bypass.
    required: false
    choices: ["disable", "enable"]

  profile_type:
    description:
      - Determine whether the firewall policy allows security profile groups or single profiles only.
      - choice | single | Do not allow security profile groups.
      - choice | group | Allow security profile groups.
    required: false
    choices: ["single", "group"]

  profile_protocol_options:
    description:
      - Name of an existing Protocol options profile.
    required: false

  profile_group:
    description:
      - Name of profile group.
    required: false

  poolname:
    description:
      - IP Pool names.
    required: false

  policyid:
    description:
      - Policy ID.
    required: false

  permit_stun_host:
    description:
      - Accept UDP packets from any Session Traversal Utilities for NAT (STUN) host.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  permit_any_host:
    description:
      - Accept UDP packets from any host.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  per_ip_shaper:
    description:
      - Per-IP traffic shaper.
    required: false

  outbound:
    description:
      - Policy-based IPsec VPN |  only traffic from the internal network can initiate a VPN.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  ntlm_guest:
    description:
      - Enable/disable NTLM guest user access.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  ntlm_enabled_browsers:
    description:
      - HTTP-User-Agent value of supported browsers.
    required: false

  ntlm:
    description:
      - Enable/disable NTLM authentication.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  np_acceleration:
    description:
      - Enable/disable UTM Network Processor acceleration.
      - choice | disable | Disable UTM Network Processor acceleration.
      - choice | enable | Enable UTM Network Processor acceleration.
    required: false
    choices: ["disable", "enable"]

  natoutbound:
    description:
      - Policy-based IPsec VPN |  apply source NAT to outbound traffic.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  natip:
    description:
      - Policy-based IPsec VPN |  source NAT IP address for outgoing traffic.
    required: false

  natinbound:
    description:
      - Policy-based IPsec VPN |  apply destination NAT to inbound traffic.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  nat:
    description:
      - Enable/disable source NAT.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  name:
    description:
      - Policy name.
    required: false

  mms_profile:
    description:
      - Name of an existing MMS profile.
    required: false

  match_vip:
    description:
      - Enable to match packets that have had their destination addresses changed by a VIP.
      - choice | disable | Do not match DNATed packet.
      - choice | enable | Match DNATed packet.
    required: false
    choices: ["disable", "enable"]

  logtraffic_start:
    description:
      - Record logs when a session starts and ends.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  logtraffic:
    description:
      - Enable or disable logging. Log all sessions or security profile sessions.
      - choice | disable | Disable all logging for this policy.
      - choice | all | Log all sessions accepted or denied by this policy.
      - choice | utm | Log traffic that has a security profile applied to it.
    required: false
    choices: ["disable", "all", "utm"]

  learning_mode:
    description:
      - Enable to allow everything, but log all of the meaningful data for security information gathering.
      - choice | disable | Disable learning mode in firewall policy.
      - choice | enable | Enable learning mode in firewall policy.
    required: false
    choices: ["disable", "enable"]

  label:
    description:
      - Label for the policy that appears when the GUI is in Section View mode.
    required: false

  ips_sensor:
    description:
      - Name of an existing IPS sensor.
    required: false

  ippool:
    description:
      - Enable to use IP Pools for source NAT.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  internet_service_src_negate:
    description:
      - When enabled internet-service-src specifies what the service must NOT be.
      - choice | disable | Disable negated Internet Service source match.
      - choice | enable | Enable negated Internet Service source match.
    required: false
    choices: ["disable", "enable"]

  internet_service_src_id:
    description:
      - Internet Service source ID.
    required: false

  internet_service_src_custom:
    description:
      - Custom Internet Service source name.
    required: false

  internet_service_src:
    description:
      - Enable/disable use of Internet Services in source for this policy. If enabled, source address is not used.
      - choice | disable | Disable use of Internet Services source in policy.
      - choice | enable | Enable use of Internet Services source in policy.
    required: false
    choices: ["disable", "enable"]

  internet_service_negate:
    description:
      - When enabled internet-service specifies what the service must NOT be.
      - choice | disable | Disable negated Internet Service match.
      - choice | enable | Enable negated Internet Service match.
    required: false
    choices: ["disable", "enable"]

  internet_service_id:
    description:
      - Internet Service ID.
    required: false

  internet_service_custom:
    description:
      - Custom Internet Service name.
    required: false

  internet_service:
    description:
      - Enable/disable use of Internet Services for this policy. If enabled, dstaddr and service are not used.
      - choice | disable | Disable use of Internet Services in policy.
      - choice | enable | Enable use of Internet Services in policy.
    required: false
    choices: ["disable", "enable"]

  inbound:
    description:
      - Policy-based IPsec VPN |  only traffic from the remote network can initiate a VPN.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  identity_based_route:
    description:
      - Name of identity-based routing rule.
    required: false

  icap_profile:
    description:
      - Name of an existing ICAP profile.
    required: false

  gtp_profile:
    description:
      - GTP profile.
    required: false

  groups:
    description:
      - Names of user groups that can authenticate with this policy.
    required: false

  global_label:
    description:
      - Label for the policy that appears when the GUI is in Global View mode.
    required: false

  fsso_agent_for_ntlm:
    description:
      - FSSO agent to use for NTLM authentication.
    required: false

  fsso:
    description:
      - Enable/disable Fortinet Single Sign-On.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  fixedport:
    description:
      - Enable to prevent source NAT from changing a session's source port.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  firewall_session_dirty:
    description:
      - How to handle sessions if the configuration of this firewall policy changes.
      - choice | check-all | Flush all current sessions accepted by this policy.
      - choice | check-new | Continue to allow sessions already accepted by this policy.
    required: false
    choices: ["check-all", "check-new"]

  dstintf:
    description:
      - Outgoing (egress) interface.
    required: false

  dstaddr_negate:
    description:
      - When enabled dstaddr specifies what the destination address must NOT be.
      - choice | disable | Disable destination address negate.
      - choice | enable | Enable destination address negate.
    required: false
    choices: ["disable", "enable"]

  dstaddr:
    description:
      - Destination address and address group names.
    required: false

  dsri:
    description:
      - Enable DSRI to ignore HTTP server responses.
      - choice | disable | Disable DSRI.
      - choice | enable | Enable DSRI.
    required: false
    choices: ["disable", "enable"]

  dscp_value:
    description:
      - DSCP value.
    required: false

  dscp_negate:
    description:
      - Enable negated DSCP match.
      - choice | disable | Disable DSCP negate.
      - choice | enable | Enable DSCP negate.
    required: false
    choices: ["disable", "enable"]

  dscp_match:
    description:
      - Enable DSCP check.
      - choice | disable | Disable DSCP check.
      - choice | enable | Enable DSCP check.
    required: false
    choices: ["disable", "enable"]

  dnsfilter_profile:
    description:
      - Name of an existing DNS filter profile.
    required: false

  dlp_sensor:
    description:
      - Name of an existing DLP sensor.
    required: false

  disclaimer:
    description:
      - Enable/disable user authentication disclaimer.
      - choice | disable | Disable user authentication disclaimer.
      - choice | enable | Enable user authentication disclaimer.
    required: false
    choices: ["disable", "enable"]

  diffservcode_rev:
    description:
      - Change packet's reverse (reply) DiffServ to this value.
    required: false

  diffservcode_forward:
    description:
      - Change packet's DiffServ to this value.
    required: false

  diffserv_reverse:
    description:
      - Enable to change packet's reverse (reply) DiffServ values to the specified diffservcode-rev value.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  diffserv_forward:
    description:
      - Enable to change packet's DiffServ values to the specified diffservcode-forward value.
      - choice | disable | Disable WAN optimization.
      - choice | enable | Enable WAN optimization.
    required: false
    choices: ["disable", "enable"]

  devices:
    description:
      - Names of devices or device groups that can be matched by the policy.
    required: false

  delay_tcp_npu_session:
    description:
      - Enable TCP NPU session delay to guarantee packet order of 3-way handshake.
      - choice | disable | Disable TCP NPU session delay in order to guarantee packet order of 3-way handshake.
      - choice | enable | Enable TCP NPU session delay in order to guarantee packet order of 3-way handshake.
    required: false
    choices: ["disable", "enable"]

  custom_log_fields:
    description:
      - Custom fields to append to log messages for this policy.
    required: false

  comments:
    description:
      - Comment.
    required: false

  capture_packet:
    description:
      - Enable/disable capture packets.
      - choice | disable | Disable capture packets.
      - choice | enable | Enable capture packets.
    required: false
    choices: ["disable", "enable"]

  captive_portal_exempt:
    description:
      - Enable to exempt some users from the captive portal.
      - choice | disable | Disable exemption of captive portal.
      - choice | enable | Enable exemption of captive portal.
    required: false
    choices: ["disable", "enable"]

  block_notification:
    description:
      - Enable/disable block notification.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  av_profile:
    description:
      - Name of an existing Antivirus profile.
    required: false

  auto_asic_offload:
    description:
      - Enable/disable offloading security profile processing to CP processors.
      - choice | disable | Disable ASIC offloading.
      - choice | enable | Enable auto ASIC offloading.
    required: false
    choices: ["disable", "enable"]

  auth_redirect_addr:
    description:
      - HTTP-to-HTTPS redirect address for firewall authentication.
    required: false

  auth_path:
    description:
      - Enable/disable authentication-based routing.
      - choice | disable | Disable authentication-based routing.
      - choice | enable | Enable authentication-based routing.
    required: false
    choices: ["disable", "enable"]

  auth_cert:
    description:
      - HTTPS server certificate for policy authentication.
    required: false

  application_list:
    description:
      - Name of an existing Application list.
    required: false

  application:
    description:
      - Application ID list.
    required: false

  app_group:
    description:
      - Application group names.
    required: false

  app_category:
    description:
      - Application category ID list.
    required: false

  action:
    description:
      - Policy action (allow/deny/ipsec).
      - choice | deny | Blocks sessions that match the firewall policy.
      - choice | accept | Allows session that match the firewall policy.
      - choice | ipsec | Firewall policy becomes a policy-based IPsec VPN policy.
    required: false
    choices: ["deny", "accept", "ipsec"]

  vpn_dst_node:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED. This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
    required: false

  vpn_dst_node_host:
    description:
      - VPN Destination Node Host.
    required: false

  vpn_dst_node_seq:
    description:
      - VPN Destination Node Seq.
    required: false

  vpn_dst_node_subnet:
    description:
      - VPN Destination Node Seq.
    required: false

  vpn_src_node:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED. This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
    required: false

  vpn_src_node_host:
    description:
      - VPN Source Node Host.
    required: false

  vpn_src_node_seq:
    description:
      - VPN Source Node Seq.
    required: false

  vpn_src_node_subnet:
    description:
      - VPN Source Node.
    required: false


'''

EXAMPLES = '''
- name: ADD VERY BASIC IPV4 POLICY WITH NO NAT (WIDE OPEN)
  fmgr_fwpol_ipv4:
    mode: "set"
    adom: "ansible"
    package_name: "default"
    name: "Basic_IPv4_Policy"
    comments: "Created by Ansible"
    action: "accept"
    dstaddr: "all"
    srcaddr: "all"
    dstintf: "any"
    srcintf: "any"
    logtraffic: "utm"
    service: "ALL"
    schedule: "always"

- name: ADD VERY BASIC IPV4 POLICY WITH NAT AND MULTIPLE ENTRIES
  fmgr_fwpol_ipv4:
    mode: "set"
    adom: "ansible"
    package_name: "default"
    name: "Basic_IPv4_Policy_2"
    comments: "Created by Ansible"
    action: "accept"
    dstaddr: "google-play"
    srcaddr: "all"
    dstintf: "any"
    srcintf: "any"
    logtraffic: "utm"
    service: "HTTP, HTTPS"
    schedule: "always"
    nat: "enable"
    users: "karen, kevin"

- name: ADD VERY BASIC IPV4 POLICY WITH NAT AND MULTIPLE ENTRIES AND SEC PROFILES
  fmgr_fwpol_ipv4:
    mode: "set"
    adom: "ansible"
    package_name: "default"
    name: "Basic_IPv4_Policy_3"
    comments: "Created by Ansible"
    action: "accept"
    dstaddr: "google-play, autoupdate.opera.com"
    srcaddr: "corp_internal"
    dstintf: "zone_wan1, zone_wan2"
    srcintf: "zone_int1"
    logtraffic: "utm"
    service: "HTTP, HTTPS"
    schedule: "always"
    nat: "enable"
    users: "karen, kevin"
    av_profile: "sniffer-profile"
    ips_sensor: "default"

'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import FMGRMethods
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
from ansible.module_utils.network.fortimanager.common import prepare_dict
from ansible.module_utils.network.fortimanager.common import scrub_dict


def fmgr_firewall_policy_modify(fmgr, paramgram):
    """
    fmgr_firewall_policy -- Add/Set/Deletes Firewall Policy Objects defined in the "paramgram"

    :param fmgr: The fmgr object instance from fmgr_utils.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict

    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/pkg/{pkg}/firewall/policy'.format(adom=adom, pkg=paramgram["package_name"])
        datagram = scrub_dict((prepare_dict(paramgram)))
        del datagram["package_name"]
        datagram = fmgr._tools.split_comma_strings_into_lists(datagram)

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        url = '/pm/config/adom/{adom}/pkg/{pkg}/firewall' \
              '/policy/{policyid}'.format(adom=paramgram["adom"],
                                          pkg=paramgram["package_name"],
                                          policyid=paramgram["policyid"])
        datagram = {
            "policyid": paramgram["policyid"]
        }

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


#############
# END METHODS
#############


def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),
        package_name=dict(type="str", required=False, default="default"),

        wsso=dict(required=False, type="str", choices=["disable", "enable"]),
        webfilter_profile=dict(required=False, type="str"),
        webcache_https=dict(required=False, type="str", choices=["disable", "enable"]),
        webcache=dict(required=False, type="str", choices=["disable", "enable"]),
        wccp=dict(required=False, type="str", choices=["disable", "enable"]),
        wanopt_profile=dict(required=False, type="str"),
        wanopt_peer=dict(required=False, type="str"),
        wanopt_passive_opt=dict(required=False, type="str", choices=["default", "transparent", "non-transparent"]),
        wanopt_detection=dict(required=False, type="str", choices=["active", "passive", "off"]),
        wanopt=dict(required=False, type="str", choices=["disable", "enable"]),
        waf_profile=dict(required=False, type="str"),
        vpntunnel=dict(required=False, type="str"),
        voip_profile=dict(required=False, type="str"),
        vlan_filter=dict(required=False, type="str"),
        vlan_cos_rev=dict(required=False, type="int"),
        vlan_cos_fwd=dict(required=False, type="int"),
        utm_status=dict(required=False, type="str", choices=["disable", "enable"]),
        users=dict(required=False, type="str"),
        url_category=dict(required=False, type="str"),
        traffic_shaper_reverse=dict(required=False, type="str"),
        traffic_shaper=dict(required=False, type="str"),
        timeout_send_rst=dict(required=False, type="str", choices=["disable", "enable"]),
        tcp_session_without_syn=dict(required=False, type="str", choices=["all", "data-only", "disable"]),
        tcp_mss_sender=dict(required=False, type="int"),
        tcp_mss_receiver=dict(required=False, type="int"),
        status=dict(required=False, type="str", choices=["disable", "enable"]),
        ssl_ssh_profile=dict(required=False, type="str"),
        ssl_mirror_intf=dict(required=False, type="str"),
        ssl_mirror=dict(required=False, type="str", choices=["disable", "enable"]),
        ssh_filter_profile=dict(required=False, type="str"),
        srcintf=dict(required=False, type="str"),
        srcaddr_negate=dict(required=False, type="str", choices=["disable", "enable"]),
        srcaddr=dict(required=False, type="str"),
        spamfilter_profile=dict(required=False, type="str"),
        session_ttl=dict(required=False, type="int"),
        service_negate=dict(required=False, type="str", choices=["disable", "enable"]),
        service=dict(required=False, type="str"),
        send_deny_packet=dict(required=False, type="str", choices=["disable", "enable"]),
        schedule_timeout=dict(required=False, type="str", choices=["disable", "enable"]),
        schedule=dict(required=False, type="str"),
        scan_botnet_connections=dict(required=False, type="str", choices=["disable", "block", "monitor"]),
        rtp_nat=dict(required=False, type="str", choices=["disable", "enable"]),
        rtp_addr=dict(required=False, type="str"),
        rsso=dict(required=False, type="str", choices=["disable", "enable"]),
        replacemsg_override_group=dict(required=False, type="str"),
        redirect_url=dict(required=False, type="str"),
        radius_mac_auth_bypass=dict(required=False, type="str", choices=["disable", "enable"]),
        profile_type=dict(required=False, type="str", choices=["single", "group"]),
        profile_protocol_options=dict(required=False, type="str"),
        profile_group=dict(required=False, type="str"),
        poolname=dict(required=False, type="str"),
        policyid=dict(required=False, type="str"),
        permit_stun_host=dict(required=False, type="str", choices=["disable", "enable"]),
        permit_any_host=dict(required=False, type="str", choices=["disable", "enable"]),
        per_ip_shaper=dict(required=False, type="str"),
        outbound=dict(required=False, type="str", choices=["disable", "enable"]),
        ntlm_guest=dict(required=False, type="str", choices=["disable", "enable"]),
        ntlm_enabled_browsers=dict(required=False, type="str"),
        ntlm=dict(required=False, type="str", choices=["disable", "enable"]),
        np_acceleration=dict(required=False, type="str", choices=["disable", "enable"]),
        natoutbound=dict(required=False, type="str", choices=["disable", "enable"]),
        natip=dict(required=False, type="str"),
        natinbound=dict(required=False, type="str", choices=["disable", "enable"]),
        nat=dict(required=False, type="str", choices=["disable", "enable"]),
        name=dict(required=False, type="str"),
        mms_profile=dict(required=False, type="str"),
        match_vip=dict(required=False, type="str", choices=["disable", "enable"]),
        logtraffic_start=dict(required=False, type="str", choices=["disable", "enable"]),
        logtraffic=dict(required=False, type="str", choices=["disable", "all", "utm"]),
        learning_mode=dict(required=False, type="str", choices=["disable", "enable"]),
        label=dict(required=False, type="str"),
        ips_sensor=dict(required=False, type="str"),
        ippool=dict(required=False, type="str", choices=["disable", "enable"]),
        internet_service_src_negate=dict(required=False, type="str", choices=["disable", "enable"]),
        internet_service_src_id=dict(required=False, type="str"),
        internet_service_src_custom=dict(required=False, type="str"),
        internet_service_src=dict(required=False, type="str", choices=["disable", "enable"]),
        internet_service_negate=dict(required=False, type="str", choices=["disable", "enable"]),
        internet_service_id=dict(required=False, type="str"),
        internet_service_custom=dict(required=False, type="str"),
        internet_service=dict(required=False, type="str", choices=["disable", "enable"]),
        inbound=dict(required=False, type="str", choices=["disable", "enable"]),
        identity_based_route=dict(required=False, type="str"),
        icap_profile=dict(required=False, type="str"),
        gtp_profile=dict(required=False, type="str"),
        groups=dict(required=False, type="str"),
        global_label=dict(required=False, type="str"),
        fsso_agent_for_ntlm=dict(required=False, type="str"),
        fsso=dict(required=False, type="str", choices=["disable", "enable"]),
        fixedport=dict(required=False, type="str", choices=["disable", "enable"]),
        firewall_session_dirty=dict(required=False, type="str", choices=["check-all", "check-new"]),
        dstintf=dict(required=False, type="str"),
        dstaddr_negate=dict(required=False, type="str", choices=["disable", "enable"]),
        dstaddr=dict(required=False, type="str"),
        dsri=dict(required=False, type="str", choices=["disable", "enable"]),
        dscp_value=dict(required=False, type="str"),
        dscp_negate=dict(required=False, type="str", choices=["disable", "enable"]),
        dscp_match=dict(required=False, type="str", choices=["disable", "enable"]),
        dnsfilter_profile=dict(required=False, type="str"),
        dlp_sensor=dict(required=False, type="str"),
        disclaimer=dict(required=False, type="str", choices=["disable", "enable"]),
        diffservcode_rev=dict(required=False, type="str"),
        diffservcode_forward=dict(required=False, type="str"),
        diffserv_reverse=dict(required=False, type="str", choices=["disable", "enable"]),
        diffserv_forward=dict(required=False, type="str", choices=["disable", "enable"]),
        devices=dict(required=False, type="str"),
        delay_tcp_npu_session=dict(required=False, type="str", choices=["disable", "enable"]),
        custom_log_fields=dict(required=False, type="str"),
        comments=dict(required=False, type="str"),
        capture_packet=dict(required=False, type="str", choices=["disable", "enable"]),
        captive_portal_exempt=dict(required=False, type="str", choices=["disable", "enable"]),
        block_notification=dict(required=False, type="str", choices=["disable", "enable"]),
        av_profile=dict(required=False, type="str"),
        auto_asic_offload=dict(required=False, type="str", choices=["disable", "enable"]),
        auth_redirect_addr=dict(required=False, type="str"),
        auth_path=dict(required=False, type="str", choices=["disable", "enable"]),
        auth_cert=dict(required=False, type="str"),
        application_list=dict(required=False, type="str"),
        application=dict(required=False, type="str"),
        app_group=dict(required=False, type="str"),
        app_category=dict(required=False, type="str"),
        action=dict(required=False, type="str", choices=["deny", "accept", "ipsec"]),
        vpn_dst_node=dict(required=False, type="list"),
        vpn_dst_node_host=dict(required=False, type="str"),
        vpn_dst_node_seq=dict(required=False, type="str"),
        vpn_dst_node_subnet=dict(required=False, type="str"),
        vpn_src_node=dict(required=False, type="list"),
        vpn_src_node_host=dict(required=False, type="str"),
        vpn_src_node_seq=dict(required=False, type="str"),
        vpn_src_node_subnet=dict(required=False, type="str"),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "package_name": module.params["package_name"],
        "wsso": module.params["wsso"],
        "webfilter-profile": module.params["webfilter_profile"],
        "webcache-https": module.params["webcache_https"],
        "webcache": module.params["webcache"],
        "wccp": module.params["wccp"],
        "wanopt-profile": module.params["wanopt_profile"],
        "wanopt-peer": module.params["wanopt_peer"],
        "wanopt-passive-opt": module.params["wanopt_passive_opt"],
        "wanopt-detection": module.params["wanopt_detection"],
        "wanopt": module.params["wanopt"],
        "waf-profile": module.params["waf_profile"],
        "vpntunnel": module.params["vpntunnel"],
        "voip-profile": module.params["voip_profile"],
        "vlan-filter": module.params["vlan_filter"],
        "vlan-cos-rev": module.params["vlan_cos_rev"],
        "vlan-cos-fwd": module.params["vlan_cos_fwd"],
        "utm-status": module.params["utm_status"],
        "users": module.params["users"],
        "url-category": module.params["url_category"],
        "traffic-shaper-reverse": module.params["traffic_shaper_reverse"],
        "traffic-shaper": module.params["traffic_shaper"],
        "timeout-send-rst": module.params["timeout_send_rst"],
        "tcp-session-without-syn": module.params["tcp_session_without_syn"],
        "tcp-mss-sender": module.params["tcp_mss_sender"],
        "tcp-mss-receiver": module.params["tcp_mss_receiver"],
        "status": module.params["status"],
        "ssl-ssh-profile": module.params["ssl_ssh_profile"],
        "ssl-mirror-intf": module.params["ssl_mirror_intf"],
        "ssl-mirror": module.params["ssl_mirror"],
        "ssh-filter-profile": module.params["ssh_filter_profile"],
        "srcintf": module.params["srcintf"],
        "srcaddr-negate": module.params["srcaddr_negate"],
        "srcaddr": module.params["srcaddr"],
        "spamfilter-profile": module.params["spamfilter_profile"],
        "session-ttl": module.params["session_ttl"],
        "service-negate": module.params["service_negate"],
        "service": module.params["service"],
        "send-deny-packet": module.params["send_deny_packet"],
        "schedule-timeout": module.params["schedule_timeout"],
        "schedule": module.params["schedule"],
        "scan-botnet-connections": module.params["scan_botnet_connections"],
        "rtp-nat": module.params["rtp_nat"],
        "rtp-addr": module.params["rtp_addr"],
        "rsso": module.params["rsso"],
        "replacemsg-override-group": module.params["replacemsg_override_group"],
        "redirect-url": module.params["redirect_url"],
        "radius-mac-auth-bypass": module.params["radius_mac_auth_bypass"],
        "profile-type": module.params["profile_type"],
        "profile-protocol-options": module.params["profile_protocol_options"],
        "profile-group": module.params["profile_group"],
        "poolname": module.params["poolname"],
        "policyid": module.params["policyid"],
        "permit-stun-host": module.params["permit_stun_host"],
        "permit-any-host": module.params["permit_any_host"],
        "per-ip-shaper": module.params["per_ip_shaper"],
        "outbound": module.params["outbound"],
        "ntlm-guest": module.params["ntlm_guest"],
        "ntlm-enabled-browsers": module.params["ntlm_enabled_browsers"],
        "ntlm": module.params["ntlm"],
        "np-acceleration": module.params["np_acceleration"],
        "natoutbound": module.params["natoutbound"],
        "natip": module.params["natip"],
        "natinbound": module.params["natinbound"],
        "nat": module.params["nat"],
        "name": module.params["name"],
        "mms-profile": module.params["mms_profile"],
        "match-vip": module.params["match_vip"],
        "logtraffic-start": module.params["logtraffic_start"],
        "logtraffic": module.params["logtraffic"],
        "learning-mode": module.params["learning_mode"],
        "label": module.params["label"],
        "ips-sensor": module.params["ips_sensor"],
        "ippool": module.params["ippool"],
        "internet-service-src-negate": module.params["internet_service_src_negate"],
        "internet-service-src-id": module.params["internet_service_src_id"],
        "internet-service-src-custom": module.params["internet_service_src_custom"],
        "internet-service-src": module.params["internet_service_src"],
        "internet-service-negate": module.params["internet_service_negate"],
        "internet-service-id": module.params["internet_service_id"],
        "internet-service-custom": module.params["internet_service_custom"],
        "internet-service": module.params["internet_service"],
        "inbound": module.params["inbound"],
        "identity-based-route": module.params["identity_based_route"],
        "icap-profile": module.params["icap_profile"],
        "gtp-profile": module.params["gtp_profile"],
        "groups": module.params["groups"],
        "global-label": module.params["global_label"],
        "fsso-agent-for-ntlm": module.params["fsso_agent_for_ntlm"],
        "fsso": module.params["fsso"],
        "fixedport": module.params["fixedport"],
        "firewall-session-dirty": module.params["firewall_session_dirty"],
        "dstintf": module.params["dstintf"],
        "dstaddr-negate": module.params["dstaddr_negate"],
        "dstaddr": module.params["dstaddr"],
        "dsri": module.params["dsri"],
        "dscp-value": module.params["dscp_value"],
        "dscp-negate": module.params["dscp_negate"],
        "dscp-match": module.params["dscp_match"],
        "dnsfilter-profile": module.params["dnsfilter_profile"],
        "dlp-sensor": module.params["dlp_sensor"],
        "disclaimer": module.params["disclaimer"],
        "diffservcode-rev": module.params["diffservcode_rev"],
        "diffservcode-forward": module.params["diffservcode_forward"],
        "diffserv-reverse": module.params["diffserv_reverse"],
        "diffserv-forward": module.params["diffserv_forward"],
        "devices": module.params["devices"],
        "delay-tcp-npu-session": module.params["delay_tcp_npu_session"],
        "custom-log-fields": module.params["custom_log_fields"],
        "comments": module.params["comments"],
        "capture-packet": module.params["capture_packet"],
        "captive-portal-exempt": module.params["captive_portal_exempt"],
        "block-notification": module.params["block_notification"],
        "av-profile": module.params["av_profile"],
        "auto-asic-offload": module.params["auto_asic_offload"],
        "auth-redirect-addr": module.params["auth_redirect_addr"],
        "auth-path": module.params["auth_path"],
        "auth-cert": module.params["auth_cert"],
        "application-list": module.params["application_list"],
        "application": module.params["application"],
        "app-group": module.params["app_group"],
        "app-category": module.params["app_category"],
        "action": module.params["action"],
        "vpn_dst_node": {
            "host": module.params["vpn_dst_node_host"],
            "seq": module.params["vpn_dst_node_seq"],
            "subnet": module.params["vpn_dst_node_subnet"],
        },
        "vpn_src_node": {
            "host": module.params["vpn_src_node_host"],
            "seq": module.params["vpn_src_node_seq"],
            "subnet": module.params["vpn_src_node_subnet"],
        }
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['vpn_dst_node', 'vpn_src_node']
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)

    # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION
    results = DEFAULT_RESULT_OBJ
    try:
        if paramgram["mode"] == "delete":
            # WE NEED TO GET THE POLICY ID FROM THE NAME OF THE POLICY TO DELETE IT
            url = '/pm/config/adom/{adom}/pkg/{pkg}/firewall' \
                  '/policy/'.format(adom=paramgram["adom"],
                                    pkg=paramgram["package_name"])
            datagram = {
                "filter": ["name", "==", paramgram["name"]]
            }
            response = fmgr.process_request(url, datagram, FMGRMethods.GET)
            try:
                if response[1][0]["policyid"]:
                    policy_id = response[1][0]["policyid"]
                    paramgram["policyid"] = policy_id
            except BaseException:
                fmgr.return_response(module=module, results=response, good_codes=[0, ], stop_on_success=True,
                                     ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram),
                                     msg="Couldn't find policy ID number for policy name specified.")
    except Exception as err:
        raise FMGBaseException(err)

    try:
        results = fmgr_firewall_policy_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results, good_codes=[0, -9998],
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_fwpol_package

Metadata

Name: fmgr_fwpol_package

Description: Manages FortiManager Firewall Policies Packages. Policy Packages contain one or more Firewall Policies/Rules and are distritbuted via FortiManager to Fortigates. This module controls the creation/edit/delete/assign of these packages.

Author(s):

  • Luke Weighall (github: @lweighall)
  • Andrew Welsh (github: @Ghilli3)
  • Jim Huber (github: @p4r4n0y1ng)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Luke Weighall

Module Github Link

Parameters
adom
  • Description: The ADOM the configuration should belong to.
  • Required: False
  • default: root
central_nat
  • Description: Central NAT setting.
  • Required: False
  • default: disable
  • choices: [‘enable’, ‘disable’]
fwpolicy6_implicit_log
  • Description: Implicit Log setting for all IPv6 policies in package.
  • Required: False
  • default: disable
  • choices: [‘enable’, ‘disable’]
fwpolicy_implicit_log
  • Description: Implicit Log setting for all IPv4 policies in package.
  • Required: False
  • default: disable
  • choices: [‘enable’, ‘disable’]
inspection_mode
  • Description: Inspection mode setting for the policies flow or proxy.
  • Required: False
  • default: flow
  • choices: [‘flow’, ‘proxy’]
mode
  • Description: Set will overwrite existing installation targets with scope members.

    Add will append existing installation targets with scope members.

    Delete will delete the entire named package.

    Add Targets will only add the specified scope members to installation targets.

    Delete Targets will only delete the specified scope members from installation targets.

    Install will install the package to the assigned installation targets listed on existing package.

    Update your installation targets BEFORE running install task.

  • default: add

  • choices: [‘add’, ‘set’, ‘delete’, ‘move’, ‘copy’, ‘add_targets’, ‘delete_targets’, ‘install’]

name
  • Description: Name of the FortiManager package or folder.
  • Required: True
ngfw_mode
  • Description: NGFW mode setting for the policies flow or proxy.
  • Required: False
  • default: profile-based
  • choices: [‘profile-based’, ‘policy-based’]
object_type
  • Description: Are we managing packages or package folders?
  • Required: True
  • choices: [‘pkg’, ‘folder’]
parent_folder
  • Description: The parent folder name you want to add this object under.

    Nested folders are supported with forwardslashes. i.e. ansibleTestFolder1/ansibleTestFolder2/etc…

    Do not include leading or trailing forwardslashes. We take care of that for you.

  • Required: False

scope_groups
  • Description: List of groups to add to the scope of the fw pol package
  • Required: False
scope_members
  • Description: The devices or scope that you want to assign this policy package to. Only assign to one VDOM at a time.
  • Required: False
scope_members_vdom
  • Description: The members VDOM you want to assign the package to. Only assign to one VDOM at a time.
  • Required: False
  • default: root
ssl_ssh_profile
  • Description: if policy-based ngfw-mode, refer to firewall ssl-ssh-profile.
  • Required: False
target_folder
  • Description: Only used when mode equals move.

    Nested folders are supported with forwardslashes. i.e. ansibleTestFolder1/ansibleTestFolder2/etc…

    Do not include leading or trailing forwardslashes. We take care of that for you.

  • Required: False

target_name
  • Description: Only used when mode equals move.

    Only used when you want to rename the package in its new location.

    If None, then NAME will be used.

  • Required: False

Functions
  • fmgr_fwpol_package
def fmgr_fwpol_package(fmgr, paramgram):
    """
    This function will create FMGR Firewall Policy Packages, or delete them. It is also capable of assigning packages.
    This function DOES NOT install the package. See the function fmgr_fwpol_package_install()

    :param fmgr: The fmgr object instance from fmgr_utils.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict

    :return: The response from the FortiManager
    :rtype: dict
    """
    if paramgram["mode"] in ['set', 'add']:
        url = '/pm/pkg/adom/{adom}'.format(adom=paramgram["adom"])
        datagram = {
            "type": paramgram["object_type"],
            "name": paramgram["name"],
            "package settings": {
                "central-nat": paramgram["central-nat"],
                "fwpolicy-implicit-log": paramgram["fwpolicy-implicit-log"],
                "fwpolicy6-implicit-log": paramgram["fwpolicy6-implicit-log"],
                "inspection-mode": paramgram["inspection-mode"],
                "ngfw-mode": paramgram["ngfw-mode"],
            }
        }

        if paramgram["ngfw-mode"] == "policy-based" and paramgram["ssl-ssh-profile"] is not None:
            datagram["package settings"]["ssl-ssh-profile"] = paramgram["ssl-ssh-profile"]

        # SET THE SCOPE MEMBERS ACCORDING TO MODE AND WHAT WAS SUPPLIED
        if len(paramgram["append_members_list"]) > 0:
            datagram["scope member"] = paramgram["append_members_list"]
        elif len(paramgram["append_members_list"]) == 0:
            datagram["scope member"] = {}

        # IF PARENT FOLDER IS DEFINED
        if paramgram["parent_folder"] is not None:
            datagram = fmgr_fwpol_package_create_parent_folder_objects(paramgram, datagram)

    # IF MODE IS MOVE
    if paramgram['mode'] in ["move", "copy"]:
       # pydevd.settrace('10.0.0.151', port=54654, stdoutToServer=True, stderrToServer=True)
        if paramgram["mode"] == "move":
            url = '/securityconsole/package/move'
        elif paramgram["mode"] == "copy":
            url = '/securityconsole/package/clone'
        if paramgram["target_name"]:
            name = paramgram["target_name"]
        else:
            name = paramgram["name"]
        datagram = {
            "adom": paramgram["adom"],
            "dst_name": name,
            "dst_parent": paramgram["target_folder"],
            "pkg": paramgram["name"]
        }
        if paramgram["parent_folder"]:
            datagram["pkg"] = str(paramgram["parent_folder"]) + "/" + str(paramgram["name"])
        else:
            datagram["pkg"] = str(paramgram["name"])

        if paramgram["mode"] == "copy":
            # SET THE SCOPE MEMBERS ACCORDING TO MODE AND WHAT WAS SUPPLIED
            if len(paramgram["append_members_list"]) > 0:
                datagram["scope member"] = paramgram["append_members_list"]
            elif len(paramgram["append_members_list"]) == 0:
                datagram["scope member"] = {}

    # NORMAL DELETE NO PARENT
    if paramgram["mode"] == "delete" and paramgram["parent_folder"] is None:
        datagram = {
            "name": paramgram["name"]
        }
        # SET DELETE URL
        url = '/pm/pkg/adom/{adom}/{name}'.format(adom=paramgram["adom"], name=paramgram["name"])

    # DELETE WITH PARENT
    if paramgram["mode"] == "delete" and paramgram["parent_folder"] is not None:
        datagram = {
            "name": paramgram["name"]
        }
        # SET DELETE URL
        url = '/pm/pkg/adom/{adom}/{parent_folder}/{name}'.format(adom=paramgram["adom"],
                                                                  name=paramgram["name"],
                                                                  parent_folder=paramgram["parent_folder"])

    if paramgram['mode'] in ["move", "copy"]:
        response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
    else:
        response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response
  • fmgr_fwpol_package_edit_targets
def fmgr_fwpol_package_edit_targets(fmgr, paramgram):
    """
    This function will append scope targets to an existing policy package.

    :param fmgr: The fmgr object instance from fmgr_utils.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict

    :return: The response from the FortiManager
    :rtype: dict
    """
    # MERGE APPEND AND EXISTING MEMBERS LISTS BASED ON MODE
    method = None
    members_list = None
    if paramgram["mode"] == "add_targets":
        method = FMGRMethods.ADD
        members_list = paramgram["append_members_list"]
        for member in paramgram["existing_members_list"]:
            if member not in members_list:
                members_list.append(member)

    elif paramgram["mode"] == "delete_targets":
        method = FMGRMethods.DELETE
        members_list = list()
        for member in paramgram["append_members_list"]:
            if member in paramgram["existing_members_list"]:
                members_list.append(member)
    datagram = {
        "data": members_list
    }

    if paramgram["parent_folder"] is not None:
        url = '/pm/pkg/adom/{adom}/{parent_folder}/{name}/scope member'.format(adom=paramgram["adom"],
                                                                               name=paramgram["name"],
                                                                               parent_folder=paramgram["parent_folder"])
    elif paramgram["parent_folder"] is None:
        url = '/pm/pkg/adom/{adom}/{name}/scope member'.format(adom=paramgram["adom"],
                                                               name=paramgram["name"])
    response = fmgr.process_request(url, datagram, method)
    return response
  • fmgr_fwpol_package_folder
def fmgr_fwpol_package_folder(fmgr, paramgram):
    """
    This function will create folders for firewall packages. It can create down to two levels deep.
    We haven't yet tested for any more layers below two levels.
    parent_folders for multiple levels may need to defined as "level1/level2/level3" for the URL parameters and such.

    :param fmgr: The fmgr object instance from fmgr_utils.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict

    :return: The response from the FortiManager
    :rtype: dict
    """
    if paramgram["mode"] in ['set', 'add']:
        url = '/pm/pkg/adom/{adom}'.format(adom=paramgram["adom"])

        datagram = {
            "type": paramgram["object_type"],
            "name": paramgram["name"],
        }

        # IF PARENT FOLDER IS DEFINED
        if paramgram["parent_folder"] is not None:
            datagram = fmgr_fwpol_package_create_parent_folder_objects(paramgram, datagram)

    # NORMAL DELETE NO PARENT
    if paramgram["mode"] == "delete" and paramgram["parent_folder"] is None:
        datagram = {
            "name": paramgram["name"]
        }
        # SET DELETE URL
        url = '/pm/pkg/adom/{adom}/{name}'.format(adom=paramgram["adom"], name=paramgram["name"])

    # DELETE WITH PARENT
    if paramgram["mode"] == "delete" and paramgram["parent_folder"] is not None:
        datagram = {
            "name": paramgram["name"]
        }
        # SET DELETE URL
        url = '/pm/pkg/adom/{adom}/{parent_folder}/{name}'.format(adom=paramgram["adom"],
                                                                  name=paramgram["name"],
                                                                  parent_folder=paramgram["parent_folder"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response
  • fmgr_fwpol_package_install
def fmgr_fwpol_package_install(fmgr, paramgram):
    """
    This method/function installs FMGR FW Policy Packages to the scope members defined in the playbook.

    :param fmgr: The fmgr object instance from fmgr_utils.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict

    :return: The response from the FortiManager
    :rtype: dict
    """
    datagram = {
        "adom": paramgram["adom"],
        "pkg": paramgram["name"],
    }
    if paramgram["parent_folder"]:
        new_path = str(paramgram["parent_folder"]) + "/" + str(paramgram["name"])
        datagram["pkg"] = new_path

    # EXECUTE THE INSTALL REQUEST
    url = '/securityconsole/install/package'
    response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
    return response
  • fmgr_fwpol_package_get_details
def fmgr_fwpol_package_get_details(fmgr, paramgram):
    """
    This method/function will attempt to get existing package details, and append findings to the paramgram.
    If nothing is found, the paramgram additions are simply empty.

    :param fmgr: The fmgr object instance from fmgr_utils.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict

    :return: The response from the FortiManager
    :rtype: dict
    """
    # CHECK FOR SCOPE MEMBERS AND CREATE THAT MEMBERS LIST
    # WE MUST PROPERLY FORMAT THE JSON FOR SCOPE MEMBERS WITH VDOMS
    members_list = list()
    if paramgram["scope_members"] is not None and paramgram["mode"] in ['add', 'set', 'add_targets', 'delete_targets']:
        if isinstance(paramgram["scope_members"], list):
            members = paramgram["scope_members"]
        if isinstance(paramgram["scope_members"], str):
            members = FMGRCommon.split_comma_strings_into_lists(paramgram["scope_members"])
        for member in members:
            scope_dict = {
                "name": member,
                "vdom": paramgram["scope_members_vdom"],
            }
            members_list.append(scope_dict)

    # CHECK FOR SCOPE GROUPS AND ADD THAT TO THE MEMBERS LIST
    # WE MUST PROPERLY FORMAT THE JSON FOR SCOPE GROUPS
    if paramgram["scope_groups"] is not None and paramgram["mode"] in ['add', 'set', 'add_targets', 'delete_targets']:
        if isinstance(paramgram["scope_groups"], list):
            members = paramgram["scope_groups"]
        if isinstance(paramgram["scope_groups"], str):
            members = FMGRCommon.split_comma_strings_into_lists(paramgram["scope_groups"])
        for member in members:
            scope_dict = {
                "name": member
            }
            members_list.append(scope_dict)

    # CHECK FOR AN EXISTING POLICY PACKAGE, AND GET ITS MEMBERS SO WE DON'T OVERWRITE THEM WITH NOTHING
    pol_datagram = {"type": paramgram["object_type"], "name": paramgram["name"]}
    if paramgram["parent_folder"]:
        pol_package_url = '/pm/pkg/adom/{adom}/{folder}/{pkg_name}'.format(adom=paramgram["adom"],
                                                                           pkg_name=paramgram["name"],
                                                                           folder=paramgram["parent_folder"])
    else:
        pol_package_url = '/pm/pkg/adom/{adom}/{pkg_name}'.format(adom=paramgram["adom"],
                                                                  pkg_name=paramgram["name"])
    pol_package = fmgr.process_request(pol_package_url, pol_datagram, FMGRMethods.GET)
    existing_members = None
    package_exists = None
    if len(pol_package) == 2:
        package_exists = True
        try:
            existing_members = pol_package[1]["scope member"]
        except Exception as err:
            existing_members = list()
    else:
        package_exists = False

    # ADD COLLECTED DATA TO PARAMGRAM FOR USE IN METHODS
    paramgram["existing_members_list"] = existing_members
    paramgram["append_members_list"] = members_list
    paramgram["package_exists"] = package_exists

    return paramgram
  • fmgr_fwpol_package_create_parent_folder_objects
def fmgr_fwpol_package_create_parent_folder_objects(paramgram, datagram):
    """
    This function/method will take a paramgram with parent folders defined, and create the proper structure
    so that objects are nested correctly.

    :param paramgram: The paramgram used
    :type paramgram: dict
    :param datagram: The datagram, so far, as created by another function.
    :type datagram: dict

    :return: new_datagram
    """
    # SPLIT THE PARENT FOLDER INTO A LIST BASED ON FORWARD SLASHES
    # FORM THE DATAGRAM USING TEMPLATE ABOVE WITH THE PACKAGE NESTED IN A SUBOBJ
    subobj_list = list()
    subobj_list.append(datagram)
    new_datagram = {
        "type": "folder",
        "name": paramgram["parent_folder"],
        "subobj": subobj_list
    }
    parent_folders = paramgram["parent_folder"].split("/")
    # LOOP THROUGH PARENT FOLDERS AND ADD AS MANY SUB OBJECT NESTED DICTS AS REQUIRED
    # WE'RE BUILDING THE SUBOBJ NESTED OBJECT "INSIDE OUT"
    num_of_parents = len(parent_folders)
    if num_of_parents > 1:
        parent_list_position = num_of_parents - 1
        # REPLACE THE EXISTING PARENT FOLDER STRING WITH SLASHES, WITH THE BOTTOM MOST NESTED FOLDER
        new_datagram["name"] = parent_folders[parent_list_position]
        parent_list_position -= 1
        while parent_list_position >= 0:
            new_subobj_list = list()
            new_subobj_list.append(new_datagram)
            new_datagram = {
                "type": "folder",
                "name": parent_folders[parent_list_position],
                "subobj": new_subobj_list
            }
            parent_list_position -= 1
        # SET DATAGRAM TO THE NEWLY NESTED DATAGRAM
    return new_datagram
  • main
def main():
    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "move", "copy", "add_targets", "delete_targets", "install"],
                  type="str", default="add"),

        name=dict(required=False, type="str"),
        object_type=dict(required=True, type="str", choices=['pkg', 'folder']),
        central_nat=dict(required=False, type="str", default="disable", choices=['enable', 'disable']),
        fwpolicy_implicit_log=dict(required=False, type="str", default="disable", choices=['enable', 'disable']),
        fwpolicy6_implicit_log=dict(required=False, type="str", default="disable", choices=['enable', 'disable']),
        inspection_mode=dict(required=False, type="str", default="flow", choices=['flow', 'proxy']),
        ngfw_mode=dict(required=False, type="str", default="profile-based", choices=['profile-based', 'policy-based']),
        ssl_ssh_profile=dict(required=False, type="str"),
        scope_groups=dict(required=False, type="str"),
        scope_members=dict(required=False, type="str"),
        scope_members_vdom=dict(required=False, type="str", default="root"),
        parent_folder=dict(required=False, type="str"),
        target_folder=dict(required=False, type="str"),
        target_name=dict(required=False, type="str"),

    )
    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False,)
    # MODULE DATAGRAM
    paramgram = {
        "adom": module.params["adom"],
        "name": module.params["name"],
        "mode": module.params["mode"],
        "object_type": module.params["object_type"],
        "central-nat": module.params["central_nat"],
        "fwpolicy-implicit-log": module.params["fwpolicy_implicit_log"],
        "fwpolicy6-implicit-log": module.params["fwpolicy6_implicit_log"],
        "inspection-mode": module.params["inspection_mode"],
        "ngfw-mode": module.params["ngfw_mode"],
        "ssl-ssh-profile": module.params["ssl_ssh_profile"],
        "scope_groups": module.params["scope_groups"],
        "scope_members": module.params["scope_members"],
        "scope_members_vdom": module.params["scope_members_vdom"],
        "parent_folder": module.params["parent_folder"],
        "target_folder": module.params["target_folder"],
        "target_name": module.params["target_name"],
        "append_members_list": list(),
        "existing_members_list": list(),
        "package_exists": None,
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION
    results = DEFAULT_RESULT_OBJ

    # QUERY FORTIMANAGER FOR EXISTING PACKAGE DETAILS AND UPDATE PARAMGRAM
    paramgram = fmgr_fwpol_package_get_details(fmgr, paramgram)

    try:
        if paramgram["object_type"] == "pkg" and paramgram["mode"] in ["add", "set", "delete", "move", "copy"]:
            results = fmgr_fwpol_package(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        if paramgram["object_type"] == "pkg" and paramgram["package_exists"] \
                and len(paramgram["append_members_list"]) > 0 \
                and paramgram["mode"] in ['add_targets', 'delete_targets']:
            results = fmgr_fwpol_package_edit_targets(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # IF THE object_type IS FOLDER LETS RUN THAT METHOD
        if paramgram["object_type"] == "folder":
            results = fmgr_fwpol_package_folder(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # IF THE object_type IS INSTALL AND NEEDED PARAMETERS ARE DEFINED INSTALL THE PACKAGE
        if paramgram["name"] is not None and paramgram["object_type"] == "pkg" and paramgram["mode"] == "install":
            results = fmgr_fwpol_package_install(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {
    "metadata_version": "1.1",
    "status": ["preview"],
    "supported_by": "community"
}

DOCUMENTATION = '''
---
module: fmgr_fwpol_package
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
    - Revision Comments April 2nd 2019
        - Couldn't append to installation target list, only send a complete list. We've added modes for adding and
          deleting targets for policy packages.
        - Install mode has been added. Scope_members is no longer taken into account when mode = install.
          Only the existing installation targets on the package will be used. Update installation targets before.
        - Nested folders and packages now work properly. Before they were not.
        - When using modes "add" or "set" with object_type = "pkg" the installation targets are STILL OVERWRITTEN with
          what was supplied under scope_members and scope_groups. Use the add_targets or delete_targets mode first.
        - When using "add_targets" or "delete_targets" for changing installation targets, only scope_members or
          scope_groups is considered for changes to the package. To edit the package settings themselves, use "set".
    - Revision Comments May 21st 2019
        - Added support to move packages.
author:
    - Luke Weighall (@lweighall)
    - Andrew Welsh (@Ghilli3)
    - Jim Huber (@p4r4n0y1ng)
short_description: Manages FortiManager Firewall Policies Packages.
description:
  -  Manages FortiManager Firewall Policies Packages. Policy Packages contain one or more Firewall Policies/Rules and
     are distritbuted via FortiManager to Fortigates.
  -  This module controls the creation/edit/delete/assign of these packages.

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: false
    default: root

  mode:
    description:
      - Set will overwrite existing installation targets with scope members.
      - Add will append existing installation targets with scope members.
      - Delete will delete the entire named package.
      - Add Targets will only add the specified scope members to installation targets.
      - Delete Targets will only delete the specified scope members from installation targets.
      - Install will install the package to the assigned installation targets listed on existing package.
      - Update your installation targets BEFORE running install task.
    choices: ['add', 'set', 'delete', 'move', 'copy', 'add_targets', 'delete_targets', 'install']
    default: add

  name:
    description:
      - Name of the FortiManager package or folder.
    required: True

  object_type:
    description:
      - Are we managing packages or package folders?
    required: True
    choices: ['pkg','folder']

  central_nat:
    description:
      - Central NAT setting.
    required: false
    choices: ['enable', 'disable']
    default: disable

  fwpolicy_implicit_log:
    description:
      - Implicit Log setting for all IPv4 policies in package.
    required: false
    choices: ['enable', 'disable']
    default: disable

  fwpolicy6_implicit_log:
    description:
      - Implicit Log setting for all IPv6 policies in package.
    required: false
    choices: ['enable', 'disable']
    default: disable

  inspection_mode:
    description:
      - Inspection mode setting for the policies flow or proxy.
    required: false
    choices: ['flow', 'proxy']
    default: flow

  ngfw_mode:
    description:
      - NGFW mode setting for the policies flow or proxy.
    required: false
    choices: ['profile-based', 'policy-based']
    default: profile-based

  ssl_ssh_profile:
    description:
      - if policy-based ngfw-mode, refer to firewall ssl-ssh-profile.
    required: false

  scope_groups:
    description:
      - List of groups to add to the scope of the fw pol package
    required: false

  scope_members:
    description:
      - The devices or scope that you want to assign this policy package to. Only assign to one VDOM at a time.
    required: false

  scope_members_vdom:
    description:
      - The members VDOM you want to assign the package to. Only assign to one VDOM at a time.
    required: false
    default: root

  parent_folder:
    description:
      - The parent folder name you want to add this object under.
      - Nested folders are supported with forwardslashes. i.e. ansibleTestFolder1/ansibleTestFolder2/etc...
      - Do not include leading or trailing forwardslashes. We take care of that for you.
    required: false

  target_folder:
    description:
      - Only used when mode equals move.
      - Nested folders are supported with forwardslashes. i.e. ansibleTestFolder1/ansibleTestFolder2/etc...
      - Do not include leading or trailing forwardslashes. We take care of that for you.
    required: false

  target_name:
    description:
      - Only used when mode equals move.
      - Only used when you want to rename the package in its new location.
      - If None, then NAME will be used.
    required: false
'''


EXAMPLES = '''
- name: CREATE BASIC POLICY PACKAGE
  fmgr_fwpol_package:
    adom: "ansible"
    mode: "add"
    name: "testPackage"
    object_type: "pkg"

- name: ADD PACKAGE WITH TARGETS
  fmgr_fwpol_package:
    mode: "add"
    adom: "ansible"
    name: "ansibleTestPackage1"
    object_type: "pkg"
    inspection_mode: "flow"
    ngfw_mode: "profile-based"
    scope_members: "seattle-fgt02, seattle-fgt03"

- name: ADD FOLDER
  fmgr_fwpol_package:
    mode: "add"
    adom: "ansible"
    name: "ansibleTestFolder1"
    object_type: "folder"

- name: ADD PACKAGE INTO PARENT FOLDER
  fmgr_fwpol_package:
    mode: "set"
    adom: "ansible"
    name: "ansibleTestPackage2"
    object_type: "pkg"
    parent_folder: "ansibleTestFolder1"

- name: ADD FOLDER INTO PARENT FOLDER
  fmgr_fwpol_package:
    mode: "set"
    adom: "ansible"
    name: "ansibleTestFolder2"
    object_type: "folder"
    parent_folder: "ansibleTestFolder1"

- name: INSTALL PACKAGE
  fmgr_fwpol_package:
    mode: "install"
    adom: "ansible"
    name: "ansibleTestPackage1"

- name: REMOVE PACKAGE
  fmgr_fwpol_package:
    mode: "delete"
    adom: "ansible"
    name: "ansibleTestPackage1"
    object_type: "pkg"

- name: REMOVE NESTED PACKAGE
  fmgr_fwpol_package:
    mode: "delete"
    adom: "ansible"
    name: "ansibleTestPackage2"
    object_type: "pkg"
    parent_folder: "ansibleTestFolder1"

- name: REMOVE NESTED FOLDER
  fmgr_fwpol_package:
    mode: "delete"
    adom: "ansible"
    name: "ansibleTestFolder2"
    object_type: "folder"
    parent_folder: "ansibleTestFolder1"

- name: REMOVE FOLDER
  fmgr_fwpol_package:
    mode: "delete"
    adom: "ansible"
    name: "ansibleTestFolder1"
    object_type: "folder"
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
from ansible.module_utils.network.fortimanager.common import FMGRMethods

import pydevd

def fmgr_fwpol_package(fmgr, paramgram):
    """
    This function will create FMGR Firewall Policy Packages, or delete them. It is also capable of assigning packages.
    This function DOES NOT install the package. See the function fmgr_fwpol_package_install()

    :param fmgr: The fmgr object instance from fmgr_utils.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict

    :return: The response from the FortiManager
    :rtype: dict
    """
    if paramgram["mode"] in ['set', 'add']:
        url = '/pm/pkg/adom/{adom}'.format(adom=paramgram["adom"])
        datagram = {
            "type": paramgram["object_type"],
            "name": paramgram["name"],
            "package settings": {
                "central-nat": paramgram["central-nat"],
                "fwpolicy-implicit-log": paramgram["fwpolicy-implicit-log"],
                "fwpolicy6-implicit-log": paramgram["fwpolicy6-implicit-log"],
                "inspection-mode": paramgram["inspection-mode"],
                "ngfw-mode": paramgram["ngfw-mode"],
            }
        }

        if paramgram["ngfw-mode"] == "policy-based" and paramgram["ssl-ssh-profile"] is not None:
            datagram["package settings"]["ssl-ssh-profile"] = paramgram["ssl-ssh-profile"]

        # SET THE SCOPE MEMBERS ACCORDING TO MODE AND WHAT WAS SUPPLIED
        if len(paramgram["append_members_list"]) > 0:
            datagram["scope member"] = paramgram["append_members_list"]
        elif len(paramgram["append_members_list"]) == 0:
            datagram["scope member"] = {}

        # IF PARENT FOLDER IS DEFINED
        if paramgram["parent_folder"] is not None:
            datagram = fmgr_fwpol_package_create_parent_folder_objects(paramgram, datagram)

    # IF MODE IS MOVE
    if paramgram['mode'] in ["move", "copy"]:
       # pydevd.settrace('10.0.0.151', port=54654, stdoutToServer=True, stderrToServer=True)
        if paramgram["mode"] == "move":
            url = '/securityconsole/package/move'
        elif paramgram["mode"] == "copy":
            url = '/securityconsole/package/clone'
        if paramgram["target_name"]:
            name = paramgram["target_name"]
        else:
            name = paramgram["name"]
        datagram = {
            "adom": paramgram["adom"],
            "dst_name": name,
            "dst_parent": paramgram["target_folder"],
            "pkg": paramgram["name"]
        }
        if paramgram["parent_folder"]:
            datagram["pkg"] = str(paramgram["parent_folder"]) + "/" + str(paramgram["name"])
        else:
            datagram["pkg"] = str(paramgram["name"])

        if paramgram["mode"] == "copy":
            # SET THE SCOPE MEMBERS ACCORDING TO MODE AND WHAT WAS SUPPLIED
            if len(paramgram["append_members_list"]) > 0:
                datagram["scope member"] = paramgram["append_members_list"]
            elif len(paramgram["append_members_list"]) == 0:
                datagram["scope member"] = {}

    # NORMAL DELETE NO PARENT
    if paramgram["mode"] == "delete" and paramgram["parent_folder"] is None:
        datagram = {
            "name": paramgram["name"]
        }
        # SET DELETE URL
        url = '/pm/pkg/adom/{adom}/{name}'.format(adom=paramgram["adom"], name=paramgram["name"])

    # DELETE WITH PARENT
    if paramgram["mode"] == "delete" and paramgram["parent_folder"] is not None:
        datagram = {
            "name": paramgram["name"]
        }
        # SET DELETE URL
        url = '/pm/pkg/adom/{adom}/{parent_folder}/{name}'.format(adom=paramgram["adom"],
                                                                  name=paramgram["name"],
                                                                  parent_folder=paramgram["parent_folder"])

    if paramgram['mode'] in ["move", "copy"]:
        response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
    else:
        response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


def fmgr_fwpol_package_edit_targets(fmgr, paramgram):
    """
    This function will append scope targets to an existing policy package.

    :param fmgr: The fmgr object instance from fmgr_utils.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict

    :return: The response from the FortiManager
    :rtype: dict
    """
    # MERGE APPEND AND EXISTING MEMBERS LISTS BASED ON MODE
    method = None
    members_list = None
    if paramgram["mode"] == "add_targets":
        method = FMGRMethods.ADD
        members_list = paramgram["append_members_list"]
        for member in paramgram["existing_members_list"]:
            if member not in members_list:
                members_list.append(member)

    elif paramgram["mode"] == "delete_targets":
        method = FMGRMethods.DELETE
        members_list = list()
        for member in paramgram["append_members_list"]:
            if member in paramgram["existing_members_list"]:
                members_list.append(member)
    datagram = {
        "data": members_list
    }

    if paramgram["parent_folder"] is not None:
        url = '/pm/pkg/adom/{adom}/{parent_folder}/{name}/scope member'.format(adom=paramgram["adom"],
                                                                               name=paramgram["name"],
                                                                               parent_folder=paramgram["parent_folder"])
    elif paramgram["parent_folder"] is None:
        url = '/pm/pkg/adom/{adom}/{name}/scope member'.format(adom=paramgram["adom"],
                                                               name=paramgram["name"])
    response = fmgr.process_request(url, datagram, method)
    return response


def fmgr_fwpol_package_folder(fmgr, paramgram):
    """
    This function will create folders for firewall packages. It can create down to two levels deep.
    We haven't yet tested for any more layers below two levels.
    parent_folders for multiple levels may need to defined as "level1/level2/level3" for the URL parameters and such.

    :param fmgr: The fmgr object instance from fmgr_utils.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict

    :return: The response from the FortiManager
    :rtype: dict
    """
    if paramgram["mode"] in ['set', 'add']:
        url = '/pm/pkg/adom/{adom}'.format(adom=paramgram["adom"])

        datagram = {
            "type": paramgram["object_type"],
            "name": paramgram["name"],
        }

        # IF PARENT FOLDER IS DEFINED
        if paramgram["parent_folder"] is not None:
            datagram = fmgr_fwpol_package_create_parent_folder_objects(paramgram, datagram)

    # NORMAL DELETE NO PARENT
    if paramgram["mode"] == "delete" and paramgram["parent_folder"] is None:
        datagram = {
            "name": paramgram["name"]
        }
        # SET DELETE URL
        url = '/pm/pkg/adom/{adom}/{name}'.format(adom=paramgram["adom"], name=paramgram["name"])

    # DELETE WITH PARENT
    if paramgram["mode"] == "delete" and paramgram["parent_folder"] is not None:
        datagram = {
            "name": paramgram["name"]
        }
        # SET DELETE URL
        url = '/pm/pkg/adom/{adom}/{parent_folder}/{name}'.format(adom=paramgram["adom"],
                                                                  name=paramgram["name"],
                                                                  parent_folder=paramgram["parent_folder"])

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


def fmgr_fwpol_package_install(fmgr, paramgram):
    """
    This method/function installs FMGR FW Policy Packages to the scope members defined in the playbook.

    :param fmgr: The fmgr object instance from fmgr_utils.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict

    :return: The response from the FortiManager
    :rtype: dict
    """
    datagram = {
        "adom": paramgram["adom"],
        "pkg": paramgram["name"],
    }
    if paramgram["parent_folder"]:
        new_path = str(paramgram["parent_folder"]) + "/" + str(paramgram["name"])
        datagram["pkg"] = new_path

    # EXECUTE THE INSTALL REQUEST
    url = '/securityconsole/install/package'
    response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
    return response


def fmgr_fwpol_package_get_details(fmgr, paramgram):
    """
    This method/function will attempt to get existing package details, and append findings to the paramgram.
    If nothing is found, the paramgram additions are simply empty.

    :param fmgr: The fmgr object instance from fmgr_utils.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict

    :return: The response from the FortiManager
    :rtype: dict
    """
    # CHECK FOR SCOPE MEMBERS AND CREATE THAT MEMBERS LIST
    # WE MUST PROPERLY FORMAT THE JSON FOR SCOPE MEMBERS WITH VDOMS
    members_list = list()
    if paramgram["scope_members"] is not None and paramgram["mode"] in ['add', 'set', 'add_targets', 'delete_targets']:
        if isinstance(paramgram["scope_members"], list):
            members = paramgram["scope_members"]
        if isinstance(paramgram["scope_members"], str):
            members = FMGRCommon.split_comma_strings_into_lists(paramgram["scope_members"])
        for member in members:
            scope_dict = {
                "name": member,
                "vdom": paramgram["scope_members_vdom"],
            }
            members_list.append(scope_dict)

    # CHECK FOR SCOPE GROUPS AND ADD THAT TO THE MEMBERS LIST
    # WE MUST PROPERLY FORMAT THE JSON FOR SCOPE GROUPS
    if paramgram["scope_groups"] is not None and paramgram["mode"] in ['add', 'set', 'add_targets', 'delete_targets']:
        if isinstance(paramgram["scope_groups"], list):
            members = paramgram["scope_groups"]
        if isinstance(paramgram["scope_groups"], str):
            members = FMGRCommon.split_comma_strings_into_lists(paramgram["scope_groups"])
        for member in members:
            scope_dict = {
                "name": member
            }
            members_list.append(scope_dict)

    # CHECK FOR AN EXISTING POLICY PACKAGE, AND GET ITS MEMBERS SO WE DON'T OVERWRITE THEM WITH NOTHING
    pol_datagram = {"type": paramgram["object_type"], "name": paramgram["name"]}
    if paramgram["parent_folder"]:
        pol_package_url = '/pm/pkg/adom/{adom}/{folder}/{pkg_name}'.format(adom=paramgram["adom"],
                                                                           pkg_name=paramgram["name"],
                                                                           folder=paramgram["parent_folder"])
    else:
        pol_package_url = '/pm/pkg/adom/{adom}/{pkg_name}'.format(adom=paramgram["adom"],
                                                                  pkg_name=paramgram["name"])
    pol_package = fmgr.process_request(pol_package_url, pol_datagram, FMGRMethods.GET)
    existing_members = None
    package_exists = None
    if len(pol_package) == 2:
        package_exists = True
        try:
            existing_members = pol_package[1]["scope member"]
        except Exception as err:
            existing_members = list()
    else:
        package_exists = False

    # ADD COLLECTED DATA TO PARAMGRAM FOR USE IN METHODS
    paramgram["existing_members_list"] = existing_members
    paramgram["append_members_list"] = members_list
    paramgram["package_exists"] = package_exists

    return paramgram


def fmgr_fwpol_package_create_parent_folder_objects(paramgram, datagram):
    """
    This function/method will take a paramgram with parent folders defined, and create the proper structure
    so that objects are nested correctly.

    :param paramgram: The paramgram used
    :type paramgram: dict
    :param datagram: The datagram, so far, as created by another function.
    :type datagram: dict

    :return: new_datagram
    """
    # SPLIT THE PARENT FOLDER INTO A LIST BASED ON FORWARD SLASHES
    # FORM THE DATAGRAM USING TEMPLATE ABOVE WITH THE PACKAGE NESTED IN A SUBOBJ
    subobj_list = list()
    subobj_list.append(datagram)
    new_datagram = {
        "type": "folder",
        "name": paramgram["parent_folder"],
        "subobj": subobj_list
    }
    parent_folders = paramgram["parent_folder"].split("/")
    # LOOP THROUGH PARENT FOLDERS AND ADD AS MANY SUB OBJECT NESTED DICTS AS REQUIRED
    # WE'RE BUILDING THE SUBOBJ NESTED OBJECT "INSIDE OUT"
    num_of_parents = len(parent_folders)
    if num_of_parents > 1:
        parent_list_position = num_of_parents - 1
        # REPLACE THE EXISTING PARENT FOLDER STRING WITH SLASHES, WITH THE BOTTOM MOST NESTED FOLDER
        new_datagram["name"] = parent_folders[parent_list_position]
        parent_list_position -= 1
        while parent_list_position >= 0:
            new_subobj_list = list()
            new_subobj_list.append(new_datagram)
            new_datagram = {
                "type": "folder",
                "name": parent_folders[parent_list_position],
                "subobj": new_subobj_list
            }
            parent_list_position -= 1
        # SET DATAGRAM TO THE NEWLY NESTED DATAGRAM
    return new_datagram


def main():
    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "move", "copy", "add_targets", "delete_targets", "install"],
                  type="str", default="add"),

        name=dict(required=False, type="str"),
        object_type=dict(required=True, type="str", choices=['pkg', 'folder']),
        central_nat=dict(required=False, type="str", default="disable", choices=['enable', 'disable']),
        fwpolicy_implicit_log=dict(required=False, type="str", default="disable", choices=['enable', 'disable']),
        fwpolicy6_implicit_log=dict(required=False, type="str", default="disable", choices=['enable', 'disable']),
        inspection_mode=dict(required=False, type="str", default="flow", choices=['flow', 'proxy']),
        ngfw_mode=dict(required=False, type="str", default="profile-based", choices=['profile-based', 'policy-based']),
        ssl_ssh_profile=dict(required=False, type="str"),
        scope_groups=dict(required=False, type="str"),
        scope_members=dict(required=False, type="str"),
        scope_members_vdom=dict(required=False, type="str", default="root"),
        parent_folder=dict(required=False, type="str"),
        target_folder=dict(required=False, type="str"),
        target_name=dict(required=False, type="str"),

    )
    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False,)
    # MODULE DATAGRAM
    paramgram = {
        "adom": module.params["adom"],
        "name": module.params["name"],
        "mode": module.params["mode"],
        "object_type": module.params["object_type"],
        "central-nat": module.params["central_nat"],
        "fwpolicy-implicit-log": module.params["fwpolicy_implicit_log"],
        "fwpolicy6-implicit-log": module.params["fwpolicy6_implicit_log"],
        "inspection-mode": module.params["inspection_mode"],
        "ngfw-mode": module.params["ngfw_mode"],
        "ssl-ssh-profile": module.params["ssl_ssh_profile"],
        "scope_groups": module.params["scope_groups"],
        "scope_members": module.params["scope_members"],
        "scope_members_vdom": module.params["scope_members_vdom"],
        "parent_folder": module.params["parent_folder"],
        "target_folder": module.params["target_folder"],
        "target_name": module.params["target_name"],
        "append_members_list": list(),
        "existing_members_list": list(),
        "package_exists": None,
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION
    results = DEFAULT_RESULT_OBJ

    # QUERY FORTIMANAGER FOR EXISTING PACKAGE DETAILS AND UPDATE PARAMGRAM
    paramgram = fmgr_fwpol_package_get_details(fmgr, paramgram)

    try:
        if paramgram["object_type"] == "pkg" and paramgram["mode"] in ["add", "set", "delete", "move", "copy"]:
            results = fmgr_fwpol_package(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        if paramgram["object_type"] == "pkg" and paramgram["package_exists"] \
                and len(paramgram["append_members_list"]) > 0 \
                and paramgram["mode"] in ['add_targets', 'delete_targets']:
            results = fmgr_fwpol_package_edit_targets(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # IF THE object_type IS FOLDER LETS RUN THAT METHOD
        if paramgram["object_type"] == "folder":
            results = fmgr_fwpol_package_folder(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # IF THE object_type IS INSTALL AND NEEDED PARAMETERS ARE DEFINED INSTALL THE PACKAGE
        if paramgram["name"] is not None and paramgram["object_type"] == "pkg" and paramgram["mode"] == "install":
            results = fmgr_fwpol_package_install(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results,
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_ha

Metadata

Name: fmgr_ha

Description: Change HA state or settings of FortiManager nodes (Standalone/Master/Slave).

Author(s):

  • Luke Weighall (github: @lweighall)
  • Andrew Welsh (github: @Ghilli3)
  • Jim Huber (github: @p4r4n0y1ng)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Luke Weighall

Module Github Link

Parameters
fmgr_ha_cluster_id
  • Description: Sets the ID number of the HA cluster. Defaults to 1.
  • Required: False
  • default: 1
fmgr_ha_cluster_pw
  • Description: Sets the password for the HA cluster. Only required once. System remembers between HA mode switches.
  • Required: False
fmgr_ha_file_quota
  • Description: Sets the File quota in MB (2048-20480).
  • Required: False
  • default: 4096
fmgr_ha_hb_interval
  • Description: Sets the heartbeat interval (1-255).
  • Required: False
  • default: 5
fmgr_ha_hb_threshold
  • Description: Sets heartbeat lost threshold (1-255).
  • Required: False
  • default: 3
fmgr_ha_mode
  • Description: Sets the role of the FortiManager host for HA.
  • Required: False
  • choices: [‘standalone’, ‘master’, ‘slave’]
fmgr_ha_peer_ipv4
  • Description: Sets the IPv4 address of a HA peer.
  • Required: False
fmgr_ha_peer_ipv6
  • Description: Sets the IPv6 address of a HA peer.
  • Required: False
fmgr_ha_peer_sn
  • Description: Sets the HA Peer Serial Number.
  • Required: False
fmgr_ha_peer_status
  • Description: Sets the peer status to enable or disable.
  • Required: False
  • choices: [‘enable’, ‘disable’]
Functions
  • fmgr_set_ha_mode
def fmgr_set_ha_mode(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    if paramgram["fmgr_ha_cluster_pw"] is not None and str(paramgram["fmgr_ha_mode"].lower()) != "standalone":
        datagram = {
            "mode": paramgram["fmgr_ha_mode"],
            "file-quota": paramgram["fmgr_ha_file_quota"],
            "hb-interval": paramgram["fmgr_ha_hb_interval"],
            "hb-lost-threshold": paramgram["fmgr_ha_hb_threshold"],
            "password": paramgram["fmgr_ha_cluster_pw"],
            "clusterid": paramgram["fmgr_ha_cluster_id"]
        }
    elif str(paramgram["fmgr_ha_mode"].lower()) == "standalone":
        datagram = {
            "mode": paramgram["fmgr_ha_mode"],
            "file-quota": paramgram["fmgr_ha_file_quota"],
            "hb-interval": paramgram["fmgr_ha_hb_interval"],
            "hb-lost-threshold": paramgram["fmgr_ha_hb_threshold"],
            "clusterid": paramgram["fmgr_ha_cluster_id"]
        }

    url = '/cli/global/system/ha'
    response = fmgr.process_request(url, datagram, FMGRMethods.SET)
    return response
  • fmgr_get_ha_peer_list
def fmgr_get_ha_peer_list(fmgr):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ

    datagram = {}
    paramgram = {}

    url = '/cli/global/system/ha/peer/'
    response = fmgr.process_request(url, datagram, FMGRMethods.GET)
    return response
  • fmgr_set_ha_peer
def fmgr_set_ha_peer(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    datagram = {
        "ip": paramgram["fmgr_ha_peer_ipv4"],
        "ip6": paramgram["fmgr_ha_peer_ipv6"],
        "serial-number": paramgram["fmgr_ha_peer_sn"],
        "status": paramgram["fmgr_ha_peer_status"],
        "id": paramgram["peer_id"]
    }

    url = '/cli/global/system/ha/peer/'
    response = fmgr.process_request(url, datagram, FMGRMethods.SET)
    return response
  • main
def main():
    argument_spec = dict(
        fmgr_ha_mode=dict(required=False, type="str", choices=["standalone", "master", "slave"]),
        fmgr_ha_cluster_pw=dict(required=False, type="str", no_log=True),
        fmgr_ha_peer_status=dict(required=False, type="str", choices=["enable", "disable"]),
        fmgr_ha_peer_sn=dict(required=False, type="str"),
        fmgr_ha_peer_ipv4=dict(required=False, type="str"),
        fmgr_ha_peer_ipv6=dict(required=False, type="str"),
        fmgr_ha_hb_threshold=dict(required=False, type="int", default=3),
        fmgr_ha_hb_interval=dict(required=False, type="int", default=5),
        fmgr_ha_file_quota=dict(required=False, type="int", default=4096),
        fmgr_ha_cluster_id=dict(required=False, type="int", default=1)
    )

    required_if = [
        ['fmgr_ha_peer_ipv4', 'present', ['fmgr_ha_peer_sn', 'fmgr_ha_peer_status']],
        ['fmgr_ha_peer_ipv6', 'present', ['fmgr_ha_peer_sn', 'fmgr_ha_peer_status']],
        ['fmgr_ha_mode', 'master', ['fmgr_ha_cluster_pw', 'fmgr_ha_cluster_id']],
        ['fmgr_ha_mode', 'slave', ['fmgr_ha_cluster_pw', 'fmgr_ha_cluster_id']],
    ]

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, required_if=required_if)
    paramgram = {
        "fmgr_ha_mode": module.params["fmgr_ha_mode"],
        "fmgr_ha_cluster_pw": module.params["fmgr_ha_cluster_pw"],
        "fmgr_ha_peer_status": module.params["fmgr_ha_peer_status"],
        "fmgr_ha_peer_sn": module.params["fmgr_ha_peer_sn"],
        "fmgr_ha_peer_ipv4": module.params["fmgr_ha_peer_ipv4"],
        "fmgr_ha_peer_ipv6": module.params["fmgr_ha_peer_ipv6"],
        "fmgr_ha_hb_threshold": module.params["fmgr_ha_hb_threshold"],
        "fmgr_ha_hb_interval": module.params["fmgr_ha_hb_interval"],
        "fmgr_ha_file_quota": module.params["fmgr_ha_file_quota"],
        "fmgr_ha_cluster_id": module.params["fmgr_ha_cluster_id"],
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    # INIT FLAGS AND COUNTERS
    get_ha_peers = 0
    results = DEFAULT_RESULT_OBJ
    try:
        if any(v is not None for v in (paramgram["fmgr_ha_peer_sn"], paramgram["fmgr_ha_peer_ipv4"],
                                       paramgram["fmgr_ha_peer_ipv6"], paramgram["fmgr_ha_peer_status"])):
            get_ha_peers = 1
    except Exception as err:
        raise FMGBaseException(err)
    try:
        # IF HA MODE IS NOT NULL, SWITCH THAT
        if paramgram["fmgr_ha_mode"] is not None:
            if (str.lower(paramgram["fmgr_ha_mode"]) != "standalone" and paramgram["fmgr_ha_cluster_pw"] is not None)\
                    or str.lower(paramgram["fmgr_ha_mode"]) == "standalone":
                results = fmgr_set_ha_mode(fmgr, paramgram)
                fmgr.govern_response(module=module, results=results, stop_on_success=False,
                                     ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

            elif str.lower(paramgram["fmgr_ha_mode"]) != "standalone" and\
                    paramgram["fmgr_ha_mode"] is not None and\
                    paramgram["fmgr_ha_cluster_pw"] is None:
                module.exit_json(msg="If setting HA Mode of MASTER or SLAVE, you must specify a cluster password")

    except Exception as err:
        raise FMGBaseException(err)
        # IF GET_HA_PEERS IS ENABLED, LETS PROCESS THE PEERS
    try:
        if get_ha_peers == 1:
            # GET THE CURRENT LIST OF PEERS FROM THE NODE
            peers = fmgr_get_ha_peer_list(fmgr)
            # GET LENGTH OF RETURNED PEERS LIST AND ADD ONE FOR THE NEXT ID
            paramgram["next_peer_id"] = len(peers[1]) + 1
            # SET THE ACTUAL NUMBER OF PEERS
            num_of_peers = len(peers[1])
            # SET THE PEER ID FOR DISABLE METHOD
            paramgram["peer_id"] = len(peers) - 1
            # SET THE PEER LOOPCOUNT TO 1 TO START THE LOOP
            peer_loopcount = 1

            # LOOP THROUGH PEERS TO FIND THE SERIAL NUMBER MATCH TO GET THE RIGHT PEER ID
            # IDEA BEING WE DON'T WANT TO SUBMIT A BAD peer_id THAT DOESN'T JIVE WITH CURRENT DB ON FMG
            # SO LETS SEARCH FOR IT, AND IF WE FIND IT, WE WILL CHANGE THE PEER ID VARIABLES TO MATCH
            # IF NOT FOUND, LIFE GOES ON AND WE ASSUME THAT WE'RE ADDING A PEER
            # AT WHICH POINT THE next_peer_id VARIABLE WILL HAVE THE RIGHT PRIMARY KEY

            if paramgram["fmgr_ha_peer_sn"] is not None:
                while peer_loopcount <= num_of_peers:
                    # GET THE SERIAL NUMBER FOR CURRENT PEER IN LOOP TO COMPARE TO SN IN PLAYBOOK
                    try:
                        sn_compare = peers[1][peer_loopcount - 1]["serial-number"]
                        # IF THE SN IN THE PEERS MATCHES THE PLAYBOOK SN, SET THE IDS
                        if sn_compare == paramgram["fmgr_ha_peer_sn"]:
                            paramgram["peer_id"] = peer_loopcount
                            paramgram["next_peer_id"] = paramgram["peer_id"]
                    except Exception as err:
                        raise FMGBaseException(err)
                    # ADVANCE THE LOOP AND REPEAT UNTIL DONE
                    peer_loopcount += 1

            # IF THE PEER STATUS ISN'T IN THE PLAYBOOK, ASSUME ITS ENABLE
            if paramgram["fmgr_ha_peer_status"] is None:
                paramgram["fmgr_ha_peer_status"] = "enable"

            # IF THE PEER STATUS IS ENABLE, USE THE next_peer_id IN THE API CALL FOR THE ID
            if paramgram["fmgr_ha_peer_status"] == "enable":
                results = fmgr_set_ha_peer(fmgr, paramgram)
                fmgr.govern_response(module=module, results=results, stop_on_success=True,
                                     ansible_facts=fmgr.construct_ansible_facts(results,
                                                                                module.params, paramgram))

            # IF THE PEER STATUS IS DISABLE, WE HAVE TO HANDLE THAT A BIT DIFFERENTLY
            # JUST USING TWO DIFFERENT peer_id 's HERE
            if paramgram["fmgr_ha_peer_status"] == "disable":
                results = fmgr_set_ha_peer(fmgr, paramgram)
                fmgr.govern_response(module=module, results=results, stop_on_success=True,
                                     ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {
    "metadata_version": "1.1",
    "status": ["preview"],
    "supported_by": "community"
}

DOCUMENTATION = '''
---
module: fmgr_ha
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author:
    - Luke Weighall (@lweighall)
    - Andrew Welsh (@Ghilli3)
    - Jim Huber (@p4r4n0y1ng)
short_description: Manages the High-Availability State of FortiManager Clusters and Nodes.
description: Change HA state or settings of FortiManager nodes (Standalone/Master/Slave).

options:
  fmgr_ha_mode:
    description:
      - Sets the role of the FortiManager host for HA.
    required: false
    choices: ["standalone", "master", "slave"]

  fmgr_ha_peer_ipv4:
    description:
      - Sets the IPv4 address of a HA peer.
    required: false

  fmgr_ha_peer_ipv6:
    description:
      - Sets the IPv6 address of a HA peer.
    required: false

  fmgr_ha_peer_sn:
    description:
      - Sets the HA Peer Serial Number.
    required: false

  fmgr_ha_peer_status:
    description:
      - Sets the peer status to enable or disable.
    required: false
    choices: ["enable", "disable"]

  fmgr_ha_cluster_pw:
    description:
      - Sets the password for the HA cluster. Only required once. System remembers between HA mode switches.
    required: false

  fmgr_ha_cluster_id:
    description:
      - Sets the ID number of the HA cluster. Defaults to 1.
    required: false
    default: 1

  fmgr_ha_hb_threshold:
    description:
      - Sets heartbeat lost threshold (1-255).
    required: false
    default: 3

  fmgr_ha_hb_interval:
    description:
      - Sets the heartbeat interval (1-255).
    required: false
    default: 5

  fmgr_ha_file_quota:
    description:
      - Sets the File quota in MB (2048-20480).
    required: false
    default: 4096
'''


EXAMPLES = '''
- name: SET FORTIMANAGER HA NODE TO MASTER
  fmgr_ha:
    fmgr_ha_mode: "master"
    fmgr_ha_cluster_pw: "fortinet"
    fmgr_ha_cluster_id: "1"

- name: SET FORTIMANAGER HA NODE TO SLAVE
  fmgr_ha:
    fmgr_ha_mode: "slave"
    fmgr_ha_cluster_pw: "fortinet"
    fmgr_ha_cluster_id: "1"

- name: SET FORTIMANAGER HA NODE TO STANDALONE
  fmgr_ha:
    fmgr_ha_mode: "standalone"

- name: ADD FORTIMANAGER HA PEER
  fmgr_ha:
    fmgr_ha_peer_ipv4: "192.168.1.254"
    fmgr_ha_peer_sn: "FMG-VM1234567890"
    fmgr_ha_peer_status: "enable"

- name: CREATE CLUSTER ON MASTER
  fmgr_ha:
    fmgr_ha_mode: "master"
    fmgr_ha_cluster_pw: "fortinet"
    fmgr_ha_cluster_id: "1"
    fmgr_ha_hb_threshold: "10"
    fmgr_ha_hb_interval: "15"
    fmgr_ha_file_quota: "2048"
'''
RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import FMGRMethods
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG


def fmgr_set_ha_mode(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    if paramgram["fmgr_ha_cluster_pw"] is not None and str(paramgram["fmgr_ha_mode"].lower()) != "standalone":
        datagram = {
            "mode": paramgram["fmgr_ha_mode"],
            "file-quota": paramgram["fmgr_ha_file_quota"],
            "hb-interval": paramgram["fmgr_ha_hb_interval"],
            "hb-lost-threshold": paramgram["fmgr_ha_hb_threshold"],
            "password": paramgram["fmgr_ha_cluster_pw"],
            "clusterid": paramgram["fmgr_ha_cluster_id"]
        }
    elif str(paramgram["fmgr_ha_mode"].lower()) == "standalone":
        datagram = {
            "mode": paramgram["fmgr_ha_mode"],
            "file-quota": paramgram["fmgr_ha_file_quota"],
            "hb-interval": paramgram["fmgr_ha_hb_interval"],
            "hb-lost-threshold": paramgram["fmgr_ha_hb_threshold"],
            "clusterid": paramgram["fmgr_ha_cluster_id"]
        }

    url = '/cli/global/system/ha'
    response = fmgr.process_request(url, datagram, FMGRMethods.SET)
    return response


def fmgr_get_ha_peer_list(fmgr):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ

    datagram = {}
    paramgram = {}

    url = '/cli/global/system/ha/peer/'
    response = fmgr.process_request(url, datagram, FMGRMethods.GET)
    return response


def fmgr_set_ha_peer(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    datagram = {
        "ip": paramgram["fmgr_ha_peer_ipv4"],
        "ip6": paramgram["fmgr_ha_peer_ipv6"],
        "serial-number": paramgram["fmgr_ha_peer_sn"],
        "status": paramgram["fmgr_ha_peer_status"],
        "id": paramgram["peer_id"]
    }

    url = '/cli/global/system/ha/peer/'
    response = fmgr.process_request(url, datagram, FMGRMethods.SET)
    return response


def main():
    argument_spec = dict(
        fmgr_ha_mode=dict(required=False, type="str", choices=["standalone", "master", "slave"]),
        fmgr_ha_cluster_pw=dict(required=False, type="str", no_log=True),
        fmgr_ha_peer_status=dict(required=False, type="str", choices=["enable", "disable"]),
        fmgr_ha_peer_sn=dict(required=False, type="str"),
        fmgr_ha_peer_ipv4=dict(required=False, type="str"),
        fmgr_ha_peer_ipv6=dict(required=False, type="str"),
        fmgr_ha_hb_threshold=dict(required=False, type="int", default=3),
        fmgr_ha_hb_interval=dict(required=False, type="int", default=5),
        fmgr_ha_file_quota=dict(required=False, type="int", default=4096),
        fmgr_ha_cluster_id=dict(required=False, type="int", default=1)
    )

    required_if = [
        ['fmgr_ha_peer_ipv4', 'present', ['fmgr_ha_peer_sn', 'fmgr_ha_peer_status']],
        ['fmgr_ha_peer_ipv6', 'present', ['fmgr_ha_peer_sn', 'fmgr_ha_peer_status']],
        ['fmgr_ha_mode', 'master', ['fmgr_ha_cluster_pw', 'fmgr_ha_cluster_id']],
        ['fmgr_ha_mode', 'slave', ['fmgr_ha_cluster_pw', 'fmgr_ha_cluster_id']],
    ]

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, required_if=required_if)
    paramgram = {
        "fmgr_ha_mode": module.params["fmgr_ha_mode"],
        "fmgr_ha_cluster_pw": module.params["fmgr_ha_cluster_pw"],
        "fmgr_ha_peer_status": module.params["fmgr_ha_peer_status"],
        "fmgr_ha_peer_sn": module.params["fmgr_ha_peer_sn"],
        "fmgr_ha_peer_ipv4": module.params["fmgr_ha_peer_ipv4"],
        "fmgr_ha_peer_ipv6": module.params["fmgr_ha_peer_ipv6"],
        "fmgr_ha_hb_threshold": module.params["fmgr_ha_hb_threshold"],
        "fmgr_ha_hb_interval": module.params["fmgr_ha_hb_interval"],
        "fmgr_ha_file_quota": module.params["fmgr_ha_file_quota"],
        "fmgr_ha_cluster_id": module.params["fmgr_ha_cluster_id"],
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    # INIT FLAGS AND COUNTERS
    get_ha_peers = 0
    results = DEFAULT_RESULT_OBJ
    try:
        if any(v is not None for v in (paramgram["fmgr_ha_peer_sn"], paramgram["fmgr_ha_peer_ipv4"],
                                       paramgram["fmgr_ha_peer_ipv6"], paramgram["fmgr_ha_peer_status"])):
            get_ha_peers = 1
    except Exception as err:
        raise FMGBaseException(err)
    try:
        # IF HA MODE IS NOT NULL, SWITCH THAT
        if paramgram["fmgr_ha_mode"] is not None:
            if (str.lower(paramgram["fmgr_ha_mode"]) != "standalone" and paramgram["fmgr_ha_cluster_pw"] is not None)\
                    or str.lower(paramgram["fmgr_ha_mode"]) == "standalone":
                results = fmgr_set_ha_mode(fmgr, paramgram)
                fmgr.govern_response(module=module, results=results, stop_on_success=False,
                                     ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

            elif str.lower(paramgram["fmgr_ha_mode"]) != "standalone" and\
                    paramgram["fmgr_ha_mode"] is not None and\
                    paramgram["fmgr_ha_cluster_pw"] is None:
                module.exit_json(msg="If setting HA Mode of MASTER or SLAVE, you must specify a cluster password")

    except Exception as err:
        raise FMGBaseException(err)
        # IF GET_HA_PEERS IS ENABLED, LETS PROCESS THE PEERS
    try:
        if get_ha_peers == 1:
            # GET THE CURRENT LIST OF PEERS FROM THE NODE
            peers = fmgr_get_ha_peer_list(fmgr)
            # GET LENGTH OF RETURNED PEERS LIST AND ADD ONE FOR THE NEXT ID
            paramgram["next_peer_id"] = len(peers[1]) + 1
            # SET THE ACTUAL NUMBER OF PEERS
            num_of_peers = len(peers[1])
            # SET THE PEER ID FOR DISABLE METHOD
            paramgram["peer_id"] = len(peers) - 1
            # SET THE PEER LOOPCOUNT TO 1 TO START THE LOOP
            peer_loopcount = 1

            # LOOP THROUGH PEERS TO FIND THE SERIAL NUMBER MATCH TO GET THE RIGHT PEER ID
            # IDEA BEING WE DON'T WANT TO SUBMIT A BAD peer_id THAT DOESN'T JIVE WITH CURRENT DB ON FMG
            # SO LETS SEARCH FOR IT, AND IF WE FIND IT, WE WILL CHANGE THE PEER ID VARIABLES TO MATCH
            # IF NOT FOUND, LIFE GOES ON AND WE ASSUME THAT WE'RE ADDING A PEER
            # AT WHICH POINT THE next_peer_id VARIABLE WILL HAVE THE RIGHT PRIMARY KEY

            if paramgram["fmgr_ha_peer_sn"] is not None:
                while peer_loopcount <= num_of_peers:
                    # GET THE SERIAL NUMBER FOR CURRENT PEER IN LOOP TO COMPARE TO SN IN PLAYBOOK
                    try:
                        sn_compare = peers[1][peer_loopcount - 1]["serial-number"]
                        # IF THE SN IN THE PEERS MATCHES THE PLAYBOOK SN, SET THE IDS
                        if sn_compare == paramgram["fmgr_ha_peer_sn"]:
                            paramgram["peer_id"] = peer_loopcount
                            paramgram["next_peer_id"] = paramgram["peer_id"]
                    except Exception as err:
                        raise FMGBaseException(err)
                    # ADVANCE THE LOOP AND REPEAT UNTIL DONE
                    peer_loopcount += 1

            # IF THE PEER STATUS ISN'T IN THE PLAYBOOK, ASSUME ITS ENABLE
            if paramgram["fmgr_ha_peer_status"] is None:
                paramgram["fmgr_ha_peer_status"] = "enable"

            # IF THE PEER STATUS IS ENABLE, USE THE next_peer_id IN THE API CALL FOR THE ID
            if paramgram["fmgr_ha_peer_status"] == "enable":
                results = fmgr_set_ha_peer(fmgr, paramgram)
                fmgr.govern_response(module=module, results=results, stop_on_success=True,
                                     ansible_facts=fmgr.construct_ansible_facts(results,
                                                                                module.params, paramgram))

            # IF THE PEER STATUS IS DISABLE, WE HAVE TO HANDLE THAT A BIT DIFFERENTLY
            # JUST USING TWO DIFFERENT peer_id 's HERE
            if paramgram["fmgr_ha_peer_status"] == "disable":
                results = fmgr_set_ha_peer(fmgr, paramgram)
                fmgr.govern_response(module=module, results=results, stop_on_success=True,
                                     ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_provisioning

Metadata

Name: fmgr_provisioning

Description: Add model devices on the FortiManager using jsonrpc API and have them pre-configured, so when central management is configured, the configuration is pushed down to the registering devices

Author(s): Andrew Welsh (@Ghilli3)

Ansible Version Added/Required: 2.8

Dev Status: CODE UPDATE IN PROGRESS

Owning Developer: Andrew Welsh

Pull Request Started:

Days in PR:

Module Github Link

Parameters
adom
  • Description: The administrative domain (admon) the configuration belongs to.
  • default: root
description
  • Description: Description of the device to be provisioned.
  • Required: False
group
  • Description: The name of the device group the provisioned device can belong to.
  • Required: False
minor_release
  • Description: The minor release number such as 6.X.1, as X being the minor release.
  • Required: False
name
  • Description: The name of the device to be provisioned.
  • Required: True
os_type
  • Description: The Fortinet OS type to be pushed to the device, such as ‘FOS’ for FortiOS.
  • default: fos
os_version
  • Description: The Fortinet OS version to be used for the device, such as 5.0 or 6.0.
  • Required: True
patch_release
  • Description: The patch release number such as 6.0.X, as X being the patch release.
  • Required: False
platform
  • Description: The platform of the device, such as model number or VM.
  • default: FortiGate-VM64
policy_package
  • Description: The name of the policy package to be assigned to the device.
  • default: default
serial
  • Description: The serial number of the device that will be provisioned.
  • Required: True
vdom
  • Description: The virtual domain (vdom) the configuration belongs to.
  • default: root
Functions
  • dev_group_exists
def dev_group_exists(fmgr, paramgram):
    datagram = {
        'adom': paramgram["adom"],
        'name': paramgram["dev_grp_name"],
    }

    url = '/dvmdb/adom/{adom}/group/{dev_grp_name}'.format(adom=paramgram["adom"],
                                                           dev_grp_name=paramgram["dev_grp_name"])
    response = fmgr.process_request(url, datagram, FMGRMethods.GET)
    return response
  • prov_template_exists
def prov_template_exists(fmgr, paramgram):
    datagram = {
        'name': paramgram["prov_template"],
        'adom': paramgram["adom"],
    }

    url = '/pm/devprof/adom/{adom}/devprof/{name}'.format(adom=paramgram["adom"], name=paramgram["prov_template"])
    response = fmgr.process_request(url, datagram, FMGRMethods.GET)
    return response
  • create_model_device
def create_model_device(fmgr, paramgram):
    datagram = {
        'adom': paramgram["adom"],
        'flags': ['create_task', 'nonblocking'],
        'groups': [{'name': paramgram["group"], 'vdom': paramgram['vdom']}],
        'device': {
            'mr': paramgram["minor_release"],
            'name': paramgram["name"],
            'sn': paramgram["serial"],
            'mgmt_mode': 'fmg',
            'device action': 'add_model',
            'platform_str': paramgram["platform"],
            'os_ver': paramgram["os_version"],
            'os_type': paramgram["os_type"],
            'patch': paramgram["patch_release"],
            'desc': 'Provisioned by Ansible',
        }
    }

    url = '/dvm/cmd/add/device'
    response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
    return response
  • update_flags
def update_flags(fmgr, paramgram):
    datagram = {
        'flags': ['is_model', 'linked_to_model']
    }

    url = 'dvmdb/device/{name}'.format(name=paramgram["name"])
    response = fmgr.process_request(url, datagram, FMGRMethods.UPDATE)
    return response
  • assign_provision_template
def assign_provision_template(fmgr, paramgram):
    datagram = {
        'name': paramgram["template"],
        'type': 'devprof',
        'description': 'Provisioned by Ansible',
        'scope member': [{'name': paramgram["target"]}]
    }

    url = "/pm/devprof/adom/{adom}".format(adom=paramgram["adom"])
    response = fmgr.process_request(url, datagram, FMGRMethods.UPDATE)
    return response
#
#
  • set_devprof_scope
# def set_devprof_scope(self, provisioning_template, adom, provision_targets):
#     """
#     :param fmgr: The fmgr object instance from fortimanager.py
#     :type fmgr: class object
#     :param paramgram: The formatted dictionary of options to process
#     :type paramgram: dict
#     :return: The response from the FortiManager
#     :rtype: dict
#     """
#     fields = dict()
#     targets = []
#     fields["name"] = provisioning_template
#     fields["type"] = "devprof"
#     fields["description"] = "CreatedByAnsible"
#
#     for target in provision_targets.strip().split(","):
#         # split the host on the space to get the mask out
#         new_target = {"name": target}
#         targets.append(new_target)
#
#     fields["scope member"] = targets
#     url = "/pm/devprof/adom/{adom}".format(adom=paramgram["adom"])
#     body = {"method": "set", "params": [{"url": "/pm/devprof/adom/{adom}".format(adom=paramgram["adom"]),
#                                          "data": fields, "session": self.session}]}
#     response = fmgr.process_request(url, body, FMGRMethods.SET)
#     return response
  • assign_dev_grp
def assign_dev_grp(fmgr, paramgram):
    datagram = {
        'name': paramgram["device_name"],
        'vdom': paramgram["vdom"],
    }

    url = "/dvmdb/adom/{adom}/group/{grp_name}/object member".format(adom=paramgram["adom"],
                                                                     grp_name=paramgram["grp_name"])
    response = fmgr.process_request(url, datagram, FMGRMethods.SET)
    return response
  • update_install_target
def update_install_target(fmgr, paramgram):
    datagram = {
        'scope member': [{'name': paramgram["device"], 'vdom': paramgram["vdom"]}],
        'type': 'pkg'
    }

    url = '/pm/pkg/adom/{adom}/{pkg_name}'.format(adom=paramgram["adom"], pkg_name=paramgram["policy_package"])
    response = fmgr.process_request(url, datagram, FMGRMethods.UPDATE)
    return response
  • install_pp
def install_pp(fmgr, paramgram):
    datagram = {
        'adom': paramgram["adom"],
        'flags': 'nonblocking',
        'pkg': paramgram["policy_package"],
        'scope': [{'name': paramgram["device"], 'vdom': paramgram["vdom"]}],
    }

    url = 'securityconsole/install/package'
    response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
    return response
  • main
def main():

    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        vdom=dict(required=False, type="str", default="root"),
        policy_package=dict(required=False, type="str", default="default"),
        name=dict(required=True, type="str"),
        group=dict(required=False, type="str"),
        serial=dict(required=True, type="str"),
        platform=dict(required=False, type="str", default="FortiGate-VM64"),
        description=dict(required=False, type="str"),
        os_version=dict(required=True, type="str"),
        minor_release=dict(required=False, type="str"),
        patch_release=dict(required=False, type="str"),
        os_type=dict(required=False, type="str", default="fos"),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )

    paramgram = {
        "adom": module.params["adom"],
        "vdom": module.params["vdom"],
        "policy_package": module.params["policy_package"],
        "name": module.params["name"],
        "group": module.params["group"],
        "serial": module.params["serial"],
        "platform": module.params["platform"],
        "description": module.params["description"],
        "os_version": module.params["os_version"],
        "minor_release": module.params["minor_release"],
        "patch_release": module.params["patch_release"],
        "os_type": module.params["os_type"],
    }

    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    results = DEFAULT_RESULT_OBJ

    try:
        results = create_model_device(fmgr, paramgram)
        if results[0] != 0:
            module.fail_json(msg="Create model failed", **results)

        results = update_flags(fmgr, paramgram)
        if results[0] != 0:
            module.fail_json(msg="Update device flags failed", **results)

        results = update_install_target(fmgr, paramgram)
        if results[0] != 0:
            module.fail_json(msg="Adding device target to package failed", **results)

        results = install_pp(fmgr, paramgram)
        if results[0] != 0:
            module.fail_json(msg="Installing policy package failed", **results)

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function

__metaclass__ = type

ANSIBLE_METADATA = {'status': ['preview'],
                    'supported_by': 'community',
                    'metadata_version': '1.1'}

DOCUMENTATION = '''
---
module: fmgr_provisioning
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author: Andrew Welsh (@Ghilli3)
short_description: Provision devices via FortiMananger
description:
  - Add model devices on the FortiManager using jsonrpc API and have them pre-configured,
    so when central management is configured, the configuration is pushed down to the
    registering devices

options:
  adom:
    description:
      - The administrative domain (admon) the configuration belongs to.
    default: "root"

  vdom:
    description:
      - The virtual domain (vdom) the configuration belongs to.
    default: "root"

  policy_package:
    description:
      - The name of the policy package to be assigned to the device.
    default: "default"

  name:
    description:
      - The name of the device to be provisioned.
    required: True

  group:
    description:
      - The name of the device group the provisioned device can belong to.
    required: False

  serial:
    description:
      - The serial number of the device that will be provisioned.
    required: True

  platform:
    description:
      - The platform of the device, such as model number or VM.
    default: "FortiGate-VM64"

  description:
    description:
      - Description of the device to be provisioned.
    required: False

  os_version:
    description:
      - The Fortinet OS version to be used for the device, such as 5.0 or 6.0.
    required: True

  minor_release:
    description:
      - The minor release number such as 6.X.1, as X being the minor release.
    required: False

  patch_release:
    description:
      - The patch release number such as 6.0.X, as X being the patch release.
    required: False

  os_type:
    description:
      - The Fortinet OS type to be pushed to the device, such as 'FOS' for FortiOS.
    default: "fos"
'''

EXAMPLES = '''
- name: Create FGT1 Model Device
  fmgr_provisioning:
    adom: "root"
    vdom: "root"
    policy_package: "default"
    name: "FGT1"
    group: "Ansible"
    serial: "FGVM000000117994"
    platform: "FortiGate-VM64"
    description: "Provisioned by Ansible"
    os_version: '6.0'
    minor_release: 0
    patch_release: 0
    os_type: 'fos'


- name: Create FGT2 Model Device
  fmgr_provisioning:
    adom: "root"
    vdom: "root"
    policy_package: "test_pp"
    name: "FGT2"
    group: "Ansible"
    serial: "FGVM000000117992"
    platform: "FortiGate-VM64"
    description: "Provisioned by Ansible"
    os_version: '5.0'
    minor_release: 6
    patch_release: 0
    os_type: 'fos'

'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
from ansible.module_utils.network.fortimanager.common import FMGRMethods


def dev_group_exists(fmgr, paramgram):
    datagram = {
        'adom': paramgram["adom"],
        'name': paramgram["dev_grp_name"],
    }

    url = '/dvmdb/adom/{adom}/group/{dev_grp_name}'.format(adom=paramgram["adom"],
                                                           dev_grp_name=paramgram["dev_grp_name"])
    response = fmgr.process_request(url, datagram, FMGRMethods.GET)
    return response


def prov_template_exists(fmgr, paramgram):
    datagram = {
        'name': paramgram["prov_template"],
        'adom': paramgram["adom"],
    }

    url = '/pm/devprof/adom/{adom}/devprof/{name}'.format(adom=paramgram["adom"], name=paramgram["prov_template"])
    response = fmgr.process_request(url, datagram, FMGRMethods.GET)
    return response


def create_model_device(fmgr, paramgram):
    datagram = {
        'adom': paramgram["adom"],
        'flags': ['create_task', 'nonblocking'],
        'groups': [{'name': paramgram["group"], 'vdom': paramgram['vdom']}],
        'device': {
            'mr': paramgram["minor_release"],
            'name': paramgram["name"],
            'sn': paramgram["serial"],
            'mgmt_mode': 'fmg',
            'device action': 'add_model',
            'platform_str': paramgram["platform"],
            'os_ver': paramgram["os_version"],
            'os_type': paramgram["os_type"],
            'patch': paramgram["patch_release"],
            'desc': 'Provisioned by Ansible',
        }
    }

    url = '/dvm/cmd/add/device'
    response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
    return response


def update_flags(fmgr, paramgram):
    datagram = {
        'flags': ['is_model', 'linked_to_model']
    }

    url = 'dvmdb/device/{name}'.format(name=paramgram["name"])
    response = fmgr.process_request(url, datagram, FMGRMethods.UPDATE)
    return response


def assign_provision_template(fmgr, paramgram):
    datagram = {
        'name': paramgram["template"],
        'type': 'devprof',
        'description': 'Provisioned by Ansible',
        'scope member': [{'name': paramgram["target"]}]
    }

    url = "/pm/devprof/adom/{adom}".format(adom=paramgram["adom"])
    response = fmgr.process_request(url, datagram, FMGRMethods.UPDATE)
    return response
#
#
# def set_devprof_scope(self, provisioning_template, adom, provision_targets):
#     """
#     :param fmgr: The fmgr object instance from fortimanager.py
#     :type fmgr: class object
#     :param paramgram: The formatted dictionary of options to process
#     :type paramgram: dict
#     :return: The response from the FortiManager
#     :rtype: dict
#     """
#     fields = dict()
#     targets = []
#     fields["name"] = provisioning_template
#     fields["type"] = "devprof"
#     fields["description"] = "CreatedByAnsible"
#
#     for target in provision_targets.strip().split(","):
#         # split the host on the space to get the mask out
#         new_target = {"name": target}
#         targets.append(new_target)
#
#     fields["scope member"] = targets
#     url = "/pm/devprof/adom/{adom}".format(adom=paramgram["adom"])
#     body = {"method": "set", "params": [{"url": "/pm/devprof/adom/{adom}".format(adom=paramgram["adom"]),
#                                          "data": fields, "session": self.session}]}
#     response = fmgr.process_request(url, body, FMGRMethods.SET)
#     return response


def assign_dev_grp(fmgr, paramgram):
    datagram = {
        'name': paramgram["device_name"],
        'vdom': paramgram["vdom"],
    }

    url = "/dvmdb/adom/{adom}/group/{grp_name}/object member".format(adom=paramgram["adom"],
                                                                     grp_name=paramgram["grp_name"])
    response = fmgr.process_request(url, datagram, FMGRMethods.SET)
    return response


def update_install_target(fmgr, paramgram):
    datagram = {
        'scope member': [{'name': paramgram["device"], 'vdom': paramgram["vdom"]}],
        'type': 'pkg'
    }

    url = '/pm/pkg/adom/{adom}/{pkg_name}'.format(adom=paramgram["adom"], pkg_name=paramgram["policy_package"])
    response = fmgr.process_request(url, datagram, FMGRMethods.UPDATE)
    return response


def install_pp(fmgr, paramgram):
    datagram = {
        'adom': paramgram["adom"],
        'flags': 'nonblocking',
        'pkg': paramgram["policy_package"],
        'scope': [{'name': paramgram["device"], 'vdom': paramgram["vdom"]}],
    }

    url = 'securityconsole/install/package'
    response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
    return response


def main():

    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        vdom=dict(required=False, type="str", default="root"),
        policy_package=dict(required=False, type="str", default="default"),
        name=dict(required=True, type="str"),
        group=dict(required=False, type="str"),
        serial=dict(required=True, type="str"),
        platform=dict(required=False, type="str", default="FortiGate-VM64"),
        description=dict(required=False, type="str"),
        os_version=dict(required=True, type="str"),
        minor_release=dict(required=False, type="str"),
        patch_release=dict(required=False, type="str"),
        os_type=dict(required=False, type="str", default="fos"),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )

    paramgram = {
        "adom": module.params["adom"],
        "vdom": module.params["vdom"],
        "policy_package": module.params["policy_package"],
        "name": module.params["name"],
        "group": module.params["group"],
        "serial": module.params["serial"],
        "platform": module.params["platform"],
        "description": module.params["description"],
        "os_version": module.params["os_version"],
        "minor_release": module.params["minor_release"],
        "patch_release": module.params["patch_release"],
        "os_type": module.params["os_type"],
    }

    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    results = DEFAULT_RESULT_OBJ

    try:
        results = create_model_device(fmgr, paramgram)
        if results[0] != 0:
            module.fail_json(msg="Create model failed", **results)

        results = update_flags(fmgr, paramgram)
        if results[0] != 0:
            module.fail_json(msg="Update device flags failed", **results)

        results = update_install_target(fmgr, paramgram)
        if results[0] != 0:
            module.fail_json(msg="Adding device target to package failed", **results)

        results = install_pp(fmgr, paramgram)
        if results[0] != 0:
            module.fail_json(msg="Installing policy package failed", **results)

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_query

Metadata

Name: fmgr_query

Description: Provides information on data objects within FortiManager so that playbooks can perform conditionals.

Author(s): Luke Weighall (@lweighall)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Luke Weighall

Module Github Link

Parameters
adom
  • Description: The ADOM the configuration should belong to.
  • Required: False
  • default: root
custom_dict
  • Description: ADVANCED USERS ONLY! REQUIRES KNOWLEDGE OF FMGR JSON API!

    DICTIONARY JSON FORMAT ONLY – Custom dictionary/datagram to send to the endpoint.

  • Required: False

custom_endpoint
  • Description: ADVANCED USERS ONLY! REQUIRES KNOWLEDGE OF FMGR JSON API!

    The HTTP Endpoint on FortiManager you wish to GET from.

  • Required: False

device_ip
  • Description: The IP of the device you want to query.
  • Required: False
device_serial
  • Description: The serial number of the device you want to query.
  • Required: False
device_unique_name
  • Description: The desired “friendly” name of the device you want to query.
  • Required: False
nodes
  • Description: A LIST of firewalls in the cluster you want to verify i.e. [“firewall_A”,”firewall_B”].
  • Required: False
object
  • Description: The data object we wish to query (device, package, rule, etc). Will expand choices as improves.
  • Required: True
  • choices: [‘device’, ‘cluster_nodes’, ‘task’, ‘custom’]
task_id
  • Description: The ID of the task you wish to query status on. If left blank and object = ‘task’ a list of tasks are returned.
  • Required: False
Functions
  • fmgr_get_custom
def fmgr_get_custom(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # IF THE CUSTOM DICTIONARY (OFTEN CONTAINING FILTERS) IS DEFINED CREATED THAT
    if paramgram["custom_dict"] is not None:
        datagram = paramgram["custom_dict"]
    else:
        datagram = dict()

    # SET THE CUSTOM ENDPOINT PROVIDED
    url = paramgram["custom_endpoint"]
    # MAKE THE CALL AND RETURN RESULTS
    response = fmgr.process_request(url, datagram, FMGRMethods.GET)
    return response
  • fmgr_get_task_status
def fmgr_get_task_status(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # IF THE TASK_ID IS DEFINED, THEN GET THAT SPECIFIC TASK
    # OTHERWISE, GET ALL RECENT TASKS IN A LIST
    if paramgram["task_id"] is not None:

        datagram = {
            "adom": paramgram["adom"]
        }
        url = '/task/task/{task_id}'.format(task_id=paramgram["task_id"])
        response = fmgr.process_request(url, datagram, FMGRMethods.GET)
    else:
        datagram = {
            "adom": paramgram["adom"]
        }
        url = '/task/task'
        response = fmgr.process_request(url, datagram, FMGRMethods.GET)
    return response
  • fmgr_get_device
def fmgr_get_device(fmgr, paramgram):
    """
    This method is used to get information on devices. This will not work on HA_SLAVE nodes, only top level devices.
    Such as cluster objects and standalone devices.

    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # FIRST TRY TO RUN AN UPDATE ON THE DEVICE
    # RUN A QUICK CLUSTER REFRESH/UPDATE ATTEMPT TO ENSURE WE'RE GETTING THE LATEST INFORMOATION
    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    update_url = '/dvm/cmd/update/device'
    update_dict = {
        "adom": paramgram['adom'],
        "device": paramgram['device_unique_name'],
        "flags": "create_task"
    }
    # DO THE UPDATE CALL
    fmgr.process_request(update_url, update_dict, FMGRMethods.EXEC)

    # SET THE URL
    url = '/dvmdb/adom/{adom}/device'.format(adom=paramgram["adom"])
    device_found = 0
    response = []

    # TRY TO FIND IT FIRST BY SERIAL NUMBER
    if paramgram["device_serial"] is not None:
        datagram = {
            "filter": ["sn", "==", paramgram["device_serial"]]
        }
        response = fmgr.process_request(url, datagram, FMGRMethods.GET)
        if len(response[1]) >= 0:
            device_found = 1

    # CHECK IF ANYTHING WAS RETURNED, IF NOT TRY DEVICE NAME PARAMETER
    if device_found == 0 and paramgram["device_unique_name"] is not None:
        datagram = {
            "filter": ["name", "==", paramgram["device_unique_name"]]
        }
        response = fmgr.process_request(url, datagram, FMGRMethods.GET)
        if len(response[1]) >= 0:
            device_found = 1

    # CHECK IF ANYTHING WAS RETURNED, IF NOT TRY DEVICE IP ADDRESS
    if device_found == 0 and paramgram["device_ip"] is not None:
        datagram = {
            "filter": ["ip", "==", paramgram["device_ip"]]
        }
        response = fmgr.process_request(url, datagram, FMGRMethods.GET)
        if len(response[1]) >= 0:
            device_found = 1

    return response
  • fmgr_get_cluster_nodes
def fmgr_get_cluster_nodes(fmgr, paramgram):
    """
    This method is used to get information on devices. This WILL work on HA_SLAVE nodes, but NOT top level standalone
    devices.
    Such as cluster objects and standalone devices.

    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}
    # USE THE DEVICE METHOD TO GET THE CLUSTER INFORMATION SO WE CAN SEE THE HA_SLAVE NODES
    response = fmgr_get_device(fmgr, paramgram)
    # CHECK FOR HA_SLAVE NODES, IF CLUSTER IS MISSING COMPLETELY THEN QUIT
    try:
        returned_nodes = response[1][0]["ha_slave"]
        num_of_nodes = len(returned_nodes)
    except Exception:
        error_msg = {"cluster_status": "MISSING"}
        return error_msg

    # INIT LOOP RESOURCES
    loop_count = 0
    good_nodes = []
    expected_nodes = list(paramgram["nodes"])
    missing_nodes = list(paramgram["nodes"])
    bad_status_nodes = []

    # LOOP THROUGH THE NODES AND GET THEIR STATUS TO BUILD THE RETURN JSON OBJECT
    # WE'RE ALSO CHECKING THE NODES IF THEY ARE BAD STATUS, OR PLAIN MISSING
    while loop_count < num_of_nodes:
        node_append = {
            "node_name": returned_nodes[loop_count]["name"],
            "node_serial": returned_nodes[loop_count]["sn"],
            "node_parent": returned_nodes[loop_count]["did"],
            "node_status": returned_nodes[loop_count]["status"],
        }
        # IF THE NODE IS IN THE EXPECTED NODES LIST AND WORKING THEN ADD IT TO GOOD NODES LIST
        if node_append["node_name"] in expected_nodes and node_append["node_status"] == 1:
            good_nodes.append(node_append["node_name"])
        # IF THE NODE IS IN THE EXPECTED NODES LIST BUT NOT WORKING THEN ADDED IT TO BAD_STATUS_NODES
        # IF THE NODE STATUS IS NOT 1 THEN ITS BAD
        if node_append["node_name"] in expected_nodes and node_append["node_status"] != 1:
            bad_status_nodes.append(node_append["node_name"])
        # REMOVE THE NODE FROM MISSING NODES LIST IF NOTHING IS WRONG WITH NODE -- LEAVING US A LIST OF
        # NOT WORKING NODES
        missing_nodes.remove(node_append["node_name"])
        loop_count += 1

    # BUILD RETURN OBJECT FROM NODE LISTS
    nodes = {
        "good_nodes": good_nodes,
        "expected_nodes": expected_nodes,
        "missing_nodes": missing_nodes,
        "bad_nodes": bad_status_nodes,
        "query_status": "good",
    }
    if len(nodes["good_nodes"]) == len(nodes["expected_nodes"]):
        nodes["cluster_status"] = "OK"
    else:
        nodes["cluster_status"] = "NOT-COMPLIANT"
    return nodes
  • main
def main():
    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        object=dict(required=True, type="str", choices=["device", "cluster_nodes", "task", "custom"]),
        custom_endpoint=dict(required=False, type="str"),
        custom_dict=dict(required=False, type="dict"),
        device_ip=dict(required=False, type="str"),
        device_unique_name=dict(required=False, type="str"),
        device_serial=dict(required=False, type="str"),
        nodes=dict(required=False, type="list"),
        task_id=dict(required=False, type="str")
    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    paramgram = {
        "adom": module.params["adom"],
        "object": module.params["object"],
        "device_ip": module.params["device_ip"],
        "device_unique_name": module.params["device_unique_name"],
        "device_serial": module.params["device_serial"],
        "nodes": module.params["nodes"],
        "task_id": module.params["task_id"],
        "custom_endpoint": module.params["custom_endpoint"],
        "custom_dict": module.params["custom_dict"]
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    results = DEFAULT_RESULT_OBJ

    try:
        # IF OBJECT IS DEVICE
        if paramgram["object"] == "device" and any(v is not None for v in [paramgram["device_unique_name"],
                                                                           paramgram["device_serial"],
                                                                           paramgram["device_ip"]]):
            results = fmgr_get_device(fmgr, paramgram)
            if results[0] not in [0]:
                module.fail_json(msg="Device query failed!")
            elif len(results[1]) == 0:
                module.exit_json(msg="Device NOT FOUND!")
            else:
                module.exit_json(msg="Device Found", **results[1][0])
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # IF OBJECT IS CLUSTER_NODES
        if paramgram["object"] == "cluster_nodes" and paramgram["nodes"] is not None:
            results = fmgr_get_cluster_nodes(fmgr, paramgram)
            if results["cluster_status"] == "MISSING":
                module.exit_json(msg="No cluster device found!", **results)
            elif results["query_status"] == "good":
                module.exit_json(msg="Cluster Found - Showing Nodes", **results)
            elif results is None:
                module.fail_json(msg="Query FAILED -- Check module or playbook syntax")
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # IF OBJECT IS TASK
        if paramgram["object"] == "task":
            results = fmgr_get_task_status(fmgr, paramgram)
            if results[0] != 0:
                module.fail_json(**results[1])
            if results[0] == 0:
                module.exit_json(**results[1])
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # IF OBJECT IS CUSTOM
        if paramgram["object"] == "custom":
            results = fmgr_get_custom(fmgr, paramgram)
            if results[0] != 0:
                module.fail_json(msg="QUERY FAILED -- Please check syntax check JSON guide if needed.")
            if results[0] == 0:
                results_len = len(results[1])
                if results_len > 0:
                    results_combine = dict()
                    if isinstance(results[1], dict):
                        results_combine["results"] = results[1]
                    if isinstance(results[1], list):
                        results_combine["results"] = results[1][0:results_len]
                    module.exit_json(msg="Custom Query Success", **results_combine)
                else:
                    module.exit_json(msg="NO RESULTS")
    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {
    "metadata_version": "1.1",
    "status": ["preview"],
    "supported_by": "community"
}

DOCUMENTATION = '''
---
module: fmgr_query
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author: Luke Weighall (@lweighall)
short_description: Query FortiManager data objects for use in Ansible workflows.
description:
  - Provides information on data objects within FortiManager so that playbooks can perform conditionals.

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: false
    default: root

  object:
    description:
      - The data object we wish to query (device, package, rule, etc). Will expand choices as improves.
    required: true
    choices:
    - device
    - cluster_nodes
    - task
    - custom

  custom_endpoint:
    description:
        - ADVANCED USERS ONLY! REQUIRES KNOWLEDGE OF FMGR JSON API!
        - The HTTP Endpoint on FortiManager you wish to GET from.
    required: false

  custom_dict:
    description:
        - ADVANCED USERS ONLY! REQUIRES KNOWLEDGE OF FMGR JSON API!
        - DICTIONARY JSON FORMAT ONLY -- Custom dictionary/datagram to send to the endpoint.
    required: false

  device_ip:
    description:
      - The IP of the device you want to query.
    required: false

  device_unique_name:
    description:
      - The desired "friendly" name of the device you want to query.
    required: false

  device_serial:
    description:
      - The serial number of the device you want to query.
    required: false

  task_id:
    description:
      - The ID of the task you wish to query status on. If left blank and object = 'task' a list of tasks are returned.
    required: false

  nodes:
    description:
      - A LIST of firewalls in the cluster you want to verify i.e. ["firewall_A","firewall_B"].
    required: false
'''


EXAMPLES = '''
- name: QUERY FORTIGATE DEVICE BY IP
  fmgr_query:
    object: "device"
    adom: "ansible"
    device_ip: "10.7.220.41"

- name: QUERY FORTIGATE DEVICE BY SERIAL
  fmgr_query:
    adom: "ansible"
    object: "device"
    device_serial: "FGVM000000117992"

- name: QUERY FORTIGATE DEVICE BY FRIENDLY NAME
  fmgr_query:
    adom: "ansible"
    object: "device"
    device_unique_name: "ansible-fgt01"

- name: VERIFY CLUSTER MEMBERS AND STATUS
  fmgr_query:
    adom: "ansible"
    object: "cluster_nodes"
    device_unique_name: "fgt-cluster01"
    nodes: ["ansible-fgt01", "ansible-fgt02", "ansible-fgt03"]

- name: GET STATUS OF TASK ID
  fmgr_query:
    adom: "ansible"
    object: "task"
    task_id: "3"

- name: USE CUSTOM TYPE TO QUERY AVAILABLE SCRIPTS
  fmgr_query:
    adom: "ansible"
    object: "custom"
    custom_endpoint: "/dvmdb/adom/ansible/script"
    custom_dict: { "type": "cli" }
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import FMGRMethods
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG


def fmgr_get_custom(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # IF THE CUSTOM DICTIONARY (OFTEN CONTAINING FILTERS) IS DEFINED CREATED THAT
    if paramgram["custom_dict"] is not None:
        datagram = paramgram["custom_dict"]
    else:
        datagram = dict()

    # SET THE CUSTOM ENDPOINT PROVIDED
    url = paramgram["custom_endpoint"]
    # MAKE THE CALL AND RETURN RESULTS
    response = fmgr.process_request(url, datagram, FMGRMethods.GET)
    return response


def fmgr_get_task_status(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # IF THE TASK_ID IS DEFINED, THEN GET THAT SPECIFIC TASK
    # OTHERWISE, GET ALL RECENT TASKS IN A LIST
    if paramgram["task_id"] is not None:

        datagram = {
            "adom": paramgram["adom"]
        }
        url = '/task/task/{task_id}'.format(task_id=paramgram["task_id"])
        response = fmgr.process_request(url, datagram, FMGRMethods.GET)
    else:
        datagram = {
            "adom": paramgram["adom"]
        }
        url = '/task/task'
        response = fmgr.process_request(url, datagram, FMGRMethods.GET)
    return response


def fmgr_get_device(fmgr, paramgram):
    """
    This method is used to get information on devices. This will not work on HA_SLAVE nodes, only top level devices.
    Such as cluster objects and standalone devices.

    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    # FIRST TRY TO RUN AN UPDATE ON THE DEVICE
    # RUN A QUICK CLUSTER REFRESH/UPDATE ATTEMPT TO ENSURE WE'RE GETTING THE LATEST INFORMOATION
    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    update_url = '/dvm/cmd/update/device'
    update_dict = {
        "adom": paramgram['adom'],
        "device": paramgram['device_unique_name'],
        "flags": "create_task"
    }
    # DO THE UPDATE CALL
    fmgr.process_request(update_url, update_dict, FMGRMethods.EXEC)

    # SET THE URL
    url = '/dvmdb/adom/{adom}/device'.format(adom=paramgram["adom"])
    device_found = 0
    response = []

    # TRY TO FIND IT FIRST BY SERIAL NUMBER
    if paramgram["device_serial"] is not None:
        datagram = {
            "filter": ["sn", "==", paramgram["device_serial"]]
        }
        response = fmgr.process_request(url, datagram, FMGRMethods.GET)
        if len(response[1]) >= 0:
            device_found = 1

    # CHECK IF ANYTHING WAS RETURNED, IF NOT TRY DEVICE NAME PARAMETER
    if device_found == 0 and paramgram["device_unique_name"] is not None:
        datagram = {
            "filter": ["name", "==", paramgram["device_unique_name"]]
        }
        response = fmgr.process_request(url, datagram, FMGRMethods.GET)
        if len(response[1]) >= 0:
            device_found = 1

    # CHECK IF ANYTHING WAS RETURNED, IF NOT TRY DEVICE IP ADDRESS
    if device_found == 0 and paramgram["device_ip"] is not None:
        datagram = {
            "filter": ["ip", "==", paramgram["device_ip"]]
        }
        response = fmgr.process_request(url, datagram, FMGRMethods.GET)
        if len(response[1]) >= 0:
            device_found = 1

    return response


def fmgr_get_cluster_nodes(fmgr, paramgram):
    """
    This method is used to get information on devices. This WILL work on HA_SLAVE nodes, but NOT top level standalone
    devices.
    Such as cluster objects and standalone devices.

    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}
    # USE THE DEVICE METHOD TO GET THE CLUSTER INFORMATION SO WE CAN SEE THE HA_SLAVE NODES
    response = fmgr_get_device(fmgr, paramgram)
    # CHECK FOR HA_SLAVE NODES, IF CLUSTER IS MISSING COMPLETELY THEN QUIT
    try:
        returned_nodes = response[1][0]["ha_slave"]
        num_of_nodes = len(returned_nodes)
    except Exception:
        error_msg = {"cluster_status": "MISSING"}
        return error_msg

    # INIT LOOP RESOURCES
    loop_count = 0
    good_nodes = []
    expected_nodes = list(paramgram["nodes"])
    missing_nodes = list(paramgram["nodes"])
    bad_status_nodes = []

    # LOOP THROUGH THE NODES AND GET THEIR STATUS TO BUILD THE RETURN JSON OBJECT
    # WE'RE ALSO CHECKING THE NODES IF THEY ARE BAD STATUS, OR PLAIN MISSING
    while loop_count < num_of_nodes:
        node_append = {
            "node_name": returned_nodes[loop_count]["name"],
            "node_serial": returned_nodes[loop_count]["sn"],
            "node_parent": returned_nodes[loop_count]["did"],
            "node_status": returned_nodes[loop_count]["status"],
        }
        # IF THE NODE IS IN THE EXPECTED NODES LIST AND WORKING THEN ADD IT TO GOOD NODES LIST
        if node_append["node_name"] in expected_nodes and node_append["node_status"] == 1:
            good_nodes.append(node_append["node_name"])
        # IF THE NODE IS IN THE EXPECTED NODES LIST BUT NOT WORKING THEN ADDED IT TO BAD_STATUS_NODES
        # IF THE NODE STATUS IS NOT 1 THEN ITS BAD
        if node_append["node_name"] in expected_nodes and node_append["node_status"] != 1:
            bad_status_nodes.append(node_append["node_name"])
        # REMOVE THE NODE FROM MISSING NODES LIST IF NOTHING IS WRONG WITH NODE -- LEAVING US A LIST OF
        # NOT WORKING NODES
        missing_nodes.remove(node_append["node_name"])
        loop_count += 1

    # BUILD RETURN OBJECT FROM NODE LISTS
    nodes = {
        "good_nodes": good_nodes,
        "expected_nodes": expected_nodes,
        "missing_nodes": missing_nodes,
        "bad_nodes": bad_status_nodes,
        "query_status": "good",
    }
    if len(nodes["good_nodes"]) == len(nodes["expected_nodes"]):
        nodes["cluster_status"] = "OK"
    else:
        nodes["cluster_status"] = "NOT-COMPLIANT"
    return nodes


def main():
    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        object=dict(required=True, type="str", choices=["device", "cluster_nodes", "task", "custom"]),
        custom_endpoint=dict(required=False, type="str"),
        custom_dict=dict(required=False, type="dict"),
        device_ip=dict(required=False, type="str"),
        device_unique_name=dict(required=False, type="str"),
        device_serial=dict(required=False, type="str"),
        nodes=dict(required=False, type="list"),
        task_id=dict(required=False, type="str")
    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    paramgram = {
        "adom": module.params["adom"],
        "object": module.params["object"],
        "device_ip": module.params["device_ip"],
        "device_unique_name": module.params["device_unique_name"],
        "device_serial": module.params["device_serial"],
        "nodes": module.params["nodes"],
        "task_id": module.params["task_id"],
        "custom_endpoint": module.params["custom_endpoint"],
        "custom_dict": module.params["custom_dict"]
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    results = DEFAULT_RESULT_OBJ

    try:
        # IF OBJECT IS DEVICE
        if paramgram["object"] == "device" and any(v is not None for v in [paramgram["device_unique_name"],
                                                                           paramgram["device_serial"],
                                                                           paramgram["device_ip"]]):
            results = fmgr_get_device(fmgr, paramgram)
            if results[0] not in [0]:
                module.fail_json(msg="Device query failed!")
            elif len(results[1]) == 0:
                module.exit_json(msg="Device NOT FOUND!")
            else:
                module.exit_json(msg="Device Found", **results[1][0])
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # IF OBJECT IS CLUSTER_NODES
        if paramgram["object"] == "cluster_nodes" and paramgram["nodes"] is not None:
            results = fmgr_get_cluster_nodes(fmgr, paramgram)
            if results["cluster_status"] == "MISSING":
                module.exit_json(msg="No cluster device found!", **results)
            elif results["query_status"] == "good":
                module.exit_json(msg="Cluster Found - Showing Nodes", **results)
            elif results is None:
                module.fail_json(msg="Query FAILED -- Check module or playbook syntax")
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # IF OBJECT IS TASK
        if paramgram["object"] == "task":
            results = fmgr_get_task_status(fmgr, paramgram)
            if results[0] != 0:
                module.fail_json(**results[1])
            if results[0] == 0:
                module.exit_json(**results[1])
    except Exception as err:
        raise FMGBaseException(err)

    try:
        # IF OBJECT IS CUSTOM
        if paramgram["object"] == "custom":
            results = fmgr_get_custom(fmgr, paramgram)
            if results[0] != 0:
                module.fail_json(msg="QUERY FAILED -- Please check syntax check JSON guide if needed.")
            if results[0] == 0:
                results_len = len(results[1])
                if results_len > 0:
                    results_combine = dict()
                    if isinstance(results[1], dict):
                        results_combine["results"] = results[1]
                    if isinstance(results[1], list):
                        results_combine["results"] = results[1][0:results_len]
                    module.exit_json(msg="Custom Query Success", **results_combine)
                else:
                    module.exit_json(msg="NO RESULTS")
    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_script

Metadata

Name: fmgr_script

Description: Create/edit/delete scripts and execute the scripts on the FortiManager using jsonrpc API

Author(s): Andrew Welsh (@Ghilli3)

Ansible Version Added/Required: 2.5

Dev Status: COMPLETED/MERGED

Owning Developer: Andrew Welsh

Module Github Link

Parameters
adom
  • Description: The administrative domain (admon) the configuration belongs to
  • Required: True
mode
  • Description: The desired mode of the specified object. Execute will run the script.
  • Required: False
  • default: add
  • choices: [‘add’, ‘delete’, ‘execute’, ‘set’]
script_content
  • Description: The script content that will be executed.
  • Required: False
script_description
  • Description: The description of the script.
  • Required: False
script_name
  • Description: The name of the script.
  • Required: True
script_package
  • Description: (datasource) Policy package object to run the script against
  • Required: False
script_scope
  • Description: (datasource) The devices that the script will run on, can have both device member and device group member.
  • Required: False
script_target
  • Description: The target of the script to be run.
  • Required: False
script_type
  • Description: The type of script (CLI or TCL).
  • Required: False
vdom
  • Description: The virtual domain (vdom) the configuration belongs to
Functions
  • set_script
def set_script(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    datagram = {
        'content': paramgram["script_content"],
        'desc': paramgram["script_description"],
        'name': paramgram["script_name"],
        'target': paramgram["script_target"],
        'type': paramgram["script_type"],
    }

    url = '/dvmdb/adom/{adom}/script/'.format(adom=paramgram["adom"])
    response = fmgr.process_request(url, datagram, FMGRMethods.SET)
    return response
  • delete_script
def delete_script(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    datagram = {
        'name': paramgram["script_name"],
    }

    url = '/dvmdb/adom/{adom}/script/{script_name}'.format(adom=paramgram["adom"], script_name=paramgram["script_name"])
    response = fmgr.process_request(url, datagram, FMGRMethods.DELETE)
    return response
  • execute_script
def execute_script(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    scope_list = list()
    scope = paramgram["script_scope"].replace(' ', '')
    scope = scope.split(',')
    for dev_name in scope:
        scope_list.append({'name': dev_name, 'vdom': paramgram["vdom"]})

    datagram = {
        'adom': paramgram["adom"],
        'script': paramgram["script_name"],
        'package': paramgram["script_package"],
        'scope': scope_list,
    }

    url = '/dvmdb/adom/{adom}/script/execute'.format(adom=paramgram["adom"])
    response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
    return response
  • main
def main():
    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        vdom=dict(required=False, type="str", default="root"),
        mode=dict(choices=["add", "execute", "set", "delete"], type="str", default="add"),
        script_name=dict(required=True, type="str"),
        script_type=dict(required=False, type="str"),
        script_target=dict(required=False, type="str"),
        script_description=dict(required=False, type="str"),
        script_content=dict(required=False, type="str"),
        script_scope=dict(required=False, type="str"),
        script_package=dict(required=False, type="str"),
    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    paramgram = {
        "script_name": module.params["script_name"],
        "script_type": module.params["script_type"],
        "script_target": module.params["script_target"],
        "script_description": module.params["script_description"],
        "script_content": module.params["script_content"],
        "script_scope": module.params["script_scope"],
        "script_package": module.params["script_package"],
        "adom": module.params["adom"],
        "vdom": module.params["vdom"],
        "mode": module.params["mode"],
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    results = DEFAULT_RESULT_OBJ

    try:
        if paramgram["mode"] in ['add', 'set']:
            results = set_script(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, msg="Operation Finished",
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, module.params))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        if paramgram["mode"] == "execute":
            results = execute_script(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, msg="Operation Finished",
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, module.params))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        if paramgram["mode"] == "delete":
            results = delete_script(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, msg="Operation Finished",
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, module.params))
    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function

__metaclass__ = type

ANSIBLE_METADATA = {'status': ['preview'],
                    'supported_by': 'community',
                    'metadata_version': '1.1'}

DOCUMENTATION = '''
---
module: fmgr_script
version_added: "2.5"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author: Andrew Welsh (@Ghilli3)
short_description: Add/Edit/Delete and execute scripts
description: Create/edit/delete scripts and execute the scripts on the FortiManager using jsonrpc API

options:
  adom:
    description:
      - The administrative domain (admon) the configuration belongs to
    required: true

  vdom:
    description:
      - The virtual domain (vdom) the configuration belongs to

  mode:
    description:
      - The desired mode of the specified object. Execute will run the script.
    required: false
    default: "add"
    choices: ["add", "delete", "execute", "set"]
    version_added: "2.8"

  script_name:
    description:
      - The name of the script.
    required: True

  script_type:
    description:
      - The type of script (CLI or TCL).
    required: false

  script_target:
    description:
      - The target of the script to be run.
    required: false

  script_description:
    description:
      - The description of the script.
    required: false

  script_content:
    description:
      - The script content that will be executed.
    required: false

  script_scope:
    description:
      - (datasource) The devices that the script will run on, can have both device member and device group member.
    required: false

  script_package:
    description:
      - (datasource) Policy package object to run the script against
    required: false
'''

EXAMPLES = '''
- name: CREATE SCRIPT
  fmgr_script:
    adom: "root"
    script_name: "TestScript"
    script_type: "cli"
    script_target: "remote_device"
    script_description: "Create by Ansible"
    script_content: "get system status"

- name: EXECUTE SCRIPT
  fmgr_script:
    adom: "root"
    script_name: "TestScript"
    mode: "execute"
    script_scope: "FGT1,FGT2"

- name: DELETE SCRIPT
  fmgr_script:
    adom: "root"
    script_name: "TestScript"
    mode: "delete"
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import FMGRMethods
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG


def set_script(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    datagram = {
        'content': paramgram["script_content"],
        'desc': paramgram["script_description"],
        'name': paramgram["script_name"],
        'target': paramgram["script_target"],
        'type': paramgram["script_type"],
    }

    url = '/dvmdb/adom/{adom}/script/'.format(adom=paramgram["adom"])
    response = fmgr.process_request(url, datagram, FMGRMethods.SET)
    return response


def delete_script(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    datagram = {
        'name': paramgram["script_name"],
    }

    url = '/dvmdb/adom/{adom}/script/{script_name}'.format(adom=paramgram["adom"], script_name=paramgram["script_name"])
    response = fmgr.process_request(url, datagram, FMGRMethods.DELETE)
    return response


def execute_script(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    scope_list = list()
    scope = paramgram["script_scope"].replace(' ', '')
    scope = scope.split(',')
    for dev_name in scope:
        scope_list.append({'name': dev_name, 'vdom': paramgram["vdom"]})

    datagram = {
        'adom': paramgram["adom"],
        'script': paramgram["script_name"],
        'package': paramgram["script_package"],
        'scope': scope_list,
    }

    url = '/dvmdb/adom/{adom}/script/execute'.format(adom=paramgram["adom"])
    response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
    return response


def main():
    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        vdom=dict(required=False, type="str", default="root"),
        mode=dict(choices=["add", "execute", "set", "delete"], type="str", default="add"),
        script_name=dict(required=True, type="str"),
        script_type=dict(required=False, type="str"),
        script_target=dict(required=False, type="str"),
        script_description=dict(required=False, type="str"),
        script_content=dict(required=False, type="str"),
        script_scope=dict(required=False, type="str"),
        script_package=dict(required=False, type="str"),
    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    paramgram = {
        "script_name": module.params["script_name"],
        "script_type": module.params["script_type"],
        "script_target": module.params["script_target"],
        "script_description": module.params["script_description"],
        "script_content": module.params["script_content"],
        "script_scope": module.params["script_scope"],
        "script_package": module.params["script_package"],
        "adom": module.params["adom"],
        "vdom": module.params["vdom"],
        "mode": module.params["mode"],
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    results = DEFAULT_RESULT_OBJ

    try:
        if paramgram["mode"] in ['add', 'set']:
            results = set_script(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, msg="Operation Finished",
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, module.params))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        if paramgram["mode"] == "execute":
            results = execute_script(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, msg="Operation Finished",
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, module.params))
    except Exception as err:
        raise FMGBaseException(err)

    try:
        if paramgram["mode"] == "delete":
            results = delete_script(fmgr, paramgram)
            fmgr.govern_response(module=module, results=results, msg="Operation Finished",
                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, module.params))
    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_secprof_appctrl

Metadata

Name: fmgr_secprof_appctrl

Description: Manage application control security profiles within FortiManager

Author(s):

  • Luke Weighall (github: @lweighall)
  • Andrew Welsh (github: @Ghilli3)
  • Jim Huber (github: @p4r4n0y1ng)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Andrew Welsh

Module Github Link

Parameters
adom
  • Description: The ADOM the configuration should belong to.
  • Required: False
  • default: root
app_replacemsg
  • Description: Enable/disable replacement messages for blocked applications.

    choice | disable | Disable replacement messages for blocked applications.

    choice | enable | Enable replacement messages for blocked applications.

  • Required: False

  • choices: [‘disable’, ‘enable’]

comment
  • Description: comments
  • Required: False
deep_app_inspection
  • Description: Enable/disable deep application inspection.

    choice | disable | Disable deep application inspection.

    choice | enable | Enable deep application inspection.

  • Required: False

  • choices: [‘disable’, ‘enable’]

entries
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED. This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, OMIT THE USE OF THIS PARAMETER

    AND USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

entries_action
  • Description: Pass or block traffic, or reset connection for traffic from this application.

    choice | pass | Pass or allow matching traffic.

    choice | block | Block or drop matching traffic.

    choice | reset | Reset sessions for matching traffic.

  • Required: False

  • choices: [‘pass’, ‘block’, ‘reset’]

entries_application
  • Description: ID of allowed applications.
  • Required: False
entries_behavior
  • Description: Application behavior filter.
  • Required: False
entries_category
  • Description: Category ID list.
  • Required: False
entries_log
  • Description: Enable/disable logging for this application list.

    choice | disable | Disable logging.

    choice | enable | Enable logging.

  • Required: False

  • choices: [‘disable’, ‘enable’]

entries_log_packet
  • Description: Enable/disable packet logging.

    choice | disable | Disable packet logging.

    choice | enable | Enable packet logging.

  • Required: False

  • choices: [‘disable’, ‘enable’]

entries_parameters_value
  • Description: Parameter value.
  • Required: False
entries_per_ip_shaper
  • Description: Per-IP traffic shaper.
  • Required: False
entries_popularity
  • Description: Application popularity filter (1 - 5, from least to most popular).

    FLAG Based Options. Specify multiple in list form.

    flag | 1 | Popularity level 1.

    flag | 2 | Popularity level 2.

    flag | 3 | Popularity level 3.

    flag | 4 | Popularity level 4.

    flag | 5 | Popularity level 5.

  • Required: False

  • choices: [‘1’, ‘2’, ‘3’, ‘4’, ‘5’]

entries_protocols
  • Description: Application protocol filter.
  • Required: False
entries_quarantine
  • Description: Quarantine method.

    choice | none | Quarantine is disabled.

    choice | attacker | Block all traffic sent from attacker’s IP address.

    The attacker’s IP address is also added to the banned user list. The target’s address is not affected.

  • Required: False

  • choices: [‘none’, ‘attacker’]

entries_quarantine_expiry
  • Description: Duration of quarantine. (Format

    Requires quarantine set to attacker.

  • Required: False

entries_quarantine_log
  • Description: Enable/disable quarantine logging.

    choice | disable | Disable quarantine logging.

    choice | enable | Enable quarantine logging.

  • Required: False

  • choices: [‘disable’, ‘enable’]

entries_rate_count
  • Description: Count of the rate.
  • Required: False
entries_rate_duration
  • Description: Duration (sec) of the rate.
  • Required: False
entries_rate_mode
  • Description: Rate limit mode.

    choice | periodical | Allow configured number of packets every rate-duration.

    choice | continuous | Block packets once the rate is reached.

  • Required: False

  • choices: [‘periodical’, ‘continuous’]

entries_rate_track
  • Description: Track the packet protocol field.

    choice | none |

    choice | src-ip | Source IP.

    choice | dest-ip | Destination IP.

    choice | dhcp-client-mac | DHCP client.

    choice | dns-domain | DNS domain.

  • Required: False

  • choices: [‘none’, ‘src-ip’, ‘dest-ip’, ‘dhcp-client-mac’, ‘dns-domain’]

entries_risk
  • Description: Risk, or impact, of allowing traffic from this application to occur 1 - 5;

    (Low, Elevated, Medium, High, and Critical).

  • Required: False

entries_session_ttl
  • Description: Session TTL (0 = default).
  • Required: False
entries_shaper
  • Description: Traffic shaper.
  • Required: False
entries_shaper_reverse
  • Description: Reverse traffic shaper.
  • Required: False
entries_sub_category
  • Description: Application Sub-category ID list.
  • Required: False
entries_technology
  • Description: Application technology filter.
  • Required: False
entries_vendor
  • Description: Application vendor filter.
  • Required: False
extended_log
  • Description: Enable/disable extended logging.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

mode
  • Description: Sets one of three modes for managing the object.

    Allows use of soft-adds instead of overwriting existing values

  • Required: False

  • default: add

  • choices: [‘add’, ‘set’, ‘delete’, ‘update’]

name
  • Description: List name.
  • Required: False
options
  • Description: NO DESCRIPTION PARSED ENTER MANUALLY

    FLAG Based Options. Specify multiple in list form.

    flag | allow-dns | Allow DNS.

    flag | allow-icmp | Allow ICMP.

    flag | allow-http | Allow generic HTTP web browsing.

    flag | allow-ssl | Allow generic SSL communication.

    flag | allow-quic | Allow QUIC.

  • Required: False

  • choices: [‘allow-dns’, ‘allow-icmp’, ‘allow-http’, ‘allow-ssl’, ‘allow-quic’]

other_application_action
  • Description: Action for other applications.

    choice | pass | Allow sessions matching an application in this application list.

    choice | block | Block sessions matching an application in this application list.

  • Required: False

  • choices: [‘pass’, ‘block’]

other_application_log
  • Description: Enable/disable logging for other applications.

    choice | disable | Disable logging for other applications.

    choice | enable | Enable logging for other applications.

  • Required: False

  • choices: [‘disable’, ‘enable’]

p2p_black_list
  • Description: NO DESCRIPTION PARSED ENTER MANUALLY

    FLAG Based Options. Specify multiple in list form.

    flag | skype | Skype.

    flag | edonkey | Edonkey.

    flag | bittorrent | Bit torrent.

  • Required: False

  • choices: [‘skype’, ‘edonkey’, ‘bittorrent’]

replacemsg_group
  • Description: Replacement message group.
  • Required: False
unknown_application_action
  • Description: Pass or block traffic from unknown applications.

    choice | pass | Pass or allow unknown applications.

    choice | block | Drop or block unknown applications.

  • Required: False

  • choices: [‘pass’, ‘block’]

unknown_application_log
  • Description: Enable/disable logging for unknown applications.

    choice | disable | Disable logging for unknown applications.

    choice | enable | Enable logging for unknown applications.

  • Required: False

  • choices: [‘disable’, ‘enable’]

Functions
  • fmgr_application_list_modify
def fmgr_application_list_modify(fmgr, paramgram):
    """
    fmgr_application_list -- Modifies Application Control Profiles on FortiManager

    :param fmgr: The fmgr object instance from fmgr_utils.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict

    :return: The response from the FortiManager
    :rtype: dict
    """
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if paramgram["mode"] in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/application/list'.format(adom=paramgram["adom"])
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif paramgram["mode"] == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/application/list/{name}'.format(adom=paramgram["adom"],
                                                                          name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


#############
# END METHODS
#############
  • main
def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        unknown_application_log=dict(required=False, type="str", choices=["disable", "enable"]),
        unknown_application_action=dict(required=False, type="str", choices=["pass", "block"]),
        replacemsg_group=dict(required=False, type="str"),
        p2p_black_list=dict(required=False, type="str", choices=["skype", "edonkey", "bittorrent"]),
        other_application_log=dict(required=False, type="str", choices=["disable", "enable"]),
        other_application_action=dict(required=False, type="str", choices=["pass", "block"]),
        options=dict(required=False, type="str",
                     choices=["allow-dns", "allow-icmp", "allow-http", "allow-ssl", "allow-quic"]),
        name=dict(required=False, type="str"),
        extended_log=dict(required=False, type="str", choices=["disable", "enable"]),
        deep_app_inspection=dict(required=False, type="str", choices=["disable", "enable"]),
        comment=dict(required=False, type="str"),
        app_replacemsg=dict(required=False, type="str", choices=["disable", "enable"]),
        entries=dict(required=False, type="list"),
        entries_action=dict(required=False, type="str", choices=["pass", "block", "reset"]),
        entries_application=dict(required=False, type="str"),
        entries_behavior=dict(required=False, type="str"),
        entries_category=dict(required=False, type="str"),
        entries_log=dict(required=False, type="str", choices=["disable", "enable"]),
        entries_log_packet=dict(required=False, type="str", choices=["disable", "enable"]),
        entries_per_ip_shaper=dict(required=False, type="str"),
        entries_popularity=dict(required=False, type="str", choices=["1", "2", "3", "4", "5"]),
        entries_protocols=dict(required=False, type="str"),
        entries_quarantine=dict(required=False, type="str", choices=["none", "attacker"]),
        entries_quarantine_expiry=dict(required=False, type="str"),
        entries_quarantine_log=dict(required=False, type="str", choices=["disable", "enable"]),
        entries_rate_count=dict(required=False, type="int"),
        entries_rate_duration=dict(required=False, type="int"),
        entries_rate_mode=dict(required=False, type="str", choices=["periodical", "continuous"]),
        entries_rate_track=dict(required=False, type="str",
                                choices=["none", "src-ip", "dest-ip", "dhcp-client-mac", "dns-domain"]),
        entries_risk=dict(required=False, type="str"),
        entries_session_ttl=dict(required=False, type="int"),
        entries_shaper=dict(required=False, type="str"),
        entries_shaper_reverse=dict(required=False, type="str"),
        entries_sub_category=dict(required=False, type="str"),
        entries_technology=dict(required=False, type="str"),
        entries_vendor=dict(required=False, type="str"),

        entries_parameters_value=dict(required=False, type="str"),

    )
    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "unknown-application-log": module.params["unknown_application_log"],
        "unknown-application-action": module.params["unknown_application_action"],
        "replacemsg-group": module.params["replacemsg_group"],
        "p2p-black-list": module.params["p2p_black_list"],
        "other-application-log": module.params["other_application_log"],
        "other-application-action": module.params["other_application_action"],
        "options": module.params["options"],
        "name": module.params["name"],
        "extended-log": module.params["extended_log"],
        "deep-app-inspection": module.params["deep_app_inspection"],
        "comment": module.params["comment"],
        "app-replacemsg": module.params["app_replacemsg"],
        "entries": {
            "action": module.params["entries_action"],
            "application": module.params["entries_application"],
            "behavior": module.params["entries_behavior"],
            "category": module.params["entries_category"],
            "log": module.params["entries_log"],
            "log-packet": module.params["entries_log_packet"],
            "per-ip-shaper": module.params["entries_per_ip_shaper"],
            "popularity": module.params["entries_popularity"],
            "protocols": module.params["entries_protocols"],
            "quarantine": module.params["entries_quarantine"],
            "quarantine-expiry": module.params["entries_quarantine_expiry"],
            "quarantine-log": module.params["entries_quarantine_log"],
            "rate-count": module.params["entries_rate_count"],
            "rate-duration": module.params["entries_rate_duration"],
            "rate-mode": module.params["entries_rate_mode"],
            "rate-track": module.params["entries_rate_track"],
            "risk": module.params["entries_risk"],
            "session-ttl": module.params["entries_session_ttl"],
            "shaper": module.params["entries_shaper"],
            "shaper-reverse": module.params["entries_shaper_reverse"],
            "sub-category": module.params["entries_sub_category"],
            "technology": module.params["entries_technology"],
            "vendor": module.params["entries_vendor"],
            "parameters": {
                "value": module.params["entries_parameters_value"],
            }
        }
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['entries']
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)

    results = DEFAULT_RESULT_OBJ
    try:
        results = fmgr_application_list_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function

__metaclass__ = type

ANSIBLE_METADATA = {'status': ['preview'],
                    'supported_by': 'community',
                    'metadata_version': '1.1'}

DOCUMENTATION = '''
---
module: fmgr_secprof_appctrl
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author:
    - Luke Weighall (@lweighall)
    - Andrew Welsh (@Ghilli3)
    - Jim Huber (@p4r4n0y1ng)
short_description: Manage application control security profiles
description:
  -  Manage application control security profiles within FortiManager

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: false
    default: root

  mode:
    description:
      - Sets one of three modes for managing the object.
      - Allows use of soft-adds instead of overwriting existing values
    choices: ['add', 'set', 'delete', 'update']
    required: false
    default: add

  unknown_application_log:
    description:
      - Enable/disable logging for unknown applications.
      - choice | disable | Disable logging for unknown applications.
      - choice | enable | Enable logging for unknown applications.
    required: false
    choices: ["disable", "enable"]

  unknown_application_action:
    description:
      - Pass or block traffic from unknown applications.
      - choice | pass | Pass or allow unknown applications.
      - choice | block | Drop or block unknown applications.
    required: false
    choices: ["pass", "block"]

  replacemsg_group:
    description:
      - Replacement message group.
    required: false

  p2p_black_list:
    description:
      - NO DESCRIPTION PARSED ENTER MANUALLY
      - FLAG Based Options. Specify multiple in list form.
      - flag | skype | Skype.
      - flag | edonkey | Edonkey.
      - flag | bittorrent | Bit torrent.
    required: false
    choices: ["skype", "edonkey", "bittorrent"]

  other_application_log:
    description:
      - Enable/disable logging for other applications.
      - choice | disable | Disable logging for other applications.
      - choice | enable | Enable logging for other applications.
    required: false
    choices: ["disable", "enable"]

  other_application_action:
    description:
      - Action for other applications.
      - choice | pass | Allow sessions matching an application in this application list.
      - choice | block | Block sessions matching an application in this application list.
    required: false
    choices: ["pass", "block"]

  options:
    description:
      - NO DESCRIPTION PARSED ENTER MANUALLY
      - FLAG Based Options. Specify multiple in list form.
      - flag | allow-dns | Allow DNS.
      - flag | allow-icmp | Allow ICMP.
      - flag | allow-http | Allow generic HTTP web browsing.
      - flag | allow-ssl | Allow generic SSL communication.
      - flag | allow-quic | Allow QUIC.
    required: false
    choices: ["allow-dns", "allow-icmp", "allow-http", "allow-ssl", "allow-quic"]

  name:
    description:
      - List name.
    required: false

  extended_log:
    description:
      - Enable/disable extended logging.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  deep_app_inspection:
    description:
      - Enable/disable deep application inspection.
      - choice | disable | Disable deep application inspection.
      - choice | enable | Enable deep application inspection.
    required: false
    choices: ["disable", "enable"]

  comment:
    description:
      - comments
    required: false

  app_replacemsg:
    description:
      - Enable/disable replacement messages for blocked applications.
      - choice | disable | Disable replacement messages for blocked applications.
      - choice | enable | Enable replacement messages for blocked applications.
    required: false
    choices: ["disable", "enable"]

  entries:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED. This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, OMIT THE USE OF THIS PARAMETER
      - AND USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  entries_action:
    description:
      - Pass or block traffic, or reset connection for traffic from this application.
      - choice | pass | Pass or allow matching traffic.
      - choice | block | Block or drop matching traffic.
      - choice | reset | Reset sessions for matching traffic.
    required: false
    choices: ["pass", "block", "reset"]

  entries_application:
    description:
      - ID of allowed applications.
    required: false

  entries_behavior:
    description:
      - Application behavior filter.
    required: false

  entries_category:
    description:
      - Category ID list.
    required: false

  entries_log:
    description:
      - Enable/disable logging for this application list.
      - choice | disable | Disable logging.
      - choice | enable | Enable logging.
    required: false
    choices: ["disable", "enable"]

  entries_log_packet:
    description:
      - Enable/disable packet logging.
      - choice | disable | Disable packet logging.
      - choice | enable | Enable packet logging.
    required: false
    choices: ["disable", "enable"]

  entries_per_ip_shaper:
    description:
      - Per-IP traffic shaper.
    required: false

  entries_popularity:
    description:
      - Application popularity filter (1 - 5, from least to most popular).
      - FLAG Based Options. Specify multiple in list form.
      - flag | 1 | Popularity level 1.
      - flag | 2 | Popularity level 2.
      - flag | 3 | Popularity level 3.
      - flag | 4 | Popularity level 4.
      - flag | 5 | Popularity level 5.
    required: false
    choices: ["1", "2", "3", "4", "5"]

  entries_protocols:
    description:
      - Application protocol filter.
    required: false

  entries_quarantine:
    description:
      - Quarantine method.
      - choice | none | Quarantine is disabled.
      - choice | attacker | Block all traffic sent from attacker's IP address.
      - The attacker's IP address is also added to the banned user list. The target's address is not affected.
    required: false
    choices: ["none", "attacker"]

  entries_quarantine_expiry:
    description:
      - Duration of quarantine. (Format ###d##h##m, minimum 1m, maximum 364d23h59m, default = 5m).
      - Requires quarantine set to attacker.
    required: false

  entries_quarantine_log:
    description:
      - Enable/disable quarantine logging.
      - choice | disable | Disable quarantine logging.
      - choice | enable | Enable quarantine logging.
    required: false
    choices: ["disable", "enable"]

  entries_rate_count:
    description:
      - Count of the rate.
    required: false

  entries_rate_duration:
    description:
      - Duration (sec) of the rate.
    required: false

  entries_rate_mode:
    description:
      - Rate limit mode.
      - choice | periodical | Allow configured number of packets every rate-duration.
      - choice | continuous | Block packets once the rate is reached.
    required: false
    choices: ["periodical", "continuous"]

  entries_rate_track:
    description:
      - Track the packet protocol field.
      - choice | none |
      - choice | src-ip | Source IP.
      - choice | dest-ip | Destination IP.
      - choice | dhcp-client-mac | DHCP client.
      - choice | dns-domain | DNS domain.
    required: false
    choices: ["none", "src-ip", "dest-ip", "dhcp-client-mac", "dns-domain"]

  entries_risk:
    description:
      - Risk, or impact, of allowing traffic from this application to occur 1 - 5;
      - (Low, Elevated, Medium, High, and Critical).
    required: false

  entries_session_ttl:
    description:
      - Session TTL (0 = default).
    required: false

  entries_shaper:
    description:
      - Traffic shaper.
    required: false

  entries_shaper_reverse:
    description:
      - Reverse traffic shaper.
    required: false

  entries_sub_category:
    description:
      - Application Sub-category ID list.
    required: false

  entries_technology:
    description:
      - Application technology filter.
    required: false

  entries_vendor:
    description:
      - Application vendor filter.
    required: false

  entries_parameters_value:
    description:
      - Parameter value.
    required: false


'''

EXAMPLES = '''
  - name: DELETE Profile
    fmgr_secprof_appctrl:
      name: "Ansible_Application_Control_Profile"
      comment: "Created by Ansible Module TEST"
      mode: "delete"

  - name: CREATE Profile
    fmgr_secprof_appctrl:
      name: "Ansible_Application_Control_Profile"
      comment: "Created by Ansible Module TEST"
      mode: "set"
      entries: [{
                action: "block",
                log: "enable",
                log-packet: "enable",
                protocols: ["1"],
                quarantine: "attacker",
                quarantine-log: "enable",
                },
                {action: "pass",
                category: ["2","3","4"]},
              ]
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
from ansible.module_utils.network.fortimanager.common import prepare_dict
from ansible.module_utils.network.fortimanager.common import scrub_dict

###############
# START METHODS
###############


def fmgr_application_list_modify(fmgr, paramgram):
    """
    fmgr_application_list -- Modifies Application Control Profiles on FortiManager

    :param fmgr: The fmgr object instance from fmgr_utils.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict

    :return: The response from the FortiManager
    :rtype: dict
    """
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if paramgram["mode"] in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/application/list'.format(adom=paramgram["adom"])
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif paramgram["mode"] == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/application/list/{name}'.format(adom=paramgram["adom"],
                                                                          name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response


#############
# END METHODS
#############


def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        unknown_application_log=dict(required=False, type="str", choices=["disable", "enable"]),
        unknown_application_action=dict(required=False, type="str", choices=["pass", "block"]),
        replacemsg_group=dict(required=False, type="str"),
        p2p_black_list=dict(required=False, type="str", choices=["skype", "edonkey", "bittorrent"]),
        other_application_log=dict(required=False, type="str", choices=["disable", "enable"]),
        other_application_action=dict(required=False, type="str", choices=["pass", "block"]),
        options=dict(required=False, type="str",
                     choices=["allow-dns", "allow-icmp", "allow-http", "allow-ssl", "allow-quic"]),
        name=dict(required=False, type="str"),
        extended_log=dict(required=False, type="str", choices=["disable", "enable"]),
        deep_app_inspection=dict(required=False, type="str", choices=["disable", "enable"]),
        comment=dict(required=False, type="str"),
        app_replacemsg=dict(required=False, type="str", choices=["disable", "enable"]),
        entries=dict(required=False, type="list"),
        entries_action=dict(required=False, type="str", choices=["pass", "block", "reset"]),
        entries_application=dict(required=False, type="str"),
        entries_behavior=dict(required=False, type="str"),
        entries_category=dict(required=False, type="str"),
        entries_log=dict(required=False, type="str", choices=["disable", "enable"]),
        entries_log_packet=dict(required=False, type="str", choices=["disable", "enable"]),
        entries_per_ip_shaper=dict(required=False, type="str"),
        entries_popularity=dict(required=False, type="str", choices=["1", "2", "3", "4", "5"]),
        entries_protocols=dict(required=False, type="str"),
        entries_quarantine=dict(required=False, type="str", choices=["none", "attacker"]),
        entries_quarantine_expiry=dict(required=False, type="str"),
        entries_quarantine_log=dict(required=False, type="str", choices=["disable", "enable"]),
        entries_rate_count=dict(required=False, type="int"),
        entries_rate_duration=dict(required=False, type="int"),
        entries_rate_mode=dict(required=False, type="str", choices=["periodical", "continuous"]),
        entries_rate_track=dict(required=False, type="str",
                                choices=["none", "src-ip", "dest-ip", "dhcp-client-mac", "dns-domain"]),
        entries_risk=dict(required=False, type="str"),
        entries_session_ttl=dict(required=False, type="int"),
        entries_shaper=dict(required=False, type="str"),
        entries_shaper_reverse=dict(required=False, type="str"),
        entries_sub_category=dict(required=False, type="str"),
        entries_technology=dict(required=False, type="str"),
        entries_vendor=dict(required=False, type="str"),

        entries_parameters_value=dict(required=False, type="str"),

    )
    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "unknown-application-log": module.params["unknown_application_log"],
        "unknown-application-action": module.params["unknown_application_action"],
        "replacemsg-group": module.params["replacemsg_group"],
        "p2p-black-list": module.params["p2p_black_list"],
        "other-application-log": module.params["other_application_log"],
        "other-application-action": module.params["other_application_action"],
        "options": module.params["options"],
        "name": module.params["name"],
        "extended-log": module.params["extended_log"],
        "deep-app-inspection": module.params["deep_app_inspection"],
        "comment": module.params["comment"],
        "app-replacemsg": module.params["app_replacemsg"],
        "entries": {
            "action": module.params["entries_action"],
            "application": module.params["entries_application"],
            "behavior": module.params["entries_behavior"],
            "category": module.params["entries_category"],
            "log": module.params["entries_log"],
            "log-packet": module.params["entries_log_packet"],
            "per-ip-shaper": module.params["entries_per_ip_shaper"],
            "popularity": module.params["entries_popularity"],
            "protocols": module.params["entries_protocols"],
            "quarantine": module.params["entries_quarantine"],
            "quarantine-expiry": module.params["entries_quarantine_expiry"],
            "quarantine-log": module.params["entries_quarantine_log"],
            "rate-count": module.params["entries_rate_count"],
            "rate-duration": module.params["entries_rate_duration"],
            "rate-mode": module.params["entries_rate_mode"],
            "rate-track": module.params["entries_rate_track"],
            "risk": module.params["entries_risk"],
            "session-ttl": module.params["entries_session_ttl"],
            "shaper": module.params["entries_shaper"],
            "shaper-reverse": module.params["entries_shaper_reverse"],
            "sub-category": module.params["entries_sub_category"],
            "technology": module.params["entries_technology"],
            "vendor": module.params["entries_vendor"],
            "parameters": {
                "value": module.params["entries_parameters_value"],
            }
        }
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['entries']
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)

    results = DEFAULT_RESULT_OBJ
    try:
        results = fmgr_application_list_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_secprof_av

Metadata

Name: fmgr_secprof_av

Description: Manage security profile groups for FortiManager objects

Author(s):

  • Luke Weighall (github: @lweighall)
  • Andrew Welsh (github: @Ghilli3)
  • Jim Huber (github: @p4r4n0y1ng)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Andrew Welsh

Module Github Link

Parameters
adom
  • Description: The ADOM the configuration should belong to.
  • Required: False
  • default: root
analytics_bl_filetype
  • Description: Only submit files matching this DLP file-pattern to FortiSandbox.
  • Required: False
analytics_db
  • Description: Enable/disable using the FortiSandbox signature database to supplement the AV signature databases.
  • Required: False
  • choices: [‘disable’, ‘enable’]
analytics_max_upload
  • Description: Maximum size of files that can be uploaded to FortiSandbox (1 - 395 MBytes, default = 10).
  • Required: False
analytics_wl_filetype
  • Description: Do not submit files matching this DLP file-pattern to FortiSandbox.
  • Required: False
av_block_log
  • Description: Enable/disable logging for AntiVirus file blocking.
  • Required: False
  • choices: [‘disable’, ‘enable’]
av_virus_log
  • Description: Enable/disable AntiVirus logging.
  • Required: False
  • choices: [‘disable’, ‘enable’]
comment
  • Description: Comment.
  • Required: False
content_disarm
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

content_disarm_cover_page
  • Description: Enable/disable inserting a cover page into the disarmed document.
  • Required: False
  • choices: [‘disable’, ‘enable’]
content_disarm_detect_only
  • Description: Enable/disable only detect disarmable files, do not alter content.
  • Required: False
  • choices: [‘disable’, ‘enable’]
content_disarm_office_embed
  • Description: Enable/disable stripping of embedded objects in Microsoft Office documents.
  • Required: False
  • choices: [‘disable’, ‘enable’]
content_disarm_office_linked
  • Description: Enable/disable stripping of linked objects in Microsoft Office documents.
  • Required: False
  • choices: [‘disable’, ‘enable’]
content_disarm_office_macro
  • Description: Enable/disable stripping of macros in Microsoft Office documents.
  • Required: False
  • choices: [‘disable’, ‘enable’]
content_disarm_original_file_destination
  • Description: Destination to send original file if active content is removed.
  • Required: False
  • choices: [‘fortisandbox’, ‘quarantine’, ‘discard’]
content_disarm_pdf_act_form
  • Description: Enable/disable stripping of actions that submit data to other targets in PDF documents.
  • Required: False
  • choices: [‘disable’, ‘enable’]
content_disarm_pdf_act_gotor
  • Description: Enable/disable stripping of links to other PDFs in PDF documents.
  • Required: False
  • choices: [‘disable’, ‘enable’]
content_disarm_pdf_act_java
  • Description: Enable/disable stripping of actions that execute JavaScript code in PDF documents.
  • Required: False
  • choices: [‘disable’, ‘enable’]
content_disarm_pdf_act_launch
  • Description: Enable/disable stripping of links to external applications in PDF documents.
  • Required: False
  • choices: [‘disable’, ‘enable’]
content_disarm_pdf_act_movie
  • Description: Enable/disable stripping of embedded movies in PDF documents.
  • Required: False
  • choices: [‘disable’, ‘enable’]
content_disarm_pdf_act_sound
  • Description: Enable/disable stripping of embedded sound files in PDF documents.
  • Required: False
  • choices: [‘disable’, ‘enable’]
content_disarm_pdf_embedfile
  • Description: Enable/disable stripping of embedded files in PDF documents.
  • Required: False
  • choices: [‘disable’, ‘enable’]
content_disarm_pdf_javacode
  • Description: Enable/disable stripping of JavaScript code in PDF documents.
  • Required: False
  • choices: [‘disable’, ‘enable’]
extended_log
  • Description: Enable/disable extended logging for antivirus.
  • Required: False
  • choices: [‘disable’, ‘enable’]
ftgd_analytics
  • Description: Settings to control which files are uploaded to FortiSandbox.
  • Required: False
  • choices: [‘disable’, ‘suspicious’, ‘everything’]
ftp
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

ftp_archive_block
  • Description: Select the archive types to block.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘encrypted’, ‘corrupted’, ‘multipart’, ‘nested’, ‘mailbomb’, ‘unhandled’, ‘partiallycorrupted’, ‘fileslimit’, ‘timeout’]

ftp_archive_log
  • Description: Select the archive types to log.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘encrypted’, ‘corrupted’, ‘multipart’, ‘nested’, ‘mailbomb’, ‘unhandled’, ‘partiallycorrupted’, ‘fileslimit’, ‘timeout’]

ftp_emulator
  • Description: Enable/disable the virus emulator.
  • Required: False
  • choices: [‘disable’, ‘enable’]
ftp_options
  • Description: Enable/disable FTP AntiVirus scanning, monitoring, and quarantine.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘scan’, ‘quarantine’, ‘avmonitor’]

ftp_outbreak_prevention
  • Description: Enable FortiGuard Virus Outbreak Prevention service.
  • Required: False
  • choices: [‘disabled’, ‘files’, ‘full-archive’]
http
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

http_archive_block
  • Description: Select the archive types to block.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘encrypted’, ‘corrupted’, ‘multipart’, ‘nested’, ‘mailbomb’, ‘unhandled’, ‘partiallycorrupted’, ‘fileslimit’, ‘timeout’]

http_archive_log
  • Description: Select the archive types to log.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘encrypted’, ‘corrupted’, ‘multipart’, ‘nested’, ‘mailbomb’, ‘unhandled’, ‘partiallycorrupted’, ‘fileslimit’, ‘timeout’]

http_content_disarm
  • Description: Enable Content Disarm and Reconstruction for this protocol.
  • Required: False
  • choices: [‘disable’, ‘enable’]
http_emulator
  • Description: Enable/disable the virus emulator.
  • Required: False
  • choices: [‘disable’, ‘enable’]
http_options
  • Description: Enable/disable HTTP AntiVirus scanning, monitoring, and quarantine.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘scan’, ‘quarantine’, ‘avmonitor’]

http_outbreak_prevention
  • Description: Enable FortiGuard Virus Outbreak Prevention service.
  • Required: False
  • choices: [‘disabled’, ‘files’, ‘full-archive’]
imap
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

imap_archive_block
  • Description: Select the archive types to block.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘encrypted’, ‘corrupted’, ‘multipart’, ‘nested’, ‘mailbomb’, ‘unhandled’, ‘partiallycorrupted’, ‘fileslimit’, ‘timeout’]

imap_archive_log
  • Description: Select the archive types to log.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘encrypted’, ‘corrupted’, ‘multipart’, ‘nested’, ‘mailbomb’, ‘unhandled’, ‘partiallycorrupted’, ‘fileslimit’, ‘timeout’]

imap_content_disarm
  • Description: Enable Content Disarm and Reconstruction for this protocol.
  • Required: False
  • choices: [‘disable’, ‘enable’]
imap_emulator
  • Description: Enable/disable the virus emulator.
  • Required: False
  • choices: [‘disable’, ‘enable’]
imap_executables
  • Description: Treat Windows executable files as viruses for the purpose of blocking or monitoring.
  • Required: False
  • choices: [‘default’, ‘virus’]
imap_options
  • Description: Enable/disable IMAP AntiVirus scanning, monitoring, and quarantine.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘scan’, ‘quarantine’, ‘avmonitor’]

imap_outbreak_prevention
  • Description: Enable FortiGuard Virus Outbreak Prevention service.
  • Required: False
  • choices: [‘disabled’, ‘files’, ‘full-archive’]
inspection_mode
  • Description: Inspection mode.
  • Required: False
  • choices: [‘proxy’, ‘flow-based’]
mapi
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

mapi_archive_block
  • Description: Select the archive types to block.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘encrypted’, ‘corrupted’, ‘multipart’, ‘nested’, ‘mailbomb’, ‘unhandled’, ‘partiallycorrupted’, ‘fileslimit’, ‘timeout’]

mapi_archive_log
  • Description: Select the archive types to log.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘encrypted’, ‘corrupted’, ‘multipart’, ‘nested’, ‘mailbomb’, ‘unhandled’, ‘partiallycorrupted’, ‘fileslimit’, ‘timeout’]

mapi_emulator
  • Description: Enable/disable the virus emulator.
  • Required: False
  • choices: [‘disable’, ‘enable’]
mapi_executables
  • Description: Treat Windows executable files as viruses for the purpose of blocking or monitoring.
  • Required: False
  • choices: [‘default’, ‘virus’]
mapi_options
  • Description: Enable/disable MAPI AntiVirus scanning, monitoring, and quarantine.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘scan’, ‘quarantine’, ‘avmonitor’]

mapi_outbreak_prevention
  • Description: Enable FortiGuard Virus Outbreak Prevention service.
  • Required: False
  • choices: [‘disabled’, ‘files’, ‘full-archive’]
mobile_malware_db
  • Description: Enable/disable using the mobile malware signature database.
  • Required: False
  • choices: [‘disable’, ‘enable’]
mode
  • Description: Sets one of three modes for managing the object.

    Allows use of soft-adds instead of overwriting existing values

  • Required: False

  • default: add

  • choices: [‘add’, ‘set’, ‘delete’, ‘update’]

nac_quar
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

nac_quar_expiry
  • Description: Duration of quarantine.
  • Required: False
nac_quar_infected
  • Description: Enable/Disable quarantining infected hosts to the banned user list.
  • Required: False
  • choices: [‘none’, ‘quar-src-ip’]
nac_quar_log
  • Description: Enable/disable AntiVirus quarantine logging.
  • Required: False
  • choices: [‘disable’, ‘enable’]
name
  • Description: Profile name.
  • Required: False
nntp
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

nntp_archive_block
  • Description: Select the archive types to block.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘encrypted’, ‘corrupted’, ‘multipart’, ‘nested’, ‘mailbomb’, ‘unhandled’, ‘partiallycorrupted’, ‘fileslimit’, ‘timeout’]

nntp_archive_log
  • Description: Select the archive types to log.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘encrypted’, ‘corrupted’, ‘multipart’, ‘nested’, ‘mailbomb’, ‘unhandled’, ‘partiallycorrupted’, ‘fileslimit’, ‘timeout’]

nntp_emulator
  • Description: Enable/disable the virus emulator.
  • Required: False
  • choices: [‘disable’, ‘enable’]
nntp_options
  • Description: Enable/disable NNTP AntiVirus scanning, monitoring, and quarantine.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘scan’, ‘quarantine’, ‘avmonitor’]

nntp_outbreak_prevention
  • Description: Enable FortiGuard Virus Outbreak Prevention service.
  • Required: False
  • choices: [‘disabled’, ‘files’, ‘full-archive’]
pop3
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

pop3_archive_block
  • Description: Select the archive types to block.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘encrypted’, ‘corrupted’, ‘multipart’, ‘nested’, ‘mailbomb’, ‘unhandled’, ‘partiallycorrupted’, ‘fileslimit’, ‘timeout’]

pop3_archive_log
  • Description: Select the archive types to log.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘encrypted’, ‘corrupted’, ‘multipart’, ‘nested’, ‘mailbomb’, ‘unhandled’, ‘partiallycorrupted’, ‘fileslimit’, ‘timeout’]

pop3_content_disarm
  • Description: Enable Content Disarm and Reconstruction for this protocol.
  • Required: False
  • choices: [‘disable’, ‘enable’]
pop3_emulator
  • Description: Enable/disable the virus emulator.
  • Required: False
  • choices: [‘disable’, ‘enable’]
pop3_executables
  • Description: Treat Windows executable files as viruses for the purpose of blocking or monitoring.
  • Required: False
  • choices: [‘default’, ‘virus’]
pop3_options
  • Description: Enable/disable POP3 AntiVirus scanning, monitoring, and quarantine.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘scan’, ‘quarantine’, ‘avmonitor’]

pop3_outbreak_prevention
  • Description: Enable FortiGuard Virus Outbreak Prevention service.
  • Required: False
  • choices: [‘disabled’, ‘files’, ‘full-archive’]
replacemsg_group
  • Description: Replacement message group customized for this profile.
  • Required: False
scan_mode
  • Description: Choose between full scan mode and quick scan mode.
  • Required: False
  • choices: [‘quick’, ‘full’]
smb
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

smb_archive_block
  • Description: Select the archive types to block.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘encrypted’, ‘corrupted’, ‘multipart’, ‘nested’, ‘mailbomb’, ‘unhandled’, ‘partiallycorrupted’, ‘fileslimit’, ‘timeout’]

smb_archive_log
  • Description: Select the archive types to log.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘encrypted’, ‘corrupted’, ‘multipart’, ‘nested’, ‘mailbomb’, ‘unhandled’, ‘partiallycorrupted’, ‘fileslimit’, ‘timeout’]

smb_emulator
  • Description: Enable/disable the virus emulator.
  • Required: False
  • choices: [‘disable’, ‘enable’]
smb_options
  • Description: Enable/disable SMB AntiVirus scanning, monitoring, and quarantine.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘scan’, ‘quarantine’, ‘avmonitor’]

smb_outbreak_prevention
  • Description: Enable FortiGuard Virus Outbreak Prevention service.
  • Required: False
  • choices: [‘disabled’, ‘files’, ‘full-archive’]
smtp
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

smtp_archive_block
  • Description: Select the archive types to block.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘encrypted’, ‘corrupted’, ‘multipart’, ‘nested’, ‘mailbomb’, ‘unhandled’, ‘partiallycorrupted’, ‘fileslimit’, ‘timeout’]

smtp_archive_log
  • Description: Select the archive types to log.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘encrypted’, ‘corrupted’, ‘multipart’, ‘nested’, ‘mailbomb’, ‘unhandled’, ‘partiallycorrupted’, ‘fileslimit’, ‘timeout’]

smtp_content_disarm
  • Description: Enable Content Disarm and Reconstruction for this protocol.
  • Required: False
  • choices: [‘disable’, ‘enable’]
smtp_emulator
  • Description: Enable/disable the virus emulator.
  • Required: False
  • choices: [‘disable’, ‘enable’]
smtp_executables
  • Description: Treat Windows executable files as viruses for the purpose of blocking or monitoring.
  • Required: False
  • choices: [‘default’, ‘virus’]
smtp_options
  • Description: Enable/disable SMTP AntiVirus scanning, monitoring, and quarantine.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘scan’, ‘quarantine’, ‘avmonitor’]

smtp_outbreak_prevention
  • Description: Enable FortiGuard Virus Outbreak Prevention service.
  • Required: False
  • choices: [‘disabled’, ‘files’, ‘full-archive’]
Functions
  • fmgr_antivirus_profile_modify
def fmgr_antivirus_profile_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/antivirus/profile'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    else:
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/antivirus/profile/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response

#############
# END METHODS
#############
  • main
def main():
    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        scan_mode=dict(required=False, type="str", choices=["quick", "full"]),
        replacemsg_group=dict(required=False, type="dict"),
        name=dict(required=False, type="str"),
        mobile_malware_db=dict(required=False, type="str", choices=["disable", "enable"]),
        inspection_mode=dict(required=False, type="str", choices=["proxy", "flow-based"]),
        ftgd_analytics=dict(required=False, type="str", choices=["disable", "suspicious", "everything"]),
        extended_log=dict(required=False, type="str", choices=["disable", "enable"]),
        comment=dict(required=False, type="str"),
        av_virus_log=dict(required=False, type="str", choices=["disable", "enable"]),
        av_block_log=dict(required=False, type="str", choices=["disable", "enable"]),
        analytics_wl_filetype=dict(required=False, type="dict"),
        analytics_max_upload=dict(required=False, type="int"),
        analytics_db=dict(required=False, type="str", choices=["disable", "enable"]),
        analytics_bl_filetype=dict(required=False, type="dict"),
        content_disarm=dict(required=False, type="list"),
        content_disarm_cover_page=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_detect_only=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_office_embed=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_office_hylink=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_office_linked=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_office_macro=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_original_file_destination=dict(required=False, type="str", choices=["fortisandbox",
                                                                                           "quarantine",
                                                                                           "discard"]),
        content_disarm_pdf_act_form=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_pdf_act_gotor=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_pdf_act_java=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_pdf_act_launch=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_pdf_act_movie=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_pdf_act_sound=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_pdf_embedfile=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_pdf_hyperlink=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_pdf_javacode=dict(required=False, type="str", choices=["disable", "enable"]),
        ftp=dict(required=False, type="list"),
        ftp_archive_block=dict(required=False, type="str", choices=["encrypted",
                                                                    "corrupted",
                                                                    "multipart",
                                                                    "nested",
                                                                    "mailbomb",
                                                                    "unhandled",
                                                                    "partiallycorrupted",
                                                                    "fileslimit",
                                                                    "timeout"]),
        ftp_archive_log=dict(required=False, type="str", choices=["encrypted",
                                                                  "corrupted",
                                                                  "multipart",
                                                                  "nested",
                                                                  "mailbomb",
                                                                  "unhandled",
                                                                  "partiallycorrupted",
                                                                  "fileslimit",
                                                                  "timeout"]),
        ftp_emulator=dict(required=False, type="str", choices=["disable", "enable"]),
        ftp_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]),
        ftp_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]),
        http=dict(required=False, type="list"),
        http_archive_block=dict(required=False, type="str", choices=["encrypted",
                                                                     "corrupted",
                                                                     "multipart",
                                                                     "nested",
                                                                     "mailbomb",
                                                                     "unhandled",
                                                                     "partiallycorrupted",
                                                                     "fileslimit",
                                                                     "timeout"]),
        http_archive_log=dict(required=False, type="str", choices=["encrypted",
                                                                   "corrupted",
                                                                   "multipart",
                                                                   "nested",
                                                                   "mailbomb",
                                                                   "unhandled",
                                                                   "partiallycorrupted",
                                                                   "fileslimit",
                                                                   "timeout"]),
        http_content_disarm=dict(required=False, type="str", choices=["disable", "enable"]),
        http_emulator=dict(required=False, type="str", choices=["disable", "enable"]),
        http_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]),
        http_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]),
        imap=dict(required=False, type="list"),
        imap_archive_block=dict(required=False, type="str", choices=["encrypted",
                                                                     "corrupted",
                                                                     "multipart",
                                                                     "nested",
                                                                     "mailbomb",
                                                                     "unhandled",
                                                                     "partiallycorrupted",
                                                                     "fileslimit",
                                                                     "timeout"]),
        imap_archive_log=dict(required=False, type="str", choices=["encrypted",
                                                                   "corrupted",
                                                                   "multipart",
                                                                   "nested",
                                                                   "mailbomb",
                                                                   "unhandled",
                                                                   "partiallycorrupted",
                                                                   "fileslimit",
                                                                   "timeout"]),
        imap_content_disarm=dict(required=False, type="str", choices=["disable", "enable"]),
        imap_emulator=dict(required=False, type="str", choices=["disable", "enable"]),
        imap_executables=dict(required=False, type="str", choices=["default", "virus"]),
        imap_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]),
        imap_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]),
        mapi=dict(required=False, type="list"),
        mapi_archive_block=dict(required=False, type="str", choices=["encrypted",
                                                                     "corrupted",
                                                                     "multipart",
                                                                     "nested",
                                                                     "mailbomb",
                                                                     "unhandled",
                                                                     "partiallycorrupted",
                                                                     "fileslimit",
                                                                     "timeout"]),
        mapi_archive_log=dict(required=False, type="str", choices=["encrypted",
                                                                   "corrupted",
                                                                   "multipart",
                                                                   "nested",
                                                                   "mailbomb",
                                                                   "unhandled",
                                                                   "partiallycorrupted",
                                                                   "fileslimit",
                                                                   "timeout"]),
        mapi_emulator=dict(required=False, type="str", choices=["disable", "enable"]),
        mapi_executables=dict(required=False, type="str", choices=["default", "virus"]),
        mapi_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]),
        mapi_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]),
        nac_quar=dict(required=False, type="list"),
        nac_quar_expiry=dict(required=False, type="str"),
        nac_quar_infected=dict(required=False, type="str", choices=["none", "quar-src-ip"]),
        nac_quar_log=dict(required=False, type="str", choices=["disable", "enable"]),
        nntp=dict(required=False, type="list"),
        nntp_archive_block=dict(required=False, type="str", choices=["encrypted",
                                                                     "corrupted",
                                                                     "multipart",
                                                                     "nested",
                                                                     "mailbomb",
                                                                     "unhandled",
                                                                     "partiallycorrupted",
                                                                     "fileslimit",
                                                                     "timeout"]),
        nntp_archive_log=dict(required=False, type="str", choices=["encrypted",
                                                                   "corrupted",
                                                                   "multipart",
                                                                   "nested",
                                                                   "mailbomb",
                                                                   "unhandled",
                                                                   "partiallycorrupted",
                                                                   "fileslimit",
                                                                   "timeout"]),
        nntp_emulator=dict(required=False, type="str", choices=["disable", "enable"]),
        nntp_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]),
        nntp_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]),
        pop3=dict(required=False, type="list"),
        pop3_archive_block=dict(required=False, type="str", choices=["encrypted",
                                                                     "corrupted",
                                                                     "multipart",
                                                                     "nested",
                                                                     "mailbomb",
                                                                     "unhandled",
                                                                     "partiallycorrupted",
                                                                     "fileslimit",
                                                                     "timeout"]),
        pop3_archive_log=dict(required=False, type="str", choices=["encrypted",
                                                                   "corrupted",
                                                                   "multipart",
                                                                   "nested",
                                                                   "mailbomb",
                                                                   "unhandled",
                                                                   "partiallycorrupted",
                                                                   "fileslimit",
                                                                   "timeout"]),
        pop3_content_disarm=dict(required=False, type="str", choices=["disable", "enable"]),
        pop3_emulator=dict(required=False, type="str", choices=["disable", "enable"]),
        pop3_executables=dict(required=False, type="str", choices=["default", "virus"]),
        pop3_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]),
        pop3_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]),
        smb=dict(required=False, type="list"),
        smb_archive_block=dict(required=False, type="str", choices=["encrypted",
                                                                    "corrupted",
                                                                    "multipart",
                                                                    "nested",
                                                                    "mailbomb",
                                                                    "unhandled",
                                                                    "partiallycorrupted",
                                                                    "fileslimit",
                                                                    "timeout"]),
        smb_archive_log=dict(required=False, type="str", choices=["encrypted",
                                                                  "corrupted",
                                                                  "multipart",
                                                                  "nested",
                                                                  "mailbomb",
                                                                  "unhandled",
                                                                  "partiallycorrupted",
                                                                  "fileslimit",
                                                                  "timeout"]),
        smb_emulator=dict(required=False, type="str", choices=["disable", "enable"]),
        smb_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]),
        smb_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]),
        smtp=dict(required=False, type="list"),
        smtp_archive_block=dict(required=False, type="str", choices=["encrypted",
                                                                     "corrupted",
                                                                     "multipart",
                                                                     "nested",
                                                                     "mailbomb",
                                                                     "unhandled",
                                                                     "partiallycorrupted",
                                                                     "fileslimit",
                                                                     "timeout"]),
        smtp_archive_log=dict(required=False, type="str", choices=["encrypted",
                                                                   "corrupted",
                                                                   "multipart",
                                                                   "nested",
                                                                   "mailbomb",
                                                                   "unhandled",
                                                                   "partiallycorrupted",
                                                                   "fileslimit",
                                                                   "timeout"]),
        smtp_content_disarm=dict(required=False, type="str", choices=["disable", "enable"]),
        smtp_emulator=dict(required=False, type="str", choices=["disable", "enable"]),
        smtp_executables=dict(required=False, type="str", choices=["default", "virus"]),
        smtp_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]),
        smtp_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "scan-mode": module.params["scan_mode"],
        "replacemsg-group": module.params["replacemsg_group"],
        "name": module.params["name"],
        "mobile-malware-db": module.params["mobile_malware_db"],
        "inspection-mode": module.params["inspection_mode"],
        "ftgd-analytics": module.params["ftgd_analytics"],
        "extended-log": module.params["extended_log"],
        "comment": module.params["comment"],
        "av-virus-log": module.params["av_virus_log"],
        "av-block-log": module.params["av_block_log"],
        "analytics-wl-filetype": module.params["analytics_wl_filetype"],
        "analytics-max-upload": module.params["analytics_max_upload"],
        "analytics-db": module.params["analytics_db"],
        "analytics-bl-filetype": module.params["analytics_bl_filetype"],
        "content-disarm": {
            "cover-page": module.params["content_disarm_cover_page"],
            "detect-only": module.params["content_disarm_detect_only"],
            "office-embed": module.params["content_disarm_office_embed"],
            "office-hylink": module.params["content_disarm_office_hylink"],
            "office-linked": module.params["content_disarm_office_linked"],
            "office-macro": module.params["content_disarm_office_macro"],
            "original-file-destination": module.params["content_disarm_original_file_destination"],
            "pdf-act-form": module.params["content_disarm_pdf_act_form"],
            "pdf-act-gotor": module.params["content_disarm_pdf_act_gotor"],
            "pdf-act-java": module.params["content_disarm_pdf_act_java"],
            "pdf-act-launch": module.params["content_disarm_pdf_act_launch"],
            "pdf-act-movie": module.params["content_disarm_pdf_act_movie"],
            "pdf-act-sound": module.params["content_disarm_pdf_act_sound"],
            "pdf-embedfile": module.params["content_disarm_pdf_embedfile"],
            "pdf-hyperlink": module.params["content_disarm_pdf_hyperlink"],
            "pdf-javacode": module.params["content_disarm_pdf_javacode"],
        },
        "ftp": {
            "archive-block": module.params["ftp_archive_block"],
            "archive-log": module.params["ftp_archive_log"],
            "emulator": module.params["ftp_emulator"],
            "options": module.params["ftp_options"],
            "outbreak-prevention": module.params["ftp_outbreak_prevention"],
        },
        "http": {
            "archive-block": module.params["http_archive_block"],
            "archive-log": module.params["http_archive_log"],
            "content-disarm": module.params["http_content_disarm"],
            "emulator": module.params["http_emulator"],
            "options": module.params["http_options"],
            "outbreak-prevention": module.params["http_outbreak_prevention"],
        },
        "imap": {
            "archive-block": module.params["imap_archive_block"],
            "archive-log": module.params["imap_archive_log"],
            "content-disarm": module.params["imap_content_disarm"],
            "emulator": module.params["imap_emulator"],
            "executables": module.params["imap_executables"],
            "options": module.params["imap_options"],
            "outbreak-prevention": module.params["imap_outbreak_prevention"],
        },
        "mapi": {
            "archive-block": module.params["mapi_archive_block"],
            "archive-log": module.params["mapi_archive_log"],
            "emulator": module.params["mapi_emulator"],
            "executables": module.params["mapi_executables"],
            "options": module.params["mapi_options"],
            "outbreak-prevention": module.params["mapi_outbreak_prevention"],
        },
        "nac-quar": {
            "expiry": module.params["nac_quar_expiry"],
            "infected": module.params["nac_quar_infected"],
            "log": module.params["nac_quar_log"],
        },
        "nntp": {
            "archive-block": module.params["nntp_archive_block"],
            "archive-log": module.params["nntp_archive_log"],
            "emulator": module.params["nntp_emulator"],
            "options": module.params["nntp_options"],
            "outbreak-prevention": module.params["nntp_outbreak_prevention"],
        },
        "pop3": {
            "archive-block": module.params["pop3_archive_block"],
            "archive-log": module.params["pop3_archive_log"],
            "content-disarm": module.params["pop3_content_disarm"],
            "emulator": module.params["pop3_emulator"],
            "executables": module.params["pop3_executables"],
            "options": module.params["pop3_options"],
            "outbreak-prevention": module.params["pop3_outbreak_prevention"],
        },
        "smb": {
            "archive-block": module.params["smb_archive_block"],
            "archive-log": module.params["smb_archive_log"],
            "emulator": module.params["smb_emulator"],
            "options": module.params["smb_options"],
            "outbreak-prevention": module.params["smb_outbreak_prevention"],
        },
        "smtp": {
            "archive-block": module.params["smtp_archive_block"],
            "archive-log": module.params["smtp_archive_log"],
            "content-disarm": module.params["smtp_content_disarm"],
            "emulator": module.params["smtp_emulator"],
            "executables": module.params["smtp_executables"],
            "options": module.params["smtp_options"],
            "outbreak-prevention": module.params["smtp_outbreak_prevention"],
        }
    }

    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ["content-disarm", "ftp", "http", "imap", "mapi", "nac-quar", "nntp", "pop3", "smb", "smtp"]
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)
    module.paramgram = paramgram

    results = DEFAULT_RESULT_OBJ

    try:
        results = fmgr_antivirus_profile_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {'metadata_version': '1.1',
                    'status': ['preview'],
                    'supported_by': 'community'}

DOCUMENTATION = '''
---
module: fmgr_secprof_av
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author:
    - Luke Weighall (@lweighall)
    - Andrew Welsh (@Ghilli3)
    - Jim Huber (@p4r4n0y1ng)
short_description: Manage security profile
description:
  -  Manage security profile groups for FortiManager objects

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: false
    default: root

  mode:
    description:
      - Sets one of three modes for managing the object.
      - Allows use of soft-adds instead of overwriting existing values
    choices: ['add', 'set', 'delete', 'update']
    required: false
    default: add

  scan_mode:
    description:
      - Choose between full scan mode and quick scan mode.
    required: false
    choices:
      - quick
      - full

  replacemsg_group:
    description:
      - Replacement message group customized for this profile.
    required: false

  name:
    description:
      - Profile name.
    required: false

  mobile_malware_db:
    description:
      - Enable/disable using the mobile malware signature database.
    required: false
    choices:
      - disable
      - enable

  inspection_mode:
    description:
      - Inspection mode.
    required: false
    choices:
      - proxy
      - flow-based

  ftgd_analytics:
    description:
      - Settings to control which files are uploaded to FortiSandbox.
    required: false
    choices:
      - disable
      - suspicious
      - everything

  extended_log:
    description:
      - Enable/disable extended logging for antivirus.
    required: false
    choices:
      - disable
      - enable

  comment:
    description:
      - Comment.
    required: false

  av_virus_log:
    description:
      - Enable/disable AntiVirus logging.
    required: false
    choices:
      - disable
      - enable

  av_block_log:
    description:
      - Enable/disable logging for AntiVirus file blocking.
    required: false
    choices:
      - disable
      - enable

  analytics_wl_filetype:
    description:
      - Do not submit files matching this DLP file-pattern to FortiSandbox.
    required: false

  analytics_max_upload:
    description:
      - Maximum size of files that can be uploaded to FortiSandbox (1 - 395 MBytes, default = 10).
    required: false

  analytics_db:
    description:
      - Enable/disable using the FortiSandbox signature database to supplement the AV signature databases.
    required: false
    choices:
      - disable
      - enable

  analytics_bl_filetype:
    description:
      - Only submit files matching this DLP file-pattern to FortiSandbox.
    required: false

  content_disarm:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  content_disarm_cover_page:
    description:
      - Enable/disable inserting a cover page into the disarmed document.
    required: false
    choices:
      - disable
      - enable

  content_disarm_detect_only:
    description:
      - Enable/disable only detect disarmable files, do not alter content.
    required: false
    choices:
      - disable
      - enable

  content_disarm_office_embed:
    description:
      - Enable/disable stripping of embedded objects in Microsoft Office documents.
    required: false
    choices:
      - disable
      - enable

  content_disarm_office_hylink:
    description:
      - Enable/disable stripping of hyperlinks in Microsoft Office documents.
    required: false
    choices:
      - disable
      - enable

  content_disarm_office_linked:
    description:
      - Enable/disable stripping of linked objects in Microsoft Office documents.
    required: false
    choices:
      - disable
      - enable

  content_disarm_office_macro:
    description:
      - Enable/disable stripping of macros in Microsoft Office documents.
    required: false
    choices:
      - disable
      - enable

  content_disarm_original_file_destination:
    description:
      - Destination to send original file if active content is removed.
    required: false
    choices:
      - fortisandbox
      - quarantine
      - discard

  content_disarm_pdf_act_form:
    description:
      - Enable/disable stripping of actions that submit data to other targets in PDF documents.
    required: false
    choices:
      - disable
      - enable

  content_disarm_pdf_act_gotor:
    description:
      - Enable/disable stripping of links to other PDFs in PDF documents.
    required: false
    choices:
      - disable
      - enable

  content_disarm_pdf_act_java:
    description:
      - Enable/disable stripping of actions that execute JavaScript code in PDF documents.
    required: false
    choices:
      - disable
      - enable

  content_disarm_pdf_act_launch:
    description:
      - Enable/disable stripping of links to external applications in PDF documents.
    required: false
    choices:
      - disable
      - enable

  content_disarm_pdf_act_movie:
    description:
      - Enable/disable stripping of embedded movies in PDF documents.
    required: false
    choices:
      - disable
      - enable

  content_disarm_pdf_act_sound:
    description:
      - Enable/disable stripping of embedded sound files in PDF documents.
    required: false
    choices:
      - disable
      - enable

  content_disarm_pdf_embedfile:
    description:
      - Enable/disable stripping of embedded files in PDF documents.
    required: false
    choices:
      - disable
      - enable

  content_disarm_pdf_hyperlink:
    description:
      - Enable/disable stripping of hyperlinks from PDF documents.
    required: false
    choices:
      - disable
      - enable

  content_disarm_pdf_javacode:
    description:
      - Enable/disable stripping of JavaScript code in PDF documents.
    required: false
    choices:
      - disable
      - enable

  ftp:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  ftp_archive_block:
    description:
      - Select the archive types to block.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - encrypted
      - corrupted
      - multipart
      - nested
      - mailbomb
      - unhandled
      - partiallycorrupted
      - fileslimit
      - timeout

  ftp_archive_log:
    description:
      - Select the archive types to log.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - encrypted
      - corrupted
      - multipart
      - nested
      - mailbomb
      - unhandled
      - partiallycorrupted
      - fileslimit
      - timeout

  ftp_emulator:
    description:
      - Enable/disable the virus emulator.
    required: false
    choices:
      - disable
      - enable

  ftp_options:
    description:
      - Enable/disable FTP AntiVirus scanning, monitoring, and quarantine.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - scan
      - quarantine
      - avmonitor

  ftp_outbreak_prevention:
    description:
      - Enable FortiGuard Virus Outbreak Prevention service.
    required: false
    choices:
      - disabled
      - files
      - full-archive

  http:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  http_archive_block:
    description:
      - Select the archive types to block.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - encrypted
      - corrupted
      - multipart
      - nested
      - mailbomb
      - unhandled
      - partiallycorrupted
      - fileslimit
      - timeout

  http_archive_log:
    description:
      - Select the archive types to log.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - encrypted
      - corrupted
      - multipart
      - nested
      - mailbomb
      - unhandled
      - partiallycorrupted
      - fileslimit
      - timeout

  http_content_disarm:
    description:
      - Enable Content Disarm and Reconstruction for this protocol.
    required: false
    choices:
      - disable
      - enable

  http_emulator:
    description:
      - Enable/disable the virus emulator.
    required: false
    choices:
      - disable
      - enable

  http_options:
    description:
      - Enable/disable HTTP AntiVirus scanning, monitoring, and quarantine.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - scan
      - quarantine
      - avmonitor

  http_outbreak_prevention:
    description:
      - Enable FortiGuard Virus Outbreak Prevention service.
    required: false
    choices:
      - disabled
      - files
      - full-archive

  imap:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  imap_archive_block:
    description:
      - Select the archive types to block.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - encrypted
      - corrupted
      - multipart
      - nested
      - mailbomb
      - unhandled
      - partiallycorrupted
      - fileslimit
      - timeout

  imap_archive_log:
    description:
      - Select the archive types to log.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - encrypted
      - corrupted
      - multipart
      - nested
      - mailbomb
      - unhandled
      - partiallycorrupted
      - fileslimit
      - timeout

  imap_content_disarm:
    description:
      - Enable Content Disarm and Reconstruction for this protocol.
    required: false
    choices:
      - disable
      - enable

  imap_emulator:
    description:
      - Enable/disable the virus emulator.
    required: false
    choices:
      - disable
      - enable

  imap_executables:
    description:
      - Treat Windows executable files as viruses for the purpose of blocking or monitoring.
    required: false
    choices:
      - default
      - virus

  imap_options:
    description:
      - Enable/disable IMAP AntiVirus scanning, monitoring, and quarantine.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - scan
      - quarantine
      - avmonitor

  imap_outbreak_prevention:
    description:
      - Enable FortiGuard Virus Outbreak Prevention service.
    required: false
    choices:
      - disabled
      - files
      - full-archive

  mapi:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  mapi_archive_block:
    description:
      - Select the archive types to block.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - encrypted
      - corrupted
      - multipart
      - nested
      - mailbomb
      - unhandled
      - partiallycorrupted
      - fileslimit
      - timeout

  mapi_archive_log:
    description:
      - Select the archive types to log.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - encrypted
      - corrupted
      - multipart
      - nested
      - mailbomb
      - unhandled
      - partiallycorrupted
      - fileslimit
      - timeout

  mapi_emulator:
    description:
      - Enable/disable the virus emulator.
    required: false
    choices:
      - disable
      - enable

  mapi_executables:
    description:
      - Treat Windows executable files as viruses for the purpose of blocking or monitoring.
    required: false
    choices:
      - default
      - virus

  mapi_options:
    description:
      - Enable/disable MAPI AntiVirus scanning, monitoring, and quarantine.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - scan
      - quarantine
      - avmonitor

  mapi_outbreak_prevention:
    description:
      - Enable FortiGuard Virus Outbreak Prevention service.
    required: false
    choices:
      - disabled
      - files
      - full-archive

  nac_quar:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  nac_quar_expiry:
    description:
      - Duration of quarantine.
    required: false

  nac_quar_infected:
    description:
      - Enable/Disable quarantining infected hosts to the banned user list.
    required: false
    choices:
      - none
      - quar-src-ip

  nac_quar_log:
    description:
      - Enable/disable AntiVirus quarantine logging.
    required: false
    choices:
      - disable
      - enable

  nntp:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  nntp_archive_block:
    description:
      - Select the archive types to block.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - encrypted
      - corrupted
      - multipart
      - nested
      - mailbomb
      - unhandled
      - partiallycorrupted
      - fileslimit
      - timeout

  nntp_archive_log:
    description:
      - Select the archive types to log.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - encrypted
      - corrupted
      - multipart
      - nested
      - mailbomb
      - unhandled
      - partiallycorrupted
      - fileslimit
      - timeout

  nntp_emulator:
    description:
      - Enable/disable the virus emulator.
    required: false
    choices:
      - disable
      - enable

  nntp_options:
    description:
      - Enable/disable NNTP AntiVirus scanning, monitoring, and quarantine.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - scan
      - quarantine
      - avmonitor

  nntp_outbreak_prevention:
    description:
      - Enable FortiGuard Virus Outbreak Prevention service.
    required: false
    choices:
      - disabled
      - files
      - full-archive

  pop3:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  pop3_archive_block:
    description:
      - Select the archive types to block.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - encrypted
      - corrupted
      - multipart
      - nested
      - mailbomb
      - unhandled
      - partiallycorrupted
      - fileslimit
      - timeout

  pop3_archive_log:
    description:
      - Select the archive types to log.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - encrypted
      - corrupted
      - multipart
      - nested
      - mailbomb
      - unhandled
      - partiallycorrupted
      - fileslimit
      - timeout

  pop3_content_disarm:
    description:
      - Enable Content Disarm and Reconstruction for this protocol.
    required: false
    choices:
      - disable
      - enable

  pop3_emulator:
    description:
      - Enable/disable the virus emulator.
    required: false
    choices:
      - disable
      - enable

  pop3_executables:
    description:
      - Treat Windows executable files as viruses for the purpose of blocking or monitoring.
    required: false
    choices:
      - default
      - virus

  pop3_options:
    description:
      - Enable/disable POP3 AntiVirus scanning, monitoring, and quarantine.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - scan
      - quarantine
      - avmonitor

  pop3_outbreak_prevention:
    description:
      - Enable FortiGuard Virus Outbreak Prevention service.
    required: false
    choices:
      - disabled
      - files
      - full-archive

  smb:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  smb_archive_block:
    description:
      - Select the archive types to block.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - encrypted
      - corrupted
      - multipart
      - nested
      - mailbomb
      - unhandled
      - partiallycorrupted
      - fileslimit
      - timeout

  smb_archive_log:
    description:
      - Select the archive types to log.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - encrypted
      - corrupted
      - multipart
      - nested
      - mailbomb
      - unhandled
      - partiallycorrupted
      - fileslimit
      - timeout

  smb_emulator:
    description:
      - Enable/disable the virus emulator.
    required: false
    choices:
      - disable
      - enable

  smb_options:
    description:
      - Enable/disable SMB AntiVirus scanning, monitoring, and quarantine.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - scan
      - quarantine
      - avmonitor

  smb_outbreak_prevention:
    description:
      - Enable FortiGuard Virus Outbreak Prevention service.
    required: false
    choices:
      - disabled
      - files
      - full-archive

  smtp:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  smtp_archive_block:
    description:
      - Select the archive types to block.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - encrypted
      - corrupted
      - multipart
      - nested
      - mailbomb
      - unhandled
      - partiallycorrupted
      - fileslimit
      - timeout

  smtp_archive_log:
    description:
      - Select the archive types to log.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - encrypted
      - corrupted
      - multipart
      - nested
      - mailbomb
      - unhandled
      - partiallycorrupted
      - fileslimit
      - timeout

  smtp_content_disarm:
    description:
      - Enable Content Disarm and Reconstruction for this protocol.
    required: false
    choices:
      - disable
      - enable

  smtp_emulator:
    description:
      - Enable/disable the virus emulator.
    required: false
    choices:
      - disable
      - enable

  smtp_executables:
    description:
      - Treat Windows executable files as viruses for the purpose of blocking or monitoring.
    required: false
    choices:
      - default
      - virus

  smtp_options:
    description:
      - Enable/disable SMTP AntiVirus scanning, monitoring, and quarantine.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - scan
      - quarantine
      - avmonitor

  smtp_outbreak_prevention:
    description:
      - Enable FortiGuard Virus Outbreak Prevention service.
    required: false
    choices:
      - disabled
      - files
      - full-archive
'''

EXAMPLES = '''
  - name: DELETE Profile
    fmgr_secprof_av:
      name: "Ansible_AV_Profile"
      mode: "delete"

  - name: CREATE Profile
    fmgr_secprof_av:
      name: "Ansible_AV_Profile"
      comment: "Created by Ansible Module TEST"
      mode: "set"
      inspection_mode: "proxy"
      ftgd_analytics: "everything"
      av_block_log: "enable"
      av_virus_log: "enable"
      scan_mode: "full"
      mobile_malware_db: "enable"
      ftp_archive_block: "encrypted"
      ftp_outbreak_prevention: "files"
      ftp_archive_log: "timeout"
      ftp_emulator: "disable"
      ftp_options: "scan"
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
from ansible.module_utils.network.fortimanager.common import prepare_dict
from ansible.module_utils.network.fortimanager.common import scrub_dict

###############
# START METHODS
###############


def fmgr_antivirus_profile_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/antivirus/profile'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    else:
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/antivirus/profile/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])
    return response

#############
# END METHODS
#############


def main():
    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        scan_mode=dict(required=False, type="str", choices=["quick", "full"]),
        replacemsg_group=dict(required=False, type="dict"),
        name=dict(required=False, type="str"),
        mobile_malware_db=dict(required=False, type="str", choices=["disable", "enable"]),
        inspection_mode=dict(required=False, type="str", choices=["proxy", "flow-based"]),
        ftgd_analytics=dict(required=False, type="str", choices=["disable", "suspicious", "everything"]),
        extended_log=dict(required=False, type="str", choices=["disable", "enable"]),
        comment=dict(required=False, type="str"),
        av_virus_log=dict(required=False, type="str", choices=["disable", "enable"]),
        av_block_log=dict(required=False, type="str", choices=["disable", "enable"]),
        analytics_wl_filetype=dict(required=False, type="dict"),
        analytics_max_upload=dict(required=False, type="int"),
        analytics_db=dict(required=False, type="str", choices=["disable", "enable"]),
        analytics_bl_filetype=dict(required=False, type="dict"),
        content_disarm=dict(required=False, type="list"),
        content_disarm_cover_page=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_detect_only=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_office_embed=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_office_hylink=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_office_linked=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_office_macro=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_original_file_destination=dict(required=False, type="str", choices=["fortisandbox",
                                                                                           "quarantine",
                                                                                           "discard"]),
        content_disarm_pdf_act_form=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_pdf_act_gotor=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_pdf_act_java=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_pdf_act_launch=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_pdf_act_movie=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_pdf_act_sound=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_pdf_embedfile=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_pdf_hyperlink=dict(required=False, type="str", choices=["disable", "enable"]),
        content_disarm_pdf_javacode=dict(required=False, type="str", choices=["disable", "enable"]),
        ftp=dict(required=False, type="list"),
        ftp_archive_block=dict(required=False, type="str", choices=["encrypted",
                                                                    "corrupted",
                                                                    "multipart",
                                                                    "nested",
                                                                    "mailbomb",
                                                                    "unhandled",
                                                                    "partiallycorrupted",
                                                                    "fileslimit",
                                                                    "timeout"]),
        ftp_archive_log=dict(required=False, type="str", choices=["encrypted",
                                                                  "corrupted",
                                                                  "multipart",
                                                                  "nested",
                                                                  "mailbomb",
                                                                  "unhandled",
                                                                  "partiallycorrupted",
                                                                  "fileslimit",
                                                                  "timeout"]),
        ftp_emulator=dict(required=False, type="str", choices=["disable", "enable"]),
        ftp_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]),
        ftp_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]),
        http=dict(required=False, type="list"),
        http_archive_block=dict(required=False, type="str", choices=["encrypted",
                                                                     "corrupted",
                                                                     "multipart",
                                                                     "nested",
                                                                     "mailbomb",
                                                                     "unhandled",
                                                                     "partiallycorrupted",
                                                                     "fileslimit",
                                                                     "timeout"]),
        http_archive_log=dict(required=False, type="str", choices=["encrypted",
                                                                   "corrupted",
                                                                   "multipart",
                                                                   "nested",
                                                                   "mailbomb",
                                                                   "unhandled",
                                                                   "partiallycorrupted",
                                                                   "fileslimit",
                                                                   "timeout"]),
        http_content_disarm=dict(required=False, type="str", choices=["disable", "enable"]),
        http_emulator=dict(required=False, type="str", choices=["disable", "enable"]),
        http_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]),
        http_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]),
        imap=dict(required=False, type="list"),
        imap_archive_block=dict(required=False, type="str", choices=["encrypted",
                                                                     "corrupted",
                                                                     "multipart",
                                                                     "nested",
                                                                     "mailbomb",
                                                                     "unhandled",
                                                                     "partiallycorrupted",
                                                                     "fileslimit",
                                                                     "timeout"]),
        imap_archive_log=dict(required=False, type="str", choices=["encrypted",
                                                                   "corrupted",
                                                                   "multipart",
                                                                   "nested",
                                                                   "mailbomb",
                                                                   "unhandled",
                                                                   "partiallycorrupted",
                                                                   "fileslimit",
                                                                   "timeout"]),
        imap_content_disarm=dict(required=False, type="str", choices=["disable", "enable"]),
        imap_emulator=dict(required=False, type="str", choices=["disable", "enable"]),
        imap_executables=dict(required=False, type="str", choices=["default", "virus"]),
        imap_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]),
        imap_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]),
        mapi=dict(required=False, type="list"),
        mapi_archive_block=dict(required=False, type="str", choices=["encrypted",
                                                                     "corrupted",
                                                                     "multipart",
                                                                     "nested",
                                                                     "mailbomb",
                                                                     "unhandled",
                                                                     "partiallycorrupted",
                                                                     "fileslimit",
                                                                     "timeout"]),
        mapi_archive_log=dict(required=False, type="str", choices=["encrypted",
                                                                   "corrupted",
                                                                   "multipart",
                                                                   "nested",
                                                                   "mailbomb",
                                                                   "unhandled",
                                                                   "partiallycorrupted",
                                                                   "fileslimit",
                                                                   "timeout"]),
        mapi_emulator=dict(required=False, type="str", choices=["disable", "enable"]),
        mapi_executables=dict(required=False, type="str", choices=["default", "virus"]),
        mapi_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]),
        mapi_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]),
        nac_quar=dict(required=False, type="list"),
        nac_quar_expiry=dict(required=False, type="str"),
        nac_quar_infected=dict(required=False, type="str", choices=["none", "quar-src-ip"]),
        nac_quar_log=dict(required=False, type="str", choices=["disable", "enable"]),
        nntp=dict(required=False, type="list"),
        nntp_archive_block=dict(required=False, type="str", choices=["encrypted",
                                                                     "corrupted",
                                                                     "multipart",
                                                                     "nested",
                                                                     "mailbomb",
                                                                     "unhandled",
                                                                     "partiallycorrupted",
                                                                     "fileslimit",
                                                                     "timeout"]),
        nntp_archive_log=dict(required=False, type="str", choices=["encrypted",
                                                                   "corrupted",
                                                                   "multipart",
                                                                   "nested",
                                                                   "mailbomb",
                                                                   "unhandled",
                                                                   "partiallycorrupted",
                                                                   "fileslimit",
                                                                   "timeout"]),
        nntp_emulator=dict(required=False, type="str", choices=["disable", "enable"]),
        nntp_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]),
        nntp_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]),
        pop3=dict(required=False, type="list"),
        pop3_archive_block=dict(required=False, type="str", choices=["encrypted",
                                                                     "corrupted",
                                                                     "multipart",
                                                                     "nested",
                                                                     "mailbomb",
                                                                     "unhandled",
                                                                     "partiallycorrupted",
                                                                     "fileslimit",
                                                                     "timeout"]),
        pop3_archive_log=dict(required=False, type="str", choices=["encrypted",
                                                                   "corrupted",
                                                                   "multipart",
                                                                   "nested",
                                                                   "mailbomb",
                                                                   "unhandled",
                                                                   "partiallycorrupted",
                                                                   "fileslimit",
                                                                   "timeout"]),
        pop3_content_disarm=dict(required=False, type="str", choices=["disable", "enable"]),
        pop3_emulator=dict(required=False, type="str", choices=["disable", "enable"]),
        pop3_executables=dict(required=False, type="str", choices=["default", "virus"]),
        pop3_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]),
        pop3_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]),
        smb=dict(required=False, type="list"),
        smb_archive_block=dict(required=False, type="str", choices=["encrypted",
                                                                    "corrupted",
                                                                    "multipart",
                                                                    "nested",
                                                                    "mailbomb",
                                                                    "unhandled",
                                                                    "partiallycorrupted",
                                                                    "fileslimit",
                                                                    "timeout"]),
        smb_archive_log=dict(required=False, type="str", choices=["encrypted",
                                                                  "corrupted",
                                                                  "multipart",
                                                                  "nested",
                                                                  "mailbomb",
                                                                  "unhandled",
                                                                  "partiallycorrupted",
                                                                  "fileslimit",
                                                                  "timeout"]),
        smb_emulator=dict(required=False, type="str", choices=["disable", "enable"]),
        smb_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]),
        smb_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]),
        smtp=dict(required=False, type="list"),
        smtp_archive_block=dict(required=False, type="str", choices=["encrypted",
                                                                     "corrupted",
                                                                     "multipart",
                                                                     "nested",
                                                                     "mailbomb",
                                                                     "unhandled",
                                                                     "partiallycorrupted",
                                                                     "fileslimit",
                                                                     "timeout"]),
        smtp_archive_log=dict(required=False, type="str", choices=["encrypted",
                                                                   "corrupted",
                                                                   "multipart",
                                                                   "nested",
                                                                   "mailbomb",
                                                                   "unhandled",
                                                                   "partiallycorrupted",
                                                                   "fileslimit",
                                                                   "timeout"]),
        smtp_content_disarm=dict(required=False, type="str", choices=["disable", "enable"]),
        smtp_emulator=dict(required=False, type="str", choices=["disable", "enable"]),
        smtp_executables=dict(required=False, type="str", choices=["default", "virus"]),
        smtp_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]),
        smtp_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "scan-mode": module.params["scan_mode"],
        "replacemsg-group": module.params["replacemsg_group"],
        "name": module.params["name"],
        "mobile-malware-db": module.params["mobile_malware_db"],
        "inspection-mode": module.params["inspection_mode"],
        "ftgd-analytics": module.params["ftgd_analytics"],
        "extended-log": module.params["extended_log"],
        "comment": module.params["comment"],
        "av-virus-log": module.params["av_virus_log"],
        "av-block-log": module.params["av_block_log"],
        "analytics-wl-filetype": module.params["analytics_wl_filetype"],
        "analytics-max-upload": module.params["analytics_max_upload"],
        "analytics-db": module.params["analytics_db"],
        "analytics-bl-filetype": module.params["analytics_bl_filetype"],
        "content-disarm": {
            "cover-page": module.params["content_disarm_cover_page"],
            "detect-only": module.params["content_disarm_detect_only"],
            "office-embed": module.params["content_disarm_office_embed"],
            "office-hylink": module.params["content_disarm_office_hylink"],
            "office-linked": module.params["content_disarm_office_linked"],
            "office-macro": module.params["content_disarm_office_macro"],
            "original-file-destination": module.params["content_disarm_original_file_destination"],
            "pdf-act-form": module.params["content_disarm_pdf_act_form"],
            "pdf-act-gotor": module.params["content_disarm_pdf_act_gotor"],
            "pdf-act-java": module.params["content_disarm_pdf_act_java"],
            "pdf-act-launch": module.params["content_disarm_pdf_act_launch"],
            "pdf-act-movie": module.params["content_disarm_pdf_act_movie"],
            "pdf-act-sound": module.params["content_disarm_pdf_act_sound"],
            "pdf-embedfile": module.params["content_disarm_pdf_embedfile"],
            "pdf-hyperlink": module.params["content_disarm_pdf_hyperlink"],
            "pdf-javacode": module.params["content_disarm_pdf_javacode"],
        },
        "ftp": {
            "archive-block": module.params["ftp_archive_block"],
            "archive-log": module.params["ftp_archive_log"],
            "emulator": module.params["ftp_emulator"],
            "options": module.params["ftp_options"],
            "outbreak-prevention": module.params["ftp_outbreak_prevention"],
        },
        "http": {
            "archive-block": module.params["http_archive_block"],
            "archive-log": module.params["http_archive_log"],
            "content-disarm": module.params["http_content_disarm"],
            "emulator": module.params["http_emulator"],
            "options": module.params["http_options"],
            "outbreak-prevention": module.params["http_outbreak_prevention"],
        },
        "imap": {
            "archive-block": module.params["imap_archive_block"],
            "archive-log": module.params["imap_archive_log"],
            "content-disarm": module.params["imap_content_disarm"],
            "emulator": module.params["imap_emulator"],
            "executables": module.params["imap_executables"],
            "options": module.params["imap_options"],
            "outbreak-prevention": module.params["imap_outbreak_prevention"],
        },
        "mapi": {
            "archive-block": module.params["mapi_archive_block"],
            "archive-log": module.params["mapi_archive_log"],
            "emulator": module.params["mapi_emulator"],
            "executables": module.params["mapi_executables"],
            "options": module.params["mapi_options"],
            "outbreak-prevention": module.params["mapi_outbreak_prevention"],
        },
        "nac-quar": {
            "expiry": module.params["nac_quar_expiry"],
            "infected": module.params["nac_quar_infected"],
            "log": module.params["nac_quar_log"],
        },
        "nntp": {
            "archive-block": module.params["nntp_archive_block"],
            "archive-log": module.params["nntp_archive_log"],
            "emulator": module.params["nntp_emulator"],
            "options": module.params["nntp_options"],
            "outbreak-prevention": module.params["nntp_outbreak_prevention"],
        },
        "pop3": {
            "archive-block": module.params["pop3_archive_block"],
            "archive-log": module.params["pop3_archive_log"],
            "content-disarm": module.params["pop3_content_disarm"],
            "emulator": module.params["pop3_emulator"],
            "executables": module.params["pop3_executables"],
            "options": module.params["pop3_options"],
            "outbreak-prevention": module.params["pop3_outbreak_prevention"],
        },
        "smb": {
            "archive-block": module.params["smb_archive_block"],
            "archive-log": module.params["smb_archive_log"],
            "emulator": module.params["smb_emulator"],
            "options": module.params["smb_options"],
            "outbreak-prevention": module.params["smb_outbreak_prevention"],
        },
        "smtp": {
            "archive-block": module.params["smtp_archive_block"],
            "archive-log": module.params["smtp_archive_log"],
            "content-disarm": module.params["smtp_content_disarm"],
            "emulator": module.params["smtp_emulator"],
            "executables": module.params["smtp_executables"],
            "options": module.params["smtp_options"],
            "outbreak-prevention": module.params["smtp_outbreak_prevention"],
        }
    }

    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ["content-disarm", "ftp", "http", "imap", "mapi", "nac-quar", "nntp", "pop3", "smb", "smtp"]
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)
    module.paramgram = paramgram

    results = DEFAULT_RESULT_OBJ

    try:
        results = fmgr_antivirus_profile_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_secprof_dns

Metadata

Name: fmgr_secprof_dns

Description: Manage DNS security profiles in FortiManager

Author(s):

  • Luke Weighall (github: @lweighall)
  • Andrew Welsh (github: @Ghilli3)
  • Jim Huber (github: @p4r4n0y1ng)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Andrew Welsh

Module Github Link

Parameters
adom
  • Description: The ADOM the configuration should belong to.
  • Required: False
  • default: root
block_action
  • Description: Action to take for blocked domains.

    choice | block | Return NXDOMAIN for blocked domains.

    choice | redirect | Redirect blocked domains to SDNS portal.

  • Required: False

  • choices: [‘block’, ‘redirect’]

block_botnet
  • Description: Enable/disable blocking botnet C&C; DNS lookups.

    choice | disable | Disable blocking botnet C&C; DNS lookups.

    choice | enable | Enable blocking botnet C&C; DNS lookups.

  • Required: False

  • choices: [‘disable’, ‘enable’]

comment
  • Description: Comment for the security profile to show in the FortiManager GUI.
  • Required: False
domain_filter_domain_filter_table
  • Description: DNS domain filter table ID.
  • Required: False
external_ip_blocklist
  • Description: One or more external IP block lists.
  • Required: False
ftgd_dns_filters_action
  • Description: Action to take for DNS requests matching the category.

    choice | monitor | Allow DNS requests matching the category and log the result.

    choice | block | Block DNS requests matching the category.

  • Required: False

  • choices: [‘monitor’, ‘block’]

ftgd_dns_filters_category
  • Description: Category number.
  • Required: False
ftgd_dns_filters_log
  • Description: Enable/disable DNS filter logging for this DNS profile.

    choice | disable | Disable DNS filter logging.

    choice | enable | Enable DNS filter logging.

  • Required: False

  • choices: [‘disable’, ‘enable’]

ftgd_dns_options
  • Description: FortiGuard DNS filter options.

    FLAG Based Options. Specify multiple in list form.

    flag | error-allow | Allow all domains when FortiGuard DNS servers fail.

    flag | ftgd-disable | Disable FortiGuard DNS domain rating.

  • Required: False

  • choices: [‘error-allow’, ‘ftgd-disable’]

log_all_domain
  • Description: Enable/disable logging of all domains visited (detailed DNS logging).

    choice | disable | Disable logging of all domains visited.

    choice | enable | Enable logging of all domains visited.

  • Required: False

  • choices: [‘disable’, ‘enable’]

mode
  • Description: Sets one of three modes for managing the object.

    Allows use of soft-adds instead of overwriting existing values.

  • Required: False

  • default: add

  • choices: [‘add’, ‘set’, ‘delete’, ‘update’]

name
  • Description: Profile name.
  • Required: False
redirect_portal
  • Description: IP address of the SDNS redirect portal.
  • Required: False
sdns_domain_log
  • Description: Enable/disable domain filtering and botnet domain logging.

    choice | disable | Disable domain filtering and botnet domain logging.

    choice | enable | Enable domain filtering and botnet domain logging.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sdns_ftgd_err_log
  • Description: Enable/disable FortiGuard SDNS rating error logging.

    choice | disable | Disable FortiGuard SDNS rating error logging.

    choice | enable | Enable FortiGuard SDNS rating error logging.

  • Required: False

  • choices: [‘disable’, ‘enable’]

youtube_restrict
  • Description: Set safe search for YouTube restriction level.

    choice | strict | Enable strict safe seach for YouTube.

    choice | moderate | Enable moderate safe search for YouTube.

  • Required: False

  • choices: [‘strict’, ‘moderate’]

Functions
  • fmgr_dnsfilter_profile_modify
def fmgr_dnsfilter_profile_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]
    url = ""
    datagram = {}

    response = DEFAULT_RESULT_OBJ

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/dnsfilter/profile'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/dnsfilter/profile/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])

    return response


#############
# END METHODS
#############
  • main
def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        youtube_restrict=dict(required=False, type="str", choices=["strict", "moderate"]),
        sdns_ftgd_err_log=dict(required=False, type="str", choices=["disable", "enable"]),
        sdns_domain_log=dict(required=False, type="str", choices=["disable", "enable"]),
        safe_search=dict(required=False, type="str", choices=["disable", "enable"]),
        redirect_portal=dict(required=False, type="str"),
        name=dict(required=False, type="str"),
        log_all_domain=dict(required=False, type="str", choices=["disable", "enable"]),
        external_ip_blocklist=dict(required=False, type="str"),
        comment=dict(required=False, type="str"),
        block_botnet=dict(required=False, type="str", choices=["disable", "enable"]),
        block_action=dict(required=False, type="str", choices=["block", "redirect"]),

        domain_filter_domain_filter_table=dict(required=False, type="str"),

        ftgd_dns_options=dict(required=False, type="str", choices=["error-allow", "ftgd-disable"]),

        ftgd_dns_filters_action=dict(required=False, type="str", choices=["monitor", "block"]),
        ftgd_dns_filters_category=dict(required=False, type="str"),
        ftgd_dns_filters_log=dict(required=False, type="str", choices=["disable", "enable"]),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "youtube-restrict": module.params["youtube_restrict"],
        "sdns-ftgd-err-log": module.params["sdns_ftgd_err_log"],
        "sdns-domain-log": module.params["sdns_domain_log"],
        "safe-search": module.params["safe_search"],
        "redirect-portal": module.params["redirect_portal"],
        "name": module.params["name"],
        "log-all-domain": module.params["log_all_domain"],
        "external-ip-blocklist": module.params["external_ip_blocklist"],
        "comment": module.params["comment"],
        "block-botnet": module.params["block_botnet"],
        "block-action": module.params["block_action"],
        "domain-filter": {
            "domain-filter-table": module.params["domain_filter_domain_filter_table"],
        },
        "ftgd-dns": {
            "options": module.params["ftgd_dns_options"],
            "filters": {
                "action": module.params["ftgd_dns_filters_action"],
                "category": module.params["ftgd_dns_filters_category"],
                "log": module.params["ftgd_dns_filters_log"],
            }
        }
    }

    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    results = DEFAULT_RESULT_OBJ

    try:
        results = fmgr_dnsfilter_profile_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function

__metaclass__ = type

ANSIBLE_METADATA = {'status': ['preview'],
                    'supported_by': 'community',
                    'metadata_version': '1.1'}

DOCUMENTATION = '''
---
module: fmgr_secprof_dns
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author:
    - Luke Weighall (@lweighall)
    - Andrew Welsh (@Ghilli3)
    - Jim Huber (@p4r4n0y1ng)
short_description: Manage DNS security profiles in FortiManager
description:
  -  Manage DNS security profiles in FortiManager

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: false
    default: root

  mode:
    description:
      - Sets one of three modes for managing the object.
      - Allows use of soft-adds instead of overwriting existing values.
    choices: ['add', 'set', 'delete', 'update']
    required: false
    default: add

  youtube_restrict:
    type: str
    description:
      - Set safe search for YouTube restriction level.
      - choice | strict | Enable strict safe seach for YouTube.
      - choice | moderate | Enable moderate safe search for YouTube.
    required: false
    choices: ["strict", "moderate"]

  sdns_ftgd_err_log:
    type: str
    description:
      - Enable/disable FortiGuard SDNS rating error logging.
      - choice | disable | Disable FortiGuard SDNS rating error logging.
      - choice | enable | Enable FortiGuard SDNS rating error logging.
    required: false
    choices: ["disable", "enable"]

  sdns_domain_log:
    type: str
    description:
      - Enable/disable domain filtering and botnet domain logging.
      - choice | disable | Disable domain filtering and botnet domain logging.
      - choice | enable | Enable domain filtering and botnet domain logging.
    required: false
    choices: ["disable", "enable"]

  safe_search:
    type: str
    description:
      - Enable/disable Google, Bing, and YouTube safe search.
      - choice | disable | Disable Google, Bing, and YouTube safe search.
      - choice | enable | Enable Google, Bing, and YouTube safe search.
    required: false
    choices: ["disable", "enable"]

  redirect_portal:
    type: str
    description:
      - IP address of the SDNS redirect portal.
    required: false

  name:
    type: str
    description:
      - Profile name.
    required: false

  log_all_domain:
    type: str
    description:
      - Enable/disable logging of all domains visited (detailed DNS logging).
      - choice | disable | Disable logging of all domains visited.
      - choice | enable | Enable logging of all domains visited.
    required: false
    choices: ["disable", "enable"]

  external_ip_blocklist:
    type: str
    description:
      - One or more external IP block lists.
    required: false

  comment:
    type: str
    description:
      - Comment for the security profile to show in the FortiManager GUI.
    required: false

  block_botnet:
    type: str
    description:
      - Enable/disable blocking botnet C&C; DNS lookups.
      - choice | disable | Disable blocking botnet C&C; DNS lookups.
      - choice | enable | Enable blocking botnet C&C; DNS lookups.
    required: false
    choices: ["disable", "enable"]

  block_action:
    type: str
    description:
      - Action to take for blocked domains.
      - choice | block | Return NXDOMAIN for blocked domains.
      - choice | redirect | Redirect blocked domains to SDNS portal.
    required: false
    choices: ["block", "redirect"]

  domain_filter_domain_filter_table:
    type: str
    description:
      - DNS domain filter table ID.
    required: false

  ftgd_dns_options:
    type: str
    description:
      - FortiGuard DNS filter options.
      - FLAG Based Options. Specify multiple in list form.
      - flag | error-allow | Allow all domains when FortiGuard DNS servers fail.
      - flag | ftgd-disable | Disable FortiGuard DNS domain rating.
    required: false
    choices: ["error-allow", "ftgd-disable"]

  ftgd_dns_filters_action:
    type: str
    description:
      - Action to take for DNS requests matching the category.
      - choice | monitor | Allow DNS requests matching the category and log the result.
      - choice | block | Block DNS requests matching the category.
    required: false
    choices: ["monitor", "block"]

  ftgd_dns_filters_category:
    type: str
    description:
      - Category number.
    required: false

  ftgd_dns_filters_log:
    type: str
    description:
      - Enable/disable DNS filter logging for this DNS profile.
      - choice | disable | Disable DNS filter logging.
      - choice | enable | Enable DNS filter logging.
    required: false
    choices: ["disable", "enable"]


'''

EXAMPLES = '''
  - name: DELETE Profile
    fmgr_secprof_dns:
      name: "Ansible_DNS_Profile"
      comment: "Created by Ansible Module TEST"
      mode: "delete"

  - name: CREATE Profile
    fmgr_secprof_dns:
      name: "Ansible_DNS_Profile"
      comment: "Created by Ansible Module TEST"
      mode: "set"
      block_action: "block"


'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import FMGRMethods
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
from ansible.module_utils.network.fortimanager.common import prepare_dict
from ansible.module_utils.network.fortimanager.common import scrub_dict


###############
# START METHODS
###############


def fmgr_dnsfilter_profile_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]
    url = ""
    datagram = {}

    response = DEFAULT_RESULT_OBJ

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/dnsfilter/profile'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/dnsfilter/profile/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])

    return response


#############
# END METHODS
#############


def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        youtube_restrict=dict(required=False, type="str", choices=["strict", "moderate"]),
        sdns_ftgd_err_log=dict(required=False, type="str", choices=["disable", "enable"]),
        sdns_domain_log=dict(required=False, type="str", choices=["disable", "enable"]),
        safe_search=dict(required=False, type="str", choices=["disable", "enable"]),
        redirect_portal=dict(required=False, type="str"),
        name=dict(required=False, type="str"),
        log_all_domain=dict(required=False, type="str", choices=["disable", "enable"]),
        external_ip_blocklist=dict(required=False, type="str"),
        comment=dict(required=False, type="str"),
        block_botnet=dict(required=False, type="str", choices=["disable", "enable"]),
        block_action=dict(required=False, type="str", choices=["block", "redirect"]),

        domain_filter_domain_filter_table=dict(required=False, type="str"),

        ftgd_dns_options=dict(required=False, type="str", choices=["error-allow", "ftgd-disable"]),

        ftgd_dns_filters_action=dict(required=False, type="str", choices=["monitor", "block"]),
        ftgd_dns_filters_category=dict(required=False, type="str"),
        ftgd_dns_filters_log=dict(required=False, type="str", choices=["disable", "enable"]),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "youtube-restrict": module.params["youtube_restrict"],
        "sdns-ftgd-err-log": module.params["sdns_ftgd_err_log"],
        "sdns-domain-log": module.params["sdns_domain_log"],
        "safe-search": module.params["safe_search"],
        "redirect-portal": module.params["redirect_portal"],
        "name": module.params["name"],
        "log-all-domain": module.params["log_all_domain"],
        "external-ip-blocklist": module.params["external_ip_blocklist"],
        "comment": module.params["comment"],
        "block-botnet": module.params["block_botnet"],
        "block-action": module.params["block_action"],
        "domain-filter": {
            "domain-filter-table": module.params["domain_filter_domain_filter_table"],
        },
        "ftgd-dns": {
            "options": module.params["ftgd_dns_options"],
            "filters": {
                "action": module.params["ftgd_dns_filters_action"],
                "category": module.params["ftgd_dns_filters_category"],
                "log": module.params["ftgd_dns_filters_log"],
            }
        }
    }

    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    results = DEFAULT_RESULT_OBJ

    try:
        results = fmgr_dnsfilter_profile_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_secprof_ips

Metadata

Name: fmgr_secprof_ips

Description: Managing IPS security profiles in FortiManager

Author(s):

  • Luke Weighall (github: @lweighall)
  • Andrew Welsh (github: @Ghilli3)
  • Jim Huber (github: @p4r4n0y1ng)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Andrew Welsh

Module Github Link

Parameters
adom
  • Description: The ADOM the configuration should belong to.
  • Required: False
  • default: root
block_malicious_url
  • Description: Enable/disable malicious URL blocking.
  • Required: False
  • choices: [‘disable’, ‘enable’]
comment
  • Description: Comment.
  • Required: False
entries
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

entries_action
  • Description: Action taken with traffic in which signatures are detected.
  • Required: False
  • choices: [‘pass’, ‘block’, ‘reset’, ‘default’]
entries_application
  • Description: Applications to be protected. set application ? lists available applications. all includes all applications. other includes all unlisted applications.
  • Required: False
entries_exempt_ip_dst_ip
  • Description: Destination IP address and netmask.
  • Required: False
entries_exempt_ip_src_ip
  • Description: Source IP address and netmask.
  • Required: False
entries_location
  • Description: Protect client or server traffic.
  • Required: False
entries_log
  • Description: Enable/disable logging of signatures included in filter.
  • Required: False
  • choices: [‘disable’, ‘enable’]
entries_log_attack_context
  • Description: Enable/disable logging of attack context| URL buffer, header buffer, body buffer, packet buffer.
  • Required: False
  • choices: [‘disable’, ‘enable’]
entries_log_packet
  • Description: Enable/disable packet logging. Enable to save the packet that triggers the filter. You can download the packets in pcap format for diagnostic use.
  • Required: False
  • choices: [‘disable’, ‘enable’]
entries_os
  • Description: Operating systems to be protected. all includes all operating systems. other includes all unlisted operating systems.
  • Required: False
entries_protocol
  • Description: Protocols to be examined. set protocol ? lists available protocols. all includes all protocols. other includes all unlisted protocols.
  • Required: False
entries_quarantine
  • Description: Quarantine method.
  • Required: False
  • choices: [‘none’, ‘attacker’]
entries_quarantine_expiry
  • Description: Duration of quarantine.
  • Required: False
entries_quarantine_log
  • Description: Enable/disable quarantine logging.
  • Required: False
  • choices: [‘disable’, ‘enable’]
entries_rate_count
  • Description: Count of the rate.
  • Required: False
entries_rate_duration
  • Description: Duration (sec) of the rate.
  • Required: False
entries_rate_mode
  • Description: Rate limit mode.
  • Required: False
  • choices: [‘periodical’, ‘continuous’]
entries_rate_track
  • Description: Track the packet protocol field.
  • Required: False
  • choices: [‘none’, ‘src-ip’, ‘dest-ip’, ‘dhcp-client-mac’, ‘dns-domain’]
entries_rule
  • Description: Identifies the predefined or custom IPS signatures to add to the sensor.
  • Required: False
entries_severity
  • Description: Relative severity of the signature, from info to critical. Log messages generated by the signature include the severity.
  • Required: False
entries_status
  • Description: Status of the signatures included in filter. default enables the filter and only use filters with default status of enable. Filters with default status of disable will not be used.
  • Required: False
  • choices: [‘disable’, ‘enable’, ‘default’]
extended_log
  • Description: Enable/disable extended logging.
  • Required: False
  • choices: [‘disable’, ‘enable’]
filter
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

filter_action
  • Description: Action of selected rules.
  • Required: False
  • choices: [‘pass’, ‘block’, ‘default’, ‘reset’]
filter_application
  • Description: Vulnerable application filter.
  • Required: False
filter_location
  • Description: Vulnerability location filter.
  • Required: False
filter_log
  • Description: Enable/disable logging of selected rules.
  • Required: False
  • choices: [‘disable’, ‘enable’]
filter_log_packet
  • Description: Enable/disable packet logging of selected rules.
  • Required: False
  • choices: [‘disable’, ‘enable’]
filter_name
  • Description: Filter name.
  • Required: False
filter_os
  • Description: Vulnerable OS filter.
  • Required: False
filter_protocol
  • Description: Vulnerable protocol filter.
  • Required: False
filter_quarantine
  • Description: Quarantine IP or interface.
  • Required: False
  • choices: [‘none’, ‘attacker’]
filter_quarantine_expiry
  • Description: Duration of quarantine in minute.
  • Required: False
filter_quarantine_log
  • Description: Enable/disable logging of selected quarantine.
  • Required: False
  • choices: [‘disable’, ‘enable’]
filter_severity
  • Description: Vulnerability severity filter.
  • Required: False
filter_status
  • Description: Selected rules status.
  • Required: False
  • choices: [‘disable’, ‘enable’, ‘default’]
mode
  • Description: Sets one of three modes for managing the object.

    Allows use of soft-adds instead of overwriting existing values

  • Required: False

  • default: add

  • choices: [‘add’, ‘set’, ‘delete’, ‘update’]

name
  • Description: Sensor name.
  • Required: False
override
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

override_action
  • Description: Action of override rule.
  • Required: False
  • choices: [‘pass’, ‘block’, ‘reset’]
override_exempt_ip_dst_ip
  • Description: Destination IP address and netmask.
  • Required: False
override_exempt_ip_src_ip
  • Description: Source IP address and netmask.
  • Required: False
override_log
  • Description: Enable/disable logging.
  • Required: False
  • choices: [‘disable’, ‘enable’]
override_log_packet
  • Description: Enable/disable packet logging.
  • Required: False
  • choices: [‘disable’, ‘enable’]
override_quarantine
  • Description: Quarantine IP or interface.
  • Required: False
  • choices: [‘none’, ‘attacker’]
override_quarantine_expiry
  • Description: Duration of quarantine in minute.
  • Required: False
override_quarantine_log
  • Description: Enable/disable logging of selected quarantine.
  • Required: False
  • choices: [‘disable’, ‘enable’]
override_rule_id
  • Description: Override rule ID.
  • Required: False
override_status
  • Description: Enable/disable status of override rule.
  • Required: False
  • choices: [‘disable’, ‘enable’]
replacemsg_group
  • Description: Replacement message group.
  • Required: False
Functions
  • fmgr_ips_sensor_modify
def fmgr_ips_sensor_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/ips/sensor'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/ips/sensor/{name}'.format(
            adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])

    return response


#############
# END METHODS
#############
  • main
def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"],
                  type="str", default="add"),

        replacemsg_group=dict(required=False, type="str"),
        name=dict(required=False, type="str"),
        extended_log=dict(required=False, type="str",
                          choices=["disable", "enable"]),
        comment=dict(required=False, type="str"),
        block_malicious_url=dict(required=False, type="str", choices=[
                                 "disable", "enable"]),
        entries=dict(required=False, type="list"),
        entries_action=dict(required=False, type="str", choices=[
                            "pass", "block", "reset", "default"]),
        entries_application=dict(required=False, type="str"),
        entries_location=dict(required=False, type="str"),
        entries_log=dict(required=False, type="str",
                         choices=["disable", "enable"]),
        entries_log_attack_context=dict(
            required=False, type="str", choices=["disable", "enable"]),
        entries_log_packet=dict(required=False, type="str", choices=[
                                "disable", "enable"]),
        entries_os=dict(required=False, type="str"),
        entries_protocol=dict(required=False, type="str"),
        entries_quarantine=dict(required=False, type="str", choices=[
                                "none", "attacker"]),
        entries_quarantine_expiry=dict(required=False, type="str"),
        entries_quarantine_log=dict(
            required=False, type="str", choices=["disable", "enable"]),
        entries_rate_count=dict(required=False, type="int"),
        entries_rate_duration=dict(required=False, type="int"),
        entries_rate_mode=dict(required=False, type="str", choices=[
                               "periodical", "continuous"]),
        entries_rate_track=dict(required=False, type="str",
                                choices=["none", "src-ip", "dest-ip", "dhcp-client-mac", "dns-domain"]),
        entries_rule=dict(required=False, type="str"),
        entries_severity=dict(required=False, type="str"),
        entries_status=dict(required=False, type="str", choices=[
                            "disable", "enable", "default"]),

        entries_exempt_ip_dst_ip=dict(required=False, type="str"),
        entries_exempt_ip_src_ip=dict(required=False, type="str"),
        filter=dict(required=False, type="list"),
        filter_action=dict(required=False, type="str", choices=[
                           "pass", "block", "default", "reset"]),
        filter_application=dict(required=False, type="str"),
        filter_location=dict(required=False, type="str"),
        filter_log=dict(required=False, type="str",
                        choices=["disable", "enable"]),
        filter_log_packet=dict(required=False, type="str",
                               choices=["disable", "enable"]),
        filter_name=dict(required=False, type="str"),
        filter_os=dict(required=False, type="str"),
        filter_protocol=dict(required=False, type="str"),
        filter_quarantine=dict(required=False, type="str",
                               choices=["none", "attacker"]),
        filter_quarantine_expiry=dict(required=False, type="int"),
        filter_quarantine_log=dict(required=False, type="str", choices=[
                                   "disable", "enable"]),
        filter_severity=dict(required=False, type="str"),
        filter_status=dict(required=False, type="str", choices=[
                           "disable", "enable", "default"]),
        override=dict(required=False, type="list"),
        override_action=dict(required=False, type="str",
                             choices=["pass", "block", "reset"]),
        override_log=dict(required=False, type="str",
                          choices=["disable", "enable"]),
        override_log_packet=dict(required=False, type="str", choices=[
                                 "disable", "enable"]),
        override_quarantine=dict(required=False, type="str", choices=[
                                 "none", "attacker"]),
        override_quarantine_expiry=dict(required=False, type="int"),
        override_quarantine_log=dict(
            required=False, type="str", choices=["disable", "enable"]),
        override_rule_id=dict(required=False, type="str"),
        override_status=dict(required=False, type="str",
                             choices=["disable", "enable"]),

        override_exempt_ip_dst_ip=dict(required=False, type="str"),
        override_exempt_ip_src_ip=dict(required=False, type="str"),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "replacemsg-group": module.params["replacemsg_group"],
        "name": module.params["name"],
        "extended-log": module.params["extended_log"],
        "comment": module.params["comment"],
        "block-malicious-url": module.params["block_malicious_url"],
        "entries": {
            "action": module.params["entries_action"],
            "application": module.params["entries_application"],
            "location": module.params["entries_location"],
            "log": module.params["entries_log"],
            "log-attack-context": module.params["entries_log_attack_context"],
            "log-packet": module.params["entries_log_packet"],
            "os": module.params["entries_os"],
            "protocol": module.params["entries_protocol"],
            "quarantine": module.params["entries_quarantine"],
            "quarantine-expiry": module.params["entries_quarantine_expiry"],
            "quarantine-log": module.params["entries_quarantine_log"],
            "rate-count": module.params["entries_rate_count"],
            "rate-duration": module.params["entries_rate_duration"],
            "rate-mode": module.params["entries_rate_mode"],
            "rate-track": module.params["entries_rate_track"],
            "rule": module.params["entries_rule"],
            "severity": module.params["entries_severity"],
            "status": module.params["entries_status"],
            "exempt-ip": {
                "dst-ip": module.params["entries_exempt_ip_dst_ip"],
                "src-ip": module.params["entries_exempt_ip_src_ip"],
            },
        },
        "filter": {
            "action": module.params["filter_action"],
            "application": module.params["filter_application"],
            "location": module.params["filter_location"],
            "log": module.params["filter_log"],
            "log-packet": module.params["filter_log_packet"],
            "name": module.params["filter_name"],
            "os": module.params["filter_os"],
            "protocol": module.params["filter_protocol"],
            "quarantine": module.params["filter_quarantine"],
            "quarantine-expiry": module.params["filter_quarantine_expiry"],
            "quarantine-log": module.params["filter_quarantine_log"],
            "severity": module.params["filter_severity"],
            "status": module.params["filter_status"],
        },
        "override": {
            "action": module.params["override_action"],
            "log": module.params["override_log"],
            "log-packet": module.params["override_log_packet"],
            "quarantine": module.params["override_quarantine"],
            "quarantine-expiry": module.params["override_quarantine_expiry"],
            "quarantine-log": module.params["override_quarantine_log"],
            "rule-id": module.params["override_rule_id"],
            "status": module.params["override_status"],
            "exempt-ip": {
                "dst-ip": module.params["override_exempt_ip_dst_ip"],
                "src-ip": module.params["override_exempt_ip_src_ip"],
            }
        }
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['entries', 'filter', 'override']

    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)

    results = DEFAULT_RESULT_OBJ
    try:
        results = fmgr_ips_sensor_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function

__metaclass__ = type

ANSIBLE_METADATA = {'status': ['preview'],
                    'supported_by': 'community',
                    'metadata_version': '1.1'}

DOCUMENTATION = '''
---
module: fmgr_secprof_ips
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author:
  - Luke Weighall (@lweighall)
  - Andrew Welsh (@Ghilli3)
  - Jim Huber (@p4r4n0y1ng)
short_description: Managing IPS security profiles in FortiManager
description:
  - Managing IPS security profiles in FortiManager

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: false
    default: root

  mode:
    description:
      - Sets one of three modes for managing the object.
      - Allows use of soft-adds instead of overwriting existing values
    choices: ['add', 'set', 'delete', 'update']
    required: false
    default: add

  replacemsg_group:
    description:
      - Replacement message group.
    required: false

  name:
    description:
      - Sensor name.
    required: false

  extended_log:
    description:
      - Enable/disable extended logging.
    required: false
    choices:
      - disable
      - enable

  comment:
    description:
      - Comment.
    required: false

  block_malicious_url:
    description:
      - Enable/disable malicious URL blocking.
    required: false
    choices:
      - disable
      - enable

  entries:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  entries_action:
    description:
      - Action taken with traffic in which signatures are detected.
    required: false
    choices:
      - pass
      - block
      - reset
      - default

  entries_application:
    description:
      - Applications to be protected. set application ? lists available applications. all includes
        all applications. other includes all unlisted applications.
    required: false

  entries_location:
    description:
      - Protect client or server traffic.
    required: false

  entries_log:
    description:
      - Enable/disable logging of signatures included in filter.
    required: false
    choices:
      - disable
      - enable

  entries_log_attack_context:
    description:
      - Enable/disable logging of attack context| URL buffer, header buffer, body buffer, packet buffer.
    required: false
    choices:
      - disable
      - enable

  entries_log_packet:
    description:
      - Enable/disable packet logging. Enable to save the packet that triggers the filter. You can
        download the packets in pcap format for diagnostic use.
    required: false
    choices:
      - disable
      - enable

  entries_os:
    description:
      - Operating systems to be protected.  all includes all operating systems. other includes all
        unlisted operating systems.
    required: false

  entries_protocol:
    description:
      - Protocols to be examined. set protocol ? lists available protocols. all includes all protocols.
        other includes all unlisted protocols.
    required: false

  entries_quarantine:
    description:
      - Quarantine method.
    required: false
    choices:
      - none
      - attacker

  entries_quarantine_expiry:
    description:
      - Duration of quarantine.
    required: false

  entries_quarantine_log:
    description:
      - Enable/disable quarantine logging.
    required: false
    choices:
      - disable
      - enable

  entries_rate_count:
    description:
      - Count of the rate.
    required: false

  entries_rate_duration:
    description:
      - Duration (sec) of the rate.
    required: false

  entries_rate_mode:
    description:
      - Rate limit mode.
    required: false
    choices:
      - periodical
      - continuous

  entries_rate_track:
    description:
      - Track the packet protocol field.
    required: false
    choices:
      - none
      - src-ip
      - dest-ip
      - dhcp-client-mac
      - dns-domain

  entries_rule:
    description:
      - Identifies the predefined or custom IPS signatures to add to the sensor.
    required: false

  entries_severity:
    description:
      - Relative severity of the signature, from info to critical. Log messages generated by the signature
        include the severity.
    required: false

  entries_status:
    description:
      - Status of the signatures included in filter. default enables the filter and only use filters
        with default status of enable. Filters with default status of disable will not be used.
    required: false
    choices:
      - disable
      - enable
      - default

  entries_exempt_ip_dst_ip:
    description:
      - Destination IP address and netmask.
    required: false

  entries_exempt_ip_src_ip:
    description:
      - Source IP address and netmask.
    required: false

  filter:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  filter_action:
    description:
      - Action of selected rules.
    required: false
    choices:
      - pass
      - block
      - default
      - reset

  filter_application:
    description:
      - Vulnerable application filter.
    required: false

  filter_location:
    description:
      - Vulnerability location filter.
    required: false

  filter_log:
    description:
      - Enable/disable logging of selected rules.
    required: false
    choices:
      - disable
      - enable

  filter_log_packet:
    description:
      - Enable/disable packet logging of selected rules.
    required: false
    choices:
      - disable
      - enable

  filter_name:
    description:
      - Filter name.
    required: false

  filter_os:
    description:
      - Vulnerable OS filter.
    required: false

  filter_protocol:
    description:
      - Vulnerable protocol filter.
    required: false

  filter_quarantine:
    description:
      - Quarantine IP or interface.
    required: false
    choices:
      - none
      - attacker

  filter_quarantine_expiry:
    description:
      - Duration of quarantine in minute.
    required: false

  filter_quarantine_log:
    description:
      - Enable/disable logging of selected quarantine.
    required: false
    choices:
      - disable
      - enable

  filter_severity:
    description:
      - Vulnerability severity filter.
    required: false

  filter_status:
    description:
      - Selected rules status.
    required: false
    choices:
      - disable
      - enable
      - default

  override:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  override_action:
    description:
      - Action of override rule.
    required: false
    choices:
      - pass
      - block
      - reset

  override_log:
    description:
      - Enable/disable logging.
    required: false
    choices:
      - disable
      - enable

  override_log_packet:
    description:
      - Enable/disable packet logging.
    required: false
    choices:
      - disable
      - enable

  override_quarantine:
    description:
      - Quarantine IP or interface.
    required: false
    choices:
      - none
      - attacker

  override_quarantine_expiry:
    description:
      - Duration of quarantine in minute.
    required: false

  override_quarantine_log:
    description:
      - Enable/disable logging of selected quarantine.
    required: false
    choices:
      - disable
      - enable

  override_rule_id:
    description:
      - Override rule ID.
    required: false

  override_status:
    description:
      - Enable/disable status of override rule.
    required: false
    choices:
      - disable
      - enable

  override_exempt_ip_dst_ip:
    description:
      - Destination IP address and netmask.
    required: false

  override_exempt_ip_src_ip:
    description:
      - Source IP address and netmask.
    required: false
'''

EXAMPLES = '''
  - name: DELETE Profile
    fmgr_secprof_ips:
      name: "Ansible_IPS_Profile"
      comment: "Created by Ansible Module TEST"
      mode: "delete"

  - name: CREATE Profile
    fmgr_secprof_ips:
      name: "Ansible_IPS_Profile"
      comment: "Created by Ansible Module TEST"
      mode: "set"
      block_malicious_url: "enable"
      entries: [{severity: "high", action: "block", log-packet: "enable"}, {severity: "medium", action: "pass"}]
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
from ansible.module_utils.network.fortimanager.common import prepare_dict
from ansible.module_utils.network.fortimanager.common import scrub_dict


###############
# START METHODS
###############


def fmgr_ips_sensor_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/ips/sensor'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/ips/sensor/{name}'.format(
            adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])

    return response


#############
# END METHODS
#############


def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"],
                  type="str", default="add"),

        replacemsg_group=dict(required=False, type="str"),
        name=dict(required=False, type="str"),
        extended_log=dict(required=False, type="str",
                          choices=["disable", "enable"]),
        comment=dict(required=False, type="str"),
        block_malicious_url=dict(required=False, type="str", choices=[
                                 "disable", "enable"]),
        entries=dict(required=False, type="list"),
        entries_action=dict(required=False, type="str", choices=[
                            "pass", "block", "reset", "default"]),
        entries_application=dict(required=False, type="str"),
        entries_location=dict(required=False, type="str"),
        entries_log=dict(required=False, type="str",
                         choices=["disable", "enable"]),
        entries_log_attack_context=dict(
            required=False, type="str", choices=["disable", "enable"]),
        entries_log_packet=dict(required=False, type="str", choices=[
                                "disable", "enable"]),
        entries_os=dict(required=False, type="str"),
        entries_protocol=dict(required=False, type="str"),
        entries_quarantine=dict(required=False, type="str", choices=[
                                "none", "attacker"]),
        entries_quarantine_expiry=dict(required=False, type="str"),
        entries_quarantine_log=dict(
            required=False, type="str", choices=["disable", "enable"]),
        entries_rate_count=dict(required=False, type="int"),
        entries_rate_duration=dict(required=False, type="int"),
        entries_rate_mode=dict(required=False, type="str", choices=[
                               "periodical", "continuous"]),
        entries_rate_track=dict(required=False, type="str",
                                choices=["none", "src-ip", "dest-ip", "dhcp-client-mac", "dns-domain"]),
        entries_rule=dict(required=False, type="str"),
        entries_severity=dict(required=False, type="str"),
        entries_status=dict(required=False, type="str", choices=[
                            "disable", "enable", "default"]),

        entries_exempt_ip_dst_ip=dict(required=False, type="str"),
        entries_exempt_ip_src_ip=dict(required=False, type="str"),
        filter=dict(required=False, type="list"),
        filter_action=dict(required=False, type="str", choices=[
                           "pass", "block", "default", "reset"]),
        filter_application=dict(required=False, type="str"),
        filter_location=dict(required=False, type="str"),
        filter_log=dict(required=False, type="str",
                        choices=["disable", "enable"]),
        filter_log_packet=dict(required=False, type="str",
                               choices=["disable", "enable"]),
        filter_name=dict(required=False, type="str"),
        filter_os=dict(required=False, type="str"),
        filter_protocol=dict(required=False, type="str"),
        filter_quarantine=dict(required=False, type="str",
                               choices=["none", "attacker"]),
        filter_quarantine_expiry=dict(required=False, type="int"),
        filter_quarantine_log=dict(required=False, type="str", choices=[
                                   "disable", "enable"]),
        filter_severity=dict(required=False, type="str"),
        filter_status=dict(required=False, type="str", choices=[
                           "disable", "enable", "default"]),
        override=dict(required=False, type="list"),
        override_action=dict(required=False, type="str",
                             choices=["pass", "block", "reset"]),
        override_log=dict(required=False, type="str",
                          choices=["disable", "enable"]),
        override_log_packet=dict(required=False, type="str", choices=[
                                 "disable", "enable"]),
        override_quarantine=dict(required=False, type="str", choices=[
                                 "none", "attacker"]),
        override_quarantine_expiry=dict(required=False, type="int"),
        override_quarantine_log=dict(
            required=False, type="str", choices=["disable", "enable"]),
        override_rule_id=dict(required=False, type="str"),
        override_status=dict(required=False, type="str",
                             choices=["disable", "enable"]),

        override_exempt_ip_dst_ip=dict(required=False, type="str"),
        override_exempt_ip_src_ip=dict(required=False, type="str"),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "replacemsg-group": module.params["replacemsg_group"],
        "name": module.params["name"],
        "extended-log": module.params["extended_log"],
        "comment": module.params["comment"],
        "block-malicious-url": module.params["block_malicious_url"],
        "entries": {
            "action": module.params["entries_action"],
            "application": module.params["entries_application"],
            "location": module.params["entries_location"],
            "log": module.params["entries_log"],
            "log-attack-context": module.params["entries_log_attack_context"],
            "log-packet": module.params["entries_log_packet"],
            "os": module.params["entries_os"],
            "protocol": module.params["entries_protocol"],
            "quarantine": module.params["entries_quarantine"],
            "quarantine-expiry": module.params["entries_quarantine_expiry"],
            "quarantine-log": module.params["entries_quarantine_log"],
            "rate-count": module.params["entries_rate_count"],
            "rate-duration": module.params["entries_rate_duration"],
            "rate-mode": module.params["entries_rate_mode"],
            "rate-track": module.params["entries_rate_track"],
            "rule": module.params["entries_rule"],
            "severity": module.params["entries_severity"],
            "status": module.params["entries_status"],
            "exempt-ip": {
                "dst-ip": module.params["entries_exempt_ip_dst_ip"],
                "src-ip": module.params["entries_exempt_ip_src_ip"],
            },
        },
        "filter": {
            "action": module.params["filter_action"],
            "application": module.params["filter_application"],
            "location": module.params["filter_location"],
            "log": module.params["filter_log"],
            "log-packet": module.params["filter_log_packet"],
            "name": module.params["filter_name"],
            "os": module.params["filter_os"],
            "protocol": module.params["filter_protocol"],
            "quarantine": module.params["filter_quarantine"],
            "quarantine-expiry": module.params["filter_quarantine_expiry"],
            "quarantine-log": module.params["filter_quarantine_log"],
            "severity": module.params["filter_severity"],
            "status": module.params["filter_status"],
        },
        "override": {
            "action": module.params["override_action"],
            "log": module.params["override_log"],
            "log-packet": module.params["override_log_packet"],
            "quarantine": module.params["override_quarantine"],
            "quarantine-expiry": module.params["override_quarantine_expiry"],
            "quarantine-log": module.params["override_quarantine_log"],
            "rule-id": module.params["override_rule_id"],
            "status": module.params["override_status"],
            "exempt-ip": {
                "dst-ip": module.params["override_exempt_ip_dst_ip"],
                "src-ip": module.params["override_exempt_ip_src_ip"],
            }
        }
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['entries', 'filter', 'override']

    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)

    results = DEFAULT_RESULT_OBJ
    try:
        results = fmgr_ips_sensor_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_secprof_profile_group

Metadata

Name: fmgr_secprof_profile_group

Description: Manage security profile group which allows you to create a group of security profiles and apply that to a policy.

Author(s):

  • Luke Weighall (github: @lweighall)
  • Andrew Welsh (github: @Ghilli3)
  • Jim Huber (github: @p4r4n0y1ng)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Andrew Welsh

Module Github Link

Parameters
adom
  • Description: The ADOM the configuration should belong to.
  • Required: False
  • default: root
application_list
  • Description: Name of an existing Application list.
  • Required: False
av_profile
  • Description: Name of an existing Antivirus profile.
  • Required: False
dlp_sensor
  • Description: Name of an existing DLP sensor.
  • Required: False
dnsfilter_profile
  • Description: Name of an existing DNS filter profile.
  • Required: False
icap_profile
  • Description: Name of an existing ICAP profile.
  • Required: False
ips_sensor
  • Description: Name of an existing IPS sensor.
  • Required: False
mms_profile
  • Description: Name of an existing MMS profile.
  • Required: False
mode
  • Description: Sets one of three modes for managing the object.

    Allows use of soft-adds instead of overwriting existing values.

  • Required: False

  • default: add

  • choices: [‘add’, ‘set’, ‘delete’, ‘update’]

name
  • Description: Profile group name.
  • Required: False
profile_protocol_options
  • Description: Name of an existing Protocol options profile.
  • Required: False
spamfilter_profile
  • Description: Name of an existing Spam filter profile.
  • Required: False
ssh_filter_profile
  • Description: Name of an existing SSH filter profile.
  • Required: False
ssl_ssh_profile
  • Description: Name of an existing SSL SSH profile.
  • Required: False
voip_profile
  • Description: Name of an existing VoIP profile.
  • Required: False
waf_profile
  • Description: Name of an existing Web application firewall profile.
  • Required: False
webfilter_profile
  • Description: Name of an existing Web filter profile.
  • Required: False
Functions
  • fmgr_firewall_profile_group_modify
def fmgr_firewall_profile_group_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]
    url = ""
    datagram = {}

    response = DEFAULT_RESULT_OBJ

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/firewall/profile-group'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/firewall/profile-group/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])

    return response


#############
# END METHODS
#############
  • main
def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        webfilter_profile=dict(required=False, type="str"),
        waf_profile=dict(required=False, type="str"),
        voip_profile=dict(required=False, type="str"),
        ssl_ssh_profile=dict(required=False, type="str"),
        ssh_filter_profile=dict(required=False, type="str"),
        spamfilter_profile=dict(required=False, type="str"),
        profile_protocol_options=dict(required=False, type="str"),
        name=dict(required=False, type="str"),
        mms_profile=dict(required=False, type="str"),
        ips_sensor=dict(required=False, type="str"),
        icap_profile=dict(required=False, type="str"),
        dnsfilter_profile=dict(required=False, type="str"),
        dlp_sensor=dict(required=False, type="str"),
        av_profile=dict(required=False, type="str"),
        application_list=dict(required=False, type="str"),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "webfilter-profile": module.params["webfilter_profile"],
        "waf-profile": module.params["waf_profile"],
        "voip-profile": module.params["voip_profile"],
        "ssl-ssh-profile": module.params["ssl_ssh_profile"],
        "ssh-filter-profile": module.params["ssh_filter_profile"],
        "spamfilter-profile": module.params["spamfilter_profile"],
        "profile-protocol-options": module.params["profile_protocol_options"],
        "name": module.params["name"],
        "mms-profile": module.params["mms_profile"],
        "ips-sensor": module.params["ips_sensor"],
        "icap-profile": module.params["icap_profile"],
        "dnsfilter-profile": module.params["dnsfilter_profile"],
        "dlp-sensor": module.params["dlp_sensor"],
        "av-profile": module.params["av_profile"],
        "application-list": module.params["application_list"],

    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    results = DEFAULT_RESULT_OBJ

    try:
        results = fmgr_firewall_profile_group_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {'status': ['preview'],
                    'supported_by': 'community',
                    'metadata_version': '1.1'}

DOCUMENTATION = '''
---
module: fmgr_secprof_profile_group
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author:
    - Luke Weighall (@lweighall)
    - Andrew Welsh (@Ghilli3)
    - Jim Huber (@p4r4n0y1ng)
short_description: Manage security profiles within FortiManager
description:
  - Manage security profile group which allows you to create a group of security profiles and apply that to a policy.

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: false
    default: root

  mode:
    description:
      - Sets one of three modes for managing the object.
      - Allows use of soft-adds instead of overwriting existing values.
    choices: ['add', 'set', 'delete', 'update']
    required: false
    default: add

  webfilter_profile:
    type: str
    description:
      - Name of an existing Web filter profile.
    required: false

  waf_profile:
    type: str
    description:
      - Name of an existing Web application firewall profile.
    required: false

  voip_profile:
    type: str
    description:
      - Name of an existing VoIP profile.
    required: false

  ssl_ssh_profile:
    type: str
    description:
      - Name of an existing SSL SSH profile.
    required: false

  ssh_filter_profile:
    type: str
    description:
      - Name of an existing SSH filter profile.
    required: false

  spamfilter_profile:
    type: str
    description:
      - Name of an existing Spam filter profile.
    required: false

  profile_protocol_options:
    type: str
    description:
      - Name of an existing Protocol options profile.
    required: false

  name:
    type: str
    description:
      - Profile group name.
    required: false

  mms_profile:
    type: str
    description:
      - Name of an existing MMS profile.
    required: false

  ips_sensor:
    type: str
    description:
      - Name of an existing IPS sensor.
    required: false

  icap_profile:
    type: str
    description:
      - Name of an existing ICAP profile.
    required: false

  dnsfilter_profile:
    type: str
    description:
      - Name of an existing DNS filter profile.
    required: false

  dlp_sensor:
    type: str
    description:
      - Name of an existing DLP sensor.
    required: false

  av_profile:
    type: str
    description:
      - Name of an existing Antivirus profile.
    required: false

  application_list:
    type: str
    description:
      - Name of an existing Application list.
    required: false


'''

EXAMPLES = '''
  - name: DELETE Profile
    fmgr_secprof_profile_group:
      name: "Ansible_TEST_Profile_Group"
      mode: "delete"

  - name: CREATE Profile
    fmgr_secprof_profile_group:
      name: "Ansible_TEST_Profile_Group"
      mode: "set"
      av_profile: "Ansible_AV_Profile"
      profile_protocol_options: "default"
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import FMGRMethods
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
from ansible.module_utils.network.fortimanager.common import prepare_dict
from ansible.module_utils.network.fortimanager.common import scrub_dict


###############
# START METHODS
###############


def fmgr_firewall_profile_group_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]
    url = ""
    datagram = {}

    response = DEFAULT_RESULT_OBJ

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/firewall/profile-group'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/firewall/profile-group/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])

    return response


#############
# END METHODS
#############


def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        webfilter_profile=dict(required=False, type="str"),
        waf_profile=dict(required=False, type="str"),
        voip_profile=dict(required=False, type="str"),
        ssl_ssh_profile=dict(required=False, type="str"),
        ssh_filter_profile=dict(required=False, type="str"),
        spamfilter_profile=dict(required=False, type="str"),
        profile_protocol_options=dict(required=False, type="str"),
        name=dict(required=False, type="str"),
        mms_profile=dict(required=False, type="str"),
        ips_sensor=dict(required=False, type="str"),
        icap_profile=dict(required=False, type="str"),
        dnsfilter_profile=dict(required=False, type="str"),
        dlp_sensor=dict(required=False, type="str"),
        av_profile=dict(required=False, type="str"),
        application_list=dict(required=False, type="str"),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "webfilter-profile": module.params["webfilter_profile"],
        "waf-profile": module.params["waf_profile"],
        "voip-profile": module.params["voip_profile"],
        "ssl-ssh-profile": module.params["ssl_ssh_profile"],
        "ssh-filter-profile": module.params["ssh_filter_profile"],
        "spamfilter-profile": module.params["spamfilter_profile"],
        "profile-protocol-options": module.params["profile_protocol_options"],
        "name": module.params["name"],
        "mms-profile": module.params["mms_profile"],
        "ips-sensor": module.params["ips_sensor"],
        "icap-profile": module.params["icap_profile"],
        "dnsfilter-profile": module.params["dnsfilter_profile"],
        "dlp-sensor": module.params["dlp_sensor"],
        "av-profile": module.params["av_profile"],
        "application-list": module.params["application_list"],

    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    results = DEFAULT_RESULT_OBJ

    try:
        results = fmgr_firewall_profile_group_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_secprof_proxy

Metadata

Name: fmgr_secprof_proxy

Description: Manage proxy security profiles for FortiGates via FortiManager using the FMG API with playbooks

Author(s):

  • Luke Weighall (github: @lweighall)
  • Andrew Welsh (github: @Ghilli3)
  • Jim Huber (github: @p4r4n0y1ng)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Andrew Welsh

Module Github Link

Parameters
adom
  • Description: The ADOM the configuration should belong to.
  • Required: False
  • default: root
header_client_ip
  • Description: Actions to take on the HTTP client-IP header in forwarded requests| forwards (pass), adds, or removes the HTTP

    header.

    choice | pass | Forward the same HTTP header.

    choice | add | Add the HTTP header.

    choice | remove | Remove the HTTP header.

  • Required: False

  • choices: [‘pass’, ‘add’, ‘remove’]

header_front_end_https
  • Description: Action to take on the HTTP front-end-HTTPS header in forwarded requests| forwards (pass), adds, or removes the

    HTTP header.

    choice | pass | Forward the same HTTP header.

    choice | add | Add the HTTP header.

    choice | remove | Remove the HTTP header.

  • Required: False

  • choices: [‘pass’, ‘add’, ‘remove’]

header_via_request
  • Description: Action to take on the HTTP via header in forwarded requests| forwards (pass), adds, or removes the HTTP header

    .

    choice | pass | Forward the same HTTP header.

    choice | add | Add the HTTP header.

    choice | remove | Remove the HTTP header.

  • Required: False

  • choices: [‘pass’, ‘add’, ‘remove’]

header_via_response
  • Description: Action to take on the HTTP via header in forwarded responses| forwards (pass), adds, or removes the HTTP heade

    choice | pass | Forward the same HTTP header.

    choice | add | Add the HTTP header.

    choice | remove | Remove the HTTP header.

  • Required: False

  • choices: [‘pass’, ‘add’, ‘remove’]

header_x_authenticated_groups
  • Description: Action to take on the HTTP x-authenticated-groups header in forwarded requests| forwards (pass), adds, or remo

    ves the HTTP header.

    choice | pass | Forward the same HTTP header.

    choice | add | Add the HTTP header.

    choice | remove | Remove the HTTP header.

  • Required: False

  • choices: [‘pass’, ‘add’, ‘remove’]

header_x_authenticated_user
  • Description: Action to take on the HTTP x-authenticated-user header in forwarded requests| forwards (pass), adds, or remove

    s the HTTP header.

    choice | pass | Forward the same HTTP header.

    choice | add | Add the HTTP header.

    choice | remove | Remove the HTTP header.

  • Required: False

  • choices: [‘pass’, ‘add’, ‘remove’]

header_x_forwarded_for
  • Description: Action to take on the HTTP x-forwarded-for header in forwarded requests| forwards (pass), adds, or removes the

    HTTP header.

    choice | pass | Forward the same HTTP header.

    choice | add | Add the HTTP header.

    choice | remove | Remove the HTTP header.

  • Required: False

  • choices: [‘pass’, ‘add’, ‘remove’]

headers
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

headers_action
  • Description: Action when HTTP the header forwarded.

    choice | add-to-request | Add the HTTP header to request.

    choice | add-to-response | Add the HTTP header to response.

    choice | remove-from-request | Remove the HTTP header from request.

    choice | remove-from-response | Remove the HTTP header from response.

  • Required: False

  • choices: [‘add-to-request’, ‘add-to-response’, ‘remove-from-request’, ‘remove-from-response’]

headers_content
  • Description: HTTP header’s content.
  • Required: False
headers_name
  • Description: HTTP forwarded header name.
  • Required: False
log_header_change
  • Description: Enable/disable logging HTTP header changes.

    choice | disable | Disable Enable/disable logging HTTP header changes.

    choice | enable | Enable Enable/disable logging HTTP header changes.

  • Required: False

  • choices: [‘disable’, ‘enable’]

mode
  • Description: Sets one of three modes for managing the object.

    Allows use of soft-adds instead of overwriting existing values

  • Required: False

  • default: add

  • choices: [‘add’, ‘set’, ‘delete’, ‘update’]

name
  • Description: Profile name.
  • Required: False
strip_encoding
  • Description: Enable/disable stripping unsupported encoding from the request header.

    choice | disable | Disable stripping of unsupported encoding from the request header.

    choice | enable | Enable stripping of unsupported encoding from the request header.

  • Required: False

  • choices: [‘disable’, ‘enable’]

Functions
  • fmgr_web_proxy_profile_modify
def fmgr_web_proxy_profile_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/web-proxy/profile'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/web-proxy/profile/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])

    return response


#############
# END METHODS
#############
  • main
def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        strip_encoding=dict(required=False, type="str", choices=["disable", "enable"]),
        name=dict(required=False, type="str"),
        log_header_change=dict(required=False, type="str", choices=["disable", "enable"]),
        header_x_forwarded_for=dict(required=False, type="str", choices=["pass", "add", "remove"]),
        header_x_authenticated_user=dict(required=False, type="str", choices=["pass", "add", "remove"]),
        header_x_authenticated_groups=dict(required=False, type="str", choices=["pass", "add", "remove"]),
        header_via_response=dict(required=False, type="str", choices=["pass", "add", "remove"]),
        header_via_request=dict(required=False, type="str", choices=["pass", "add", "remove"]),
        header_front_end_https=dict(required=False, type="str", choices=["pass", "add", "remove"]),
        header_client_ip=dict(required=False, type="str", choices=["pass", "add", "remove"]),
        headers=dict(required=False, type="list"),
        headers_action=dict(required=False, type="str", choices=["add-to-request", "add-to-response",
                                                                 "remove-from-request", "remove-from-response"]),
        headers_content=dict(required=False, type="str"),
        headers_name=dict(required=False, type="str"),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "strip-encoding": module.params["strip_encoding"],
        "name": module.params["name"],
        "log-header-change": module.params["log_header_change"],
        "header-x-forwarded-for": module.params["header_x_forwarded_for"],
        "header-x-authenticated-user": module.params["header_x_authenticated_user"],
        "header-x-authenticated-groups": module.params["header_x_authenticated_groups"],
        "header-via-response": module.params["header_via_response"],
        "header-via-request": module.params["header_via_request"],
        "header-front-end-https": module.params["header_front_end_https"],
        "header-client-ip": module.params["header_client_ip"],
        "headers": {
            "action": module.params["headers_action"],
            "content": module.params["headers_content"],
            "name": module.params["headers_name"],
        }
    }

    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['headers']
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)
    module.paramgram = paramgram

    results = DEFAULT_RESULT_OBJ
    try:
        results = fmgr_web_proxy_profile_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {'status': ['preview'],
                    'supported_by': 'community',
                    'metadata_version': '1.1'}

DOCUMENTATION = '''
---
module: fmgr_secprof_proxy
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author:
    - Luke Weighall (@lweighall)
    - Andrew Welsh (@Ghilli3)
    - Jim Huber (@p4r4n0y1ng)
short_description: Manage proxy security profiles in FortiManager
description:
  -  Manage proxy security profiles for FortiGates via FortiManager using the FMG API with playbooks

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: false
    default: root

  mode:
    description:
      - Sets one of three modes for managing the object.
      - Allows use of soft-adds instead of overwriting existing values
    choices: ['add', 'set', 'delete', 'update']
    required: false
    default: add

  strip_encoding:
    description:
      - Enable/disable stripping unsupported encoding from the request header.
      - choice | disable | Disable stripping of unsupported encoding from the request header.
      - choice | enable | Enable stripping of unsupported encoding from the request header.
    required: false
    choices: ["disable", "enable"]

  name:
    description:
      - Profile name.
    required: false

  log_header_change:
    description:
      - Enable/disable logging HTTP header changes.
      - choice | disable | Disable Enable/disable logging HTTP header changes.
      - choice | enable | Enable Enable/disable logging HTTP header changes.
    required: false
    choices: ["disable", "enable"]

  header_x_forwarded_for:
    description:
      - Action to take on the HTTP x-forwarded-for header in forwarded requests| forwards (pass), adds, or removes the
      -  HTTP header.
      - choice | pass | Forward the same HTTP header.
      - choice | add | Add the HTTP header.
      - choice | remove | Remove the HTTP header.
    required: false
    choices: ["pass", "add", "remove"]

  header_x_authenticated_user:
    description:
      - Action to take on the HTTP x-authenticated-user header in forwarded requests| forwards (pass), adds, or remove
      - s the HTTP header.
      - choice | pass | Forward the same HTTP header.
      - choice | add | Add the HTTP header.
      - choice | remove | Remove the HTTP header.
    required: false
    choices: ["pass", "add", "remove"]

  header_x_authenticated_groups:
    description:
      - Action to take on the HTTP x-authenticated-groups header in forwarded requests| forwards (pass), adds, or remo
      - ves the HTTP header.
      - choice | pass | Forward the same HTTP header.
      - choice | add | Add the HTTP header.
      - choice | remove | Remove the HTTP header.
    required: false
    choices: ["pass", "add", "remove"]

  header_via_response:
    description:
      - Action to take on the HTTP via header in forwarded responses| forwards (pass), adds, or removes the HTTP heade
      - r.
      - choice | pass | Forward the same HTTP header.
      - choice | add | Add the HTTP header.
      - choice | remove | Remove the HTTP header.
    required: false
    choices: ["pass", "add", "remove"]

  header_via_request:
    description:
      - Action to take on the HTTP via header in forwarded requests| forwards (pass), adds, or removes the HTTP header
      - .
      - choice | pass | Forward the same HTTP header.
      - choice | add | Add the HTTP header.
      - choice | remove | Remove the HTTP header.
    required: false
    choices: ["pass", "add", "remove"]

  header_front_end_https:
    description:
      - Action to take on the HTTP front-end-HTTPS header in forwarded requests| forwards (pass), adds, or removes the
      -  HTTP header.
      - choice | pass | Forward the same HTTP header.
      - choice | add | Add the HTTP header.
      - choice | remove | Remove the HTTP header.
    required: false
    choices: ["pass", "add", "remove"]

  header_client_ip:
    description:
      - Actions to take on the HTTP client-IP header in forwarded requests| forwards (pass), adds, or removes the HTTP
      -  header.
      - choice | pass | Forward the same HTTP header.
      - choice | add | Add the HTTP header.
      - choice | remove | Remove the HTTP header.
    required: false
    choices: ["pass", "add", "remove"]

  headers:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  headers_action:
    description:
      - Action when HTTP the header forwarded.
      - choice | add-to-request | Add the HTTP header to request.
      - choice | add-to-response | Add the HTTP header to response.
      - choice | remove-from-request | Remove the HTTP header from request.
      - choice | remove-from-response | Remove the HTTP header from response.
    required: false
    choices: ["add-to-request", "add-to-response", "remove-from-request", "remove-from-response"]

  headers_content:
    description:
      - HTTP header's content.
    required: false

  headers_name:
    description:
      - HTTP forwarded header name.
    required: false


'''

EXAMPLES = '''
  - name: DELETE Profile
    fmgr_secprof_proxy:
      name: "Ansible_Web_Proxy_Profile"
      mode: "delete"

  - name: CREATE Profile
    fmgr_secprof_proxy:
      name: "Ansible_Web_Proxy_Profile"
      mode: "set"
      header_client_ip: "pass"
      header_front_end_https: "add"
      header_via_request: "remove"
      header_via_response: "pass"
      header_x_authenticated_groups: "add"
      header_x_authenticated_user: "remove"
      strip_encoding: "enable"
      log_header_change: "enable"
      header_x_forwarded_for: "pass"
      headers_action: "add-to-request"
      headers_content: "test"
      headers_name: "test_header"
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
from ansible.module_utils.network.fortimanager.common import prepare_dict
from ansible.module_utils.network.fortimanager.common import scrub_dict


###############
# START METHODS
###############


def fmgr_web_proxy_profile_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/web-proxy/profile'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/web-proxy/profile/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])

    return response


#############
# END METHODS
#############


def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        strip_encoding=dict(required=False, type="str", choices=["disable", "enable"]),
        name=dict(required=False, type="str"),
        log_header_change=dict(required=False, type="str", choices=["disable", "enable"]),
        header_x_forwarded_for=dict(required=False, type="str", choices=["pass", "add", "remove"]),
        header_x_authenticated_user=dict(required=False, type="str", choices=["pass", "add", "remove"]),
        header_x_authenticated_groups=dict(required=False, type="str", choices=["pass", "add", "remove"]),
        header_via_response=dict(required=False, type="str", choices=["pass", "add", "remove"]),
        header_via_request=dict(required=False, type="str", choices=["pass", "add", "remove"]),
        header_front_end_https=dict(required=False, type="str", choices=["pass", "add", "remove"]),
        header_client_ip=dict(required=False, type="str", choices=["pass", "add", "remove"]),
        headers=dict(required=False, type="list"),
        headers_action=dict(required=False, type="str", choices=["add-to-request", "add-to-response",
                                                                 "remove-from-request", "remove-from-response"]),
        headers_content=dict(required=False, type="str"),
        headers_name=dict(required=False, type="str"),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "strip-encoding": module.params["strip_encoding"],
        "name": module.params["name"],
        "log-header-change": module.params["log_header_change"],
        "header-x-forwarded-for": module.params["header_x_forwarded_for"],
        "header-x-authenticated-user": module.params["header_x_authenticated_user"],
        "header-x-authenticated-groups": module.params["header_x_authenticated_groups"],
        "header-via-response": module.params["header_via_response"],
        "header-via-request": module.params["header_via_request"],
        "header-front-end-https": module.params["header_front_end_https"],
        "header-client-ip": module.params["header_client_ip"],
        "headers": {
            "action": module.params["headers_action"],
            "content": module.params["headers_content"],
            "name": module.params["headers_name"],
        }
    }

    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['headers']
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)
    module.paramgram = paramgram

    results = DEFAULT_RESULT_OBJ
    try:
        results = fmgr_web_proxy_profile_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_secprof_spam

Metadata

Name: fmgr_secprof_spam

Description: Manage spam filter security profiles within FortiManager via API

Author(s):

  • Luke Weighall (github: @lweighall)
  • Andrew Welsh (github: @Ghilli3)
  • Jim Huber (github: @p4r4n0y1ng)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Andrew Welsh

Module Github Link

Parameters
adom
  • Description: The ADOM the configuration should belong to.
  • Required: False
  • default: root
comment
  • Description: Comment.
  • Required: False
external
  • Description: Enable/disable external Email inspection.
  • Required: False
  • choices: [‘disable’, ‘enable’]
flow_based
  • Description: Enable/disable flow-based spam filtering.
  • Required: False
  • choices: [‘disable’, ‘enable’]
gmail
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

gmail_log
  • Description: Enable/disable logging.
  • Required: False
  • choices: [‘disable’, ‘enable’]
imap
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

imap_action
  • Description: Action for spam email.
  • Required: False
  • choices: [‘pass’, ‘tag’]
imap_log
  • Description: Enable/disable logging.
  • Required: False
  • choices: [‘disable’, ‘enable’]
imap_tag_msg
  • Description: Subject text or header added to spam email.
  • Required: False
imap_tag_type
  • Description: Tag subject or header for spam email.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘subject’, ‘header’, ‘spaminfo’]

mapi
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

mapi_action
  • Description: Action for spam email.
  • Required: False
  • choices: [‘pass’, ‘discard’]
mapi_log
  • Description: Enable/disable logging.
  • Required: False
  • choices: [‘disable’, ‘enable’]
mode
  • Description: Sets one of three modes for managing the object.

    Allows use of soft-adds instead of overwriting existing values

  • Required: False

  • default: add

  • choices: [‘add’, ‘set’, ‘delete’, ‘update’]

msn_hotmail
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

msn_hotmail_log
  • Description: Enable/disable logging.
  • Required: False
  • choices: [‘disable’, ‘enable’]
name
  • Description: Profile name.
  • Required: False
options
  • Description: None

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘bannedword’, ‘spamfsip’, ‘spamfssubmit’, ‘spamfschksum’, ‘spamfsurl’, ‘spamhelodns’, ‘spamraddrdns’, ‘spamrbl’, ‘spamhdrcheck’, ‘spamfsphish’, ‘spambwl’]

pop3
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

pop3_action
  • Description: Action for spam email.
  • Required: False
  • choices: [‘pass’, ‘tag’]
pop3_log
  • Description: Enable/disable logging.
  • Required: False
  • choices: [‘disable’, ‘enable’]
pop3_tag_msg
  • Description: Subject text or header added to spam email.
  • Required: False
pop3_tag_type
  • Description: Tag subject or header for spam email.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘subject’, ‘header’, ‘spaminfo’]

replacemsg_group
  • Description: Replacement message group.
  • Required: False
smtp
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

smtp_action
  • Description: Action for spam email.
  • Required: False
  • choices: [‘pass’, ‘tag’, ‘discard’]
smtp_hdrip
  • Description: Enable/disable SMTP email header IP checks for spamfsip, spamrbl and spambwl filters.
  • Required: False
  • choices: [‘disable’, ‘enable’]
smtp_local_override
  • Description: Enable/disable local filter to override SMTP remote check result.
  • Required: False
  • choices: [‘disable’, ‘enable’]
smtp_log
  • Description: Enable/disable logging.
  • Required: False
  • choices: [‘disable’, ‘enable’]
smtp_tag_msg
  • Description: Subject text or header added to spam email.
  • Required: False
smtp_tag_type
  • Description: Tag subject or header for spam email.

    FLAG Based Options. Specify multiple in list form.

  • Required: False

  • choices: [‘subject’, ‘header’, ‘spaminfo’]

spam_bwl_table
  • Description: Anti-spam black/white list table ID.
  • Required: False
spam_bword_table
  • Description: Anti-spam banned word table ID.
  • Required: False
spam_bword_threshold
  • Description: Spam banned word threshold.
  • Required: False
spam_filtering
  • Description: Enable/disable spam filtering.
  • Required: False
  • choices: [‘disable’, ‘enable’]
spam_iptrust_table
  • Description: Anti-spam IP trust table ID.
  • Required: False
spam_log
  • Description: Enable/disable spam logging for email filtering.
  • Required: False
  • choices: [‘disable’, ‘enable’]
spam_log_fortiguard_response
  • Description: Enable/disable logging FortiGuard spam response.
  • Required: False
  • choices: [‘disable’, ‘enable’]
spam_mheader_table
  • Description: Anti-spam MIME header table ID.
  • Required: False
spam_rbl_table
  • Description: Anti-spam DNSBL table ID.
  • Required: False
yahoo_mail
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

yahoo_mail_log
  • Description: Enable/disable logging.
  • Required: False
  • choices: [‘disable’, ‘enable’]
Functions
  • fmgr_spamfilter_profile_modify
def fmgr_spamfilter_profile_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/spamfilter/profile'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/spamfilter/profile/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])

    return response


#############
# END METHODS
#############
  • main
def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        spam_rbl_table=dict(required=False, type="str"),
        spam_mheader_table=dict(required=False, type="str"),
        spam_log_fortiguard_response=dict(required=False, type="str", choices=["disable", "enable"]),
        spam_log=dict(required=False, type="str", choices=["disable", "enable"]),
        spam_iptrust_table=dict(required=False, type="str"),
        spam_filtering=dict(required=False, type="str", choices=["disable", "enable"]),
        spam_bword_threshold=dict(required=False, type="int"),
        spam_bword_table=dict(required=False, type="str"),
        spam_bwl_table=dict(required=False, type="str"),
        replacemsg_group=dict(required=False, type="str"),
        options=dict(required=False, type="list", choices=["bannedword",
                                                           "spamfsip",
                                                           "spamfssubmit",
                                                           "spamfschksum",
                                                           "spamfsurl",
                                                           "spamhelodns",
                                                           "spamraddrdns",
                                                           "spamrbl",
                                                           "spamhdrcheck",
                                                           "spamfsphish",
                                                           "spambwl"]),
        name=dict(required=False, type="str"),
        flow_based=dict(required=False, type="str", choices=["disable", "enable"]),
        external=dict(required=False, type="str", choices=["disable", "enable"]),
        comment=dict(required=False, type="str"),
        gmail=dict(required=False, type="dict"),
        gmail_log=dict(required=False, type="str", choices=["disable", "enable"]),
        imap=dict(required=False, type="dict"),
        imap_action=dict(required=False, type="str", choices=["pass", "tag"]),
        imap_log=dict(required=False, type="str", choices=["disable", "enable"]),
        imap_tag_msg=dict(required=False, type="str"),
        imap_tag_type=dict(required=False, type="str", choices=["subject", "header", "spaminfo"]),
        mapi=dict(required=False, type="dict"),
        mapi_action=dict(required=False, type="str", choices=["pass", "discard"]),
        mapi_log=dict(required=False, type="str", choices=["disable", "enable"]),
        msn_hotmail=dict(required=False, type="dict"),
        msn_hotmail_log=dict(required=False, type="str", choices=["disable", "enable"]),
        pop3=dict(required=False, type="dict"),
        pop3_action=dict(required=False, type="str", choices=["pass", "tag"]),
        pop3_log=dict(required=False, type="str", choices=["disable", "enable"]),
        pop3_tag_msg=dict(required=False, type="str"),
        pop3_tag_type=dict(required=False, type="str", choices=["subject", "header", "spaminfo"]),
        smtp=dict(required=False, type="dict"),
        smtp_action=dict(required=False, type="str", choices=["pass", "tag", "discard"]),
        smtp_hdrip=dict(required=False, type="str", choices=["disable", "enable"]),
        smtp_local_override=dict(required=False, type="str", choices=["disable", "enable"]),
        smtp_log=dict(required=False, type="str", choices=["disable", "enable"]),
        smtp_tag_msg=dict(required=False, type="str"),
        smtp_tag_type=dict(required=False, type="str", choices=["subject", "header", "spaminfo"]),
        yahoo_mail=dict(required=False, type="dict"),
        yahoo_mail_log=dict(required=False, type="str", choices=["disable", "enable"]),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "spam-rbl-table": module.params["spam_rbl_table"],
        "spam-mheader-table": module.params["spam_mheader_table"],
        "spam-log-fortiguard-response": module.params["spam_log_fortiguard_response"],
        "spam-log": module.params["spam_log"],
        "spam-iptrust-table": module.params["spam_iptrust_table"],
        "spam-filtering": module.params["spam_filtering"],
        "spam-bword-threshold": module.params["spam_bword_threshold"],
        "spam-bword-table": module.params["spam_bword_table"],
        "spam-bwl-table": module.params["spam_bwl_table"],
        "replacemsg-group": module.params["replacemsg_group"],
        "options": module.params["options"],
        "name": module.params["name"],
        "flow-based": module.params["flow_based"],
        "external": module.params["external"],
        "comment": module.params["comment"],
        "gmail": {
            "log": module.params["gmail_log"],
        },
        "imap": {
            "action": module.params["imap_action"],
            "log": module.params["imap_log"],
            "tag-msg": module.params["imap_tag_msg"],
            "tag-type": module.params["imap_tag_type"],
        },
        "mapi": {
            "action": module.params["mapi_action"],
            "log": module.params["mapi_log"],
        },
        "msn-hotmail": {
            "log": module.params["msn_hotmail_log"],
        },
        "pop3": {
            "action": module.params["pop3_action"],
            "log": module.params["pop3_log"],
            "tag-msg": module.params["pop3_tag_msg"],
            "tag-type": module.params["pop3_tag_type"],
        },
        "smtp": {
            "action": module.params["smtp_action"],
            "hdrip": module.params["smtp_hdrip"],
            "local-override": module.params["smtp_local_override"],
            "log": module.params["smtp_log"],
            "tag-msg": module.params["smtp_tag_msg"],
            "tag-type": module.params["smtp_tag_type"],
        },
        "yahoo-mail": {
            "log": module.params["yahoo_mail_log"],
        }
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['gmail', 'imap', 'mapi', 'msn-hotmail', 'pop3', 'smtp', 'yahoo-mail']
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)

    results = DEFAULT_RESULT_OBJ
    try:

        results = fmgr_spamfilter_profile_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {'status': ['preview'],
                    'supported_by': 'community',
                    'metadata_version': '1.1'}

DOCUMENTATION = '''
---
module: fmgr_secprof_spam
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author:
    - Luke Weighall (@lweighall)
    - Andrew Welsh (@Ghilli3)
    - Jim Huber (@p4r4n0y1ng)
short_description: spam filter profile for FMG
description:
  -  Manage spam filter security profiles within FortiManager via API

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: false
    default: root

  mode:
    description:
      - Sets one of three modes for managing the object.
      - Allows use of soft-adds instead of overwriting existing values
    choices: ['add', 'set', 'delete', 'update']
    required: false
    default: add

  spam_rbl_table:
    description:
      - Anti-spam DNSBL table ID.
    required: false

  spam_mheader_table:
    description:
      - Anti-spam MIME header table ID.
    required: false

  spam_log_fortiguard_response:
    description:
      - Enable/disable logging FortiGuard spam response.
    required: false
    choices:
      - disable
      - enable

  spam_log:
    description:
      - Enable/disable spam logging for email filtering.
    required: false
    choices:
      - disable
      - enable

  spam_iptrust_table:
    description:
      - Anti-spam IP trust table ID.
    required: false

  spam_filtering:
    description:
      - Enable/disable spam filtering.
    required: false
    choices:
      - disable
      - enable

  spam_bword_threshold:
    description:
      - Spam banned word threshold.
    required: false

  spam_bword_table:
    description:
      - Anti-spam banned word table ID.
    required: false

  spam_bwl_table:
    description:
      - Anti-spam black/white list table ID.
    required: false

  replacemsg_group:
    description:
      - Replacement message group.
    required: false

  options:
    description:
      - None
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - bannedword
      - spamfsip
      - spamfssubmit
      - spamfschksum
      - spamfsurl
      - spamhelodns
      - spamraddrdns
      - spamrbl
      - spamhdrcheck
      - spamfsphish
      - spambwl

  name:
    description:
      - Profile name.
    required: false

  flow_based:
    description:
      - Enable/disable flow-based spam filtering.
    required: false
    choices:
      - disable
      - enable

  external:
    description:
      - Enable/disable external Email inspection.
    required: false
    choices:
      - disable
      - enable

  comment:
    description:
      - Comment.
    required: false

  gmail:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  gmail_log:
    description:
      - Enable/disable logging.
    required: false
    choices:
      - disable
      - enable

  imap:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  imap_action:
    description:
      - Action for spam email.
    required: false
    choices:
      - pass
      - tag

  imap_log:
    description:
      - Enable/disable logging.
    required: false
    choices:
      - disable
      - enable

  imap_tag_msg:
    description:
      - Subject text or header added to spam email.
    required: false

  imap_tag_type:
    description:
      - Tag subject or header for spam email.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - subject
      - header
      - spaminfo

  mapi:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  mapi_action:
    description:
      - Action for spam email.
    required: false
    choices:
      - pass
      - discard

  mapi_log:
    description:
      - Enable/disable logging.
    required: false
    choices:
      - disable
      - enable

  msn_hotmail:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  msn_hotmail_log:
    description:
      - Enable/disable logging.
    required: false
    choices:
      - disable
      - enable

  pop3:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  pop3_action:
    description:
      - Action for spam email.
    required: false
    choices:
      - pass
      - tag

  pop3_log:
    description:
      - Enable/disable logging.
    required: false
    choices:
      - disable
      - enable

  pop3_tag_msg:
    description:
      - Subject text or header added to spam email.
    required: false

  pop3_tag_type:
    description:
      - Tag subject or header for spam email.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - subject
      - header
      - spaminfo

  smtp:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  smtp_action:
    description:
      - Action for spam email.
    required: false
    choices:
      - pass
      - tag
      - discard

  smtp_hdrip:
    description:
      - Enable/disable SMTP email header IP checks for spamfsip, spamrbl and spambwl filters.
    required: false
    choices:
      - disable
      - enable

  smtp_local_override:
    description:
      - Enable/disable local filter to override SMTP remote check result.
    required: false
    choices:
      - disable
      - enable

  smtp_log:
    description:
      - Enable/disable logging.
    required: false
    choices:
      - disable
      - enable

  smtp_tag_msg:
    description:
      - Subject text or header added to spam email.
    required: false

  smtp_tag_type:
    description:
      - Tag subject or header for spam email.
      - FLAG Based Options. Specify multiple in list form.
    required: false
    choices:
      - subject
      - header
      - spaminfo

  yahoo_mail:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  yahoo_mail_log:
    description:
      - Enable/disable logging.
    required: false
    choices:
      - disable
      - enable
'''

EXAMPLES = '''
  - name: DELETE Profile
    fmgr_secprof_spam:
      name: "Ansible_Spam_Filter_Profile"
      mode: "delete"

  - name: Create FMGR_SPAMFILTER_PROFILE
    fmgr_secprof_spam:
      host: "{{ inventory_hostname }}"
      username: "{{ username }}"
      password: "{{ password }}"
      mode: "set"
      adom: "root"
      spam_log_fortiguard_response: "enable"
      spam_iptrust_table:
      spam_filtering: "enable"
      spam_bword_threshold: 10
      options: ["bannedword", "spamfsip", "spamfsurl", "spamrbl", "spamfsphish", "spambwl"]
      name: "Ansible_Spam_Filter_Profile"
      flow_based: "enable"
      external: "enable"
      comment: "Created by Ansible"
      gmail_log: "enable"
      spam_log: "enable"
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
from ansible.module_utils.network.fortimanager.common import prepare_dict
from ansible.module_utils.network.fortimanager.common import scrub_dict

###############
# START METHODS
###############


def fmgr_spamfilter_profile_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/spamfilter/profile'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/spamfilter/profile/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])

    return response


#############
# END METHODS
#############


def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        spam_rbl_table=dict(required=False, type="str"),
        spam_mheader_table=dict(required=False, type="str"),
        spam_log_fortiguard_response=dict(required=False, type="str", choices=["disable", "enable"]),
        spam_log=dict(required=False, type="str", choices=["disable", "enable"]),
        spam_iptrust_table=dict(required=False, type="str"),
        spam_filtering=dict(required=False, type="str", choices=["disable", "enable"]),
        spam_bword_threshold=dict(required=False, type="int"),
        spam_bword_table=dict(required=False, type="str"),
        spam_bwl_table=dict(required=False, type="str"),
        replacemsg_group=dict(required=False, type="str"),
        options=dict(required=False, type="list", choices=["bannedword",
                                                           "spamfsip",
                                                           "spamfssubmit",
                                                           "spamfschksum",
                                                           "spamfsurl",
                                                           "spamhelodns",
                                                           "spamraddrdns",
                                                           "spamrbl",
                                                           "spamhdrcheck",
                                                           "spamfsphish",
                                                           "spambwl"]),
        name=dict(required=False, type="str"),
        flow_based=dict(required=False, type="str", choices=["disable", "enable"]),
        external=dict(required=False, type="str", choices=["disable", "enable"]),
        comment=dict(required=False, type="str"),
        gmail=dict(required=False, type="dict"),
        gmail_log=dict(required=False, type="str", choices=["disable", "enable"]),
        imap=dict(required=False, type="dict"),
        imap_action=dict(required=False, type="str", choices=["pass", "tag"]),
        imap_log=dict(required=False, type="str", choices=["disable", "enable"]),
        imap_tag_msg=dict(required=False, type="str"),
        imap_tag_type=dict(required=False, type="str", choices=["subject", "header", "spaminfo"]),
        mapi=dict(required=False, type="dict"),
        mapi_action=dict(required=False, type="str", choices=["pass", "discard"]),
        mapi_log=dict(required=False, type="str", choices=["disable", "enable"]),
        msn_hotmail=dict(required=False, type="dict"),
        msn_hotmail_log=dict(required=False, type="str", choices=["disable", "enable"]),
        pop3=dict(required=False, type="dict"),
        pop3_action=dict(required=False, type="str", choices=["pass", "tag"]),
        pop3_log=dict(required=False, type="str", choices=["disable", "enable"]),
        pop3_tag_msg=dict(required=False, type="str"),
        pop3_tag_type=dict(required=False, type="str", choices=["subject", "header", "spaminfo"]),
        smtp=dict(required=False, type="dict"),
        smtp_action=dict(required=False, type="str", choices=["pass", "tag", "discard"]),
        smtp_hdrip=dict(required=False, type="str", choices=["disable", "enable"]),
        smtp_local_override=dict(required=False, type="str", choices=["disable", "enable"]),
        smtp_log=dict(required=False, type="str", choices=["disable", "enable"]),
        smtp_tag_msg=dict(required=False, type="str"),
        smtp_tag_type=dict(required=False, type="str", choices=["subject", "header", "spaminfo"]),
        yahoo_mail=dict(required=False, type="dict"),
        yahoo_mail_log=dict(required=False, type="str", choices=["disable", "enable"]),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "spam-rbl-table": module.params["spam_rbl_table"],
        "spam-mheader-table": module.params["spam_mheader_table"],
        "spam-log-fortiguard-response": module.params["spam_log_fortiguard_response"],
        "spam-log": module.params["spam_log"],
        "spam-iptrust-table": module.params["spam_iptrust_table"],
        "spam-filtering": module.params["spam_filtering"],
        "spam-bword-threshold": module.params["spam_bword_threshold"],
        "spam-bword-table": module.params["spam_bword_table"],
        "spam-bwl-table": module.params["spam_bwl_table"],
        "replacemsg-group": module.params["replacemsg_group"],
        "options": module.params["options"],
        "name": module.params["name"],
        "flow-based": module.params["flow_based"],
        "external": module.params["external"],
        "comment": module.params["comment"],
        "gmail": {
            "log": module.params["gmail_log"],
        },
        "imap": {
            "action": module.params["imap_action"],
            "log": module.params["imap_log"],
            "tag-msg": module.params["imap_tag_msg"],
            "tag-type": module.params["imap_tag_type"],
        },
        "mapi": {
            "action": module.params["mapi_action"],
            "log": module.params["mapi_log"],
        },
        "msn-hotmail": {
            "log": module.params["msn_hotmail_log"],
        },
        "pop3": {
            "action": module.params["pop3_action"],
            "log": module.params["pop3_log"],
            "tag-msg": module.params["pop3_tag_msg"],
            "tag-type": module.params["pop3_tag_type"],
        },
        "smtp": {
            "action": module.params["smtp_action"],
            "hdrip": module.params["smtp_hdrip"],
            "local-override": module.params["smtp_local_override"],
            "log": module.params["smtp_log"],
            "tag-msg": module.params["smtp_tag_msg"],
            "tag-type": module.params["smtp_tag_type"],
        },
        "yahoo-mail": {
            "log": module.params["yahoo_mail_log"],
        }
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['gmail', 'imap', 'mapi', 'msn-hotmail', 'pop3', 'smtp', 'yahoo-mail']
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)

    results = DEFAULT_RESULT_OBJ
    try:

        results = fmgr_spamfilter_profile_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_secprof_ssl_ssh

Metadata

Name: fmgr_secprof_ssl_ssh

Description: Manage SSL and SSH security profiles in FortiManager via the FMG API

Author(s):

  • Luke Weighall (github: @lweighall)
  • Andrew Welsh (github: @Ghilli3)
  • Jim Huber (github: @p4r4n0y1ng)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Andrew Welsh

Module Github Link

Parameters
adom
  • Description: The ADOM the configuration should belong to.
  • Required: False
  • default: root
caname
  • Description: CA certificate used by SSL Inspection.
  • Required: False
comment
  • Description: Optional comments.
  • Required: False
ftps
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

ftps_allow_invalid_server_cert
  • Description: When enabled, allows SSL sessions whose server certificate validation failed.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

ftps_client_cert_request
  • Description: Action based on client certificate request failure.

    choice | bypass | Bypass.

    choice | inspect | Inspect.

    choice | block | Block.

  • Required: False

  • choices: [‘bypass’, ‘inspect’, ‘block’]

ftps_ports
  • Description: Ports to use for scanning (1 - 65535, default = 443).
  • Required: False
ftps_status
  • Description: Configure protocol inspection status.

    choice | disable | Disable.

    choice | deep-inspection | Full SSL inspection.

  • Required: False

  • choices: [‘disable’, ‘deep-inspection’]

ftps_unsupported_ssl
  • Description: Action based on the SSL encryption used being unsupported.

    choice | bypass | Bypass.

    choice | inspect | Inspect.

    choice | block | Block.

  • Required: False

  • choices: [‘bypass’, ‘inspect’, ‘block’]

ftps_untrusted_cert
  • Description: Allow, ignore, or block the untrusted SSL session server certificate.

    choice | allow | Allow the untrusted server certificate.

    choice | block | Block the connection when an untrusted server certificate is detected.

    choice | ignore | Always take the server certificate as trusted.

  • Required: False

  • choices: [‘allow’, ‘block’, ‘ignore’]

https
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

https_allow_invalid_server_cert
  • Description: When enabled, allows SSL sessions whose server certificate validation failed.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

https_client_cert_request
  • Description: Action based on client certificate request failure.

    choice | bypass | Bypass.

    choice | inspect | Inspect.

    choice | block | Block.

  • Required: False

  • choices: [‘bypass’, ‘inspect’, ‘block’]

https_ports
  • Description: Ports to use for scanning (1 - 65535, default = 443).
  • Required: False
https_status
  • Description: Configure protocol inspection status.

    choice | disable | Disable.

    choice | certificate-inspection | Inspect SSL handshake only.

    choice | deep-inspection | Full SSL inspection.

  • Required: False

  • choices: [‘disable’, ‘certificate-inspection’, ‘deep-inspection’]

https_unsupported_ssl
  • Description: Action based on the SSL encryption used being unsupported.

    choice | bypass | Bypass.

    choice | inspect | Inspect.

    choice | block | Block.

  • Required: False

  • choices: [‘bypass’, ‘inspect’, ‘block’]

https_untrusted_cert
  • Description: Allow, ignore, or block the untrusted SSL session server certificate.

    choice | allow | Allow the untrusted server certificate.

    choice | block | Block the connection when an untrusted server certificate is detected.

    choice | ignore | Always take the server certificate as trusted.

  • Required: False

  • choices: [‘allow’, ‘block’, ‘ignore’]

imaps
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

imaps_allow_invalid_server_cert
  • Description: When enabled, allows SSL sessions whose server certificate validation failed.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

imaps_client_cert_request
  • Description: Action based on client certificate request failure.

    choice | bypass | Bypass.

    choice | inspect | Inspect.

    choice | block | Block.

  • Required: False

  • choices: [‘bypass’, ‘inspect’, ‘block’]

imaps_ports
  • Description: Ports to use for scanning (1 - 65535, default = 443).
  • Required: False
imaps_status
  • Description: Configure protocol inspection status.

    choice | disable | Disable.

    choice | deep-inspection | Full SSL inspection.

  • Required: False

  • choices: [‘disable’, ‘deep-inspection’]

imaps_unsupported_ssl
  • Description: Action based on the SSL encryption used being unsupported.

    choice | bypass | Bypass.

    choice | inspect | Inspect.

    choice | block | Block.

  • Required: False

  • choices: [‘bypass’, ‘inspect’, ‘block’]

imaps_untrusted_cert
  • Description: Allow, ignore, or block the untrusted SSL session server certificate.

    choice | allow | Allow the untrusted server certificate.

    choice | block | Block the connection when an untrusted server certificate is detected.

    choice | ignore | Always take the server certificate as trusted.

  • Required: False

  • choices: [‘allow’, ‘block’, ‘ignore’]

mapi_over_https
  • Description: Enable/disable inspection of MAPI over HTTPS.

    choice | disable | Disable inspection of MAPI over HTTPS.

    choice | enable | Enable inspection of MAPI over HTTPS.

  • Required: False

  • choices: [‘disable’, ‘enable’]

mode
  • Description: Sets one of three modes for managing the object.

    Allows use of soft-adds instead of overwriting existing values

  • Required: False

  • default: add

  • choices: [‘add’, ‘set’, ‘delete’, ‘update’]

name
  • Description: Name.
  • Required: False
pop3s
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

pop3s_allow_invalid_server_cert
  • Description: When enabled, allows SSL sessions whose server certificate validation failed.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

pop3s_client_cert_request
  • Description: Action based on client certificate request failure.

    choice | bypass | Bypass.

    choice | inspect | Inspect.

    choice | block | Block.

  • Required: False

  • choices: [‘bypass’, ‘inspect’, ‘block’]

pop3s_ports
  • Description: Ports to use for scanning (1 - 65535, default = 443).
  • Required: False
pop3s_status
  • Description: Configure protocol inspection status.

    choice | disable | Disable.

    choice | deep-inspection | Full SSL inspection.

  • Required: False

  • choices: [‘disable’, ‘deep-inspection’]

pop3s_unsupported_ssl
  • Description: Action based on the SSL encryption used being unsupported.

    choice | bypass | Bypass.

    choice | inspect | Inspect.

    choice | block | Block.

  • Required: False

  • choices: [‘bypass’, ‘inspect’, ‘block’]

pop3s_untrusted_cert
  • Description: Allow, ignore, or block the untrusted SSL session server certificate.

    choice | allow | Allow the untrusted server certificate.

    choice | block | Block the connection when an untrusted server certificate is detected.

    choice | ignore | Always take the server certificate as trusted.

  • Required: False

  • choices: [‘allow’, ‘block’, ‘ignore’]

rpc_over_https
  • Description: Enable/disable inspection of RPC over HTTPS.

    choice | disable | Disable inspection of RPC over HTTPS.

    choice | enable | Enable inspection of RPC over HTTPS.

  • Required: False

  • choices: [‘disable’, ‘enable’]

server_cert
  • Description: Certificate used by SSL Inspection to replace server certificate.
  • Required: False
server_cert_mode
  • Description: Re-sign or replace the server’s certificate.

    choice | re-sign | Multiple clients connecting to multiple servers.

    choice | replace | Protect an SSL server.

  • Required: False

  • choices: [‘re-sign’, ‘replace’]

smtps
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

smtps_allow_invalid_server_cert
  • Description: When enabled, allows SSL sessions whose server certificate validation failed.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

smtps_client_cert_request
  • Description: Action based on client certificate request failure.

    choice | bypass | Bypass.

    choice | inspect | Inspect.

    choice | block | Block.

  • Required: False

  • choices: [‘bypass’, ‘inspect’, ‘block’]

smtps_ports
  • Description: Ports to use for scanning (1 - 65535, default = 443).
  • Required: False
smtps_status
  • Description: Configure protocol inspection status.

    choice | disable | Disable.

    choice | deep-inspection | Full SSL inspection.

  • Required: False

  • choices: [‘disable’, ‘deep-inspection’]

smtps_unsupported_ssl
  • Description: Action based on the SSL encryption used being unsupported.

    choice | bypass | Bypass.

    choice | inspect | Inspect.

    choice | block | Block.

  • Required: False

  • choices: [‘bypass’, ‘inspect’, ‘block’]

smtps_untrusted_cert
  • Description: Allow, ignore, or block the untrusted SSL session server certificate.

    choice | allow | Allow the untrusted server certificate.

    choice | block | Block the connection when an untrusted server certificate is detected.

    choice | ignore | Always take the server certificate as trusted.

  • Required: False

  • choices: [‘allow’, ‘block’, ‘ignore’]

ssh
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

ssh_inspect_all
  • Description: Level of SSL inspection.

    choice | disable | Disable.

    choice | deep-inspection | Full SSL inspection.

  • Required: False

  • choices: [‘disable’, ‘deep-inspection’]

ssh_ports
  • Description: Ports to use for scanning (1 - 65535, default = 443).
  • Required: False
ssh_ssh_algorithm
  • Description: Relative strength of encryption algorithms accepted during negotiation.

    choice | compatible | Allow a broader set of encryption algorithms for best compatibility.

    choice | high-encryption | Allow only AES-CTR, AES-GCM ciphers and high encryption algorithms.

  • Required: False

  • choices: [‘compatible’, ‘high-encryption’]

ssh_ssh_policy_check
  • Description: Enable/disable SSH policy check.

    choice | disable | Disable SSH policy check.

    choice | enable | Enable SSH policy check.

  • Required: False

  • choices: [‘disable’, ‘enable’]

ssh_ssh_tun_policy_check
  • Description: Enable/disable SSH tunnel policy check.

    choice | disable | Disable SSH tunnel policy check.

    choice | enable | Enable SSH tunnel policy check.

  • Required: False

  • choices: [‘disable’, ‘enable’]

ssh_status
  • Description: Configure protocol inspection status.

    choice | disable | Disable.

    choice | deep-inspection | Full SSL inspection.

  • Required: False

  • choices: [‘disable’, ‘deep-inspection’]

ssh_unsupported_version
  • Description: Action based on SSH version being unsupported.

    choice | block | Block.

    choice | bypass | Bypass.

  • Required: False

  • choices: [‘block’, ‘bypass’]

ssl
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

ssl_allow_invalid_server_cert
  • Description: When enabled, allows SSL sessions whose server certificate validation failed.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

ssl_anomalies_log
  • Description: Enable/disable logging SSL anomalies.

    choice | disable | Disable logging SSL anomalies.

    choice | enable | Enable logging SSL anomalies.

  • Required: False

  • choices: [‘disable’, ‘enable’]

ssl_client_cert_request
  • Description: Action based on client certificate request failure.

    choice | bypass | Bypass.

    choice | inspect | Inspect.

    choice | block | Block.

  • Required: False

  • choices: [‘bypass’, ‘inspect’, ‘block’]

ssl_exempt
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

ssl_exempt_address
  • Description: IPv4 address object.
  • Required: False
ssl_exempt_address6
  • Description: IPv6 address object.
  • Required: False
ssl_exempt_fortiguard_category
  • Description: FortiGuard category ID.
  • Required: False
ssl_exempt_regex
  • Description: Exempt servers by regular expression.
  • Required: False
ssl_exempt_type
  • Description: Type of address object (IPv4 or IPv6) or FortiGuard category.

    choice | fortiguard-category | FortiGuard category.

    choice | address | Firewall IPv4 address.

    choice | address6 | Firewall IPv6 address.

    choice | wildcard-fqdn | Fully Qualified Domain Name with wildcard characters.

    choice | regex | Regular expression FQDN.

  • Required: False

  • choices: [‘fortiguard-category’, ‘address’, ‘address6’, ‘wildcard-fqdn’, ‘regex’]

ssl_exempt_wildcard_fqdn
  • Description: Exempt servers by wildcard FQDN.
  • Required: False
ssl_exemptions_log
  • Description: Enable/disable logging SSL exemptions.

    choice | disable | Disable logging SSL exemptions.

    choice | enable | Enable logging SSL exemptions.

  • Required: False

  • choices: [‘disable’, ‘enable’]

ssl_inspect_all
  • Description: Level of SSL inspection.

    choice | disable | Disable.

    choice | certificate-inspection | Inspect SSL handshake only.

    choice | deep-inspection | Full SSL inspection.

  • Required: False

  • choices: [‘disable’, ‘certificate-inspection’, ‘deep-inspection’]

ssl_server
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

ssl_server_ftps_client_cert_request
  • Description: Action based on client certificate request failure during the FTPS handshake.

    choice | bypass | Bypass.

    choice | inspect | Inspect.

    choice | block | Block.

  • Required: False

  • choices: [‘bypass’, ‘inspect’, ‘block’]

ssl_server_https_client_cert_request
  • Description: Action based on client certificate request failure during the HTTPS handshake.

    choice | bypass | Bypass.

    choice | inspect | Inspect.

    choice | block | Block.

  • Required: False

  • choices: [‘bypass’, ‘inspect’, ‘block’]

ssl_server_imaps_client_cert_request
  • Description: Action based on client certificate request failure during the IMAPS handshake.

    choice | bypass | Bypass.

    choice | inspect | Inspect.

    choice | block | Block.

  • Required: False

  • choices: [‘bypass’, ‘inspect’, ‘block’]

ssl_server_ip
  • Description: IPv4 address of the SSL server.
  • Required: False
ssl_server_pop3s_client_cert_request
  • Description: Action based on client certificate request failure during the POP3S handshake.

    choice | bypass | Bypass.

    choice | inspect | Inspect.

    choice | block | Block.

  • Required: False

  • choices: [‘bypass’, ‘inspect’, ‘block’]

ssl_server_smtps_client_cert_request
  • Description: Action based on client certificate request failure during the SMTPS handshake.

    choice | bypass | Bypass.

    choice | inspect | Inspect.

    choice | block | Block.

  • Required: False

  • choices: [‘bypass’, ‘inspect’, ‘block’]

ssl_server_ssl_other_client_cert_request
  • Description: Action based on client certificate request failure during an SSL protocol handshake.

    choice | bypass | Bypass.

    choice | inspect | Inspect.

    choice | block | Block.

  • Required: False

  • choices: [‘bypass’, ‘inspect’, ‘block’]

ssl_unsupported_ssl
  • Description: Action based on the SSL encryption used being unsupported.

    choice | bypass | Bypass.

    choice | inspect | Inspect.

    choice | block | Block.

  • Required: False

  • choices: [‘bypass’, ‘inspect’, ‘block’]

ssl_untrusted_cert
  • Description: Allow, ignore, or block the untrusted SSL session server certificate.

    choice | allow | Allow the untrusted server certificate.

    choice | block | Block the connection when an untrusted server certificate is detected.

    choice | ignore | Always take the server certificate as trusted.

  • Required: False

  • choices: [‘allow’, ‘block’, ‘ignore’]

untrusted_caname
  • Description: Untrusted CA certificate used by SSL Inspection.
  • Required: False
use_ssl_server
  • Description: Enable/disable the use of SSL server table for SSL offloading.

    choice | disable | Don’t use SSL server configuration.

    choice | enable | Use SSL server configuration.

  • Required: False

  • choices: [‘disable’, ‘enable’]

whitelist
  • Description: Enable/disable exempting servers by FortiGuard whitelist.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

Functions
  • fmgr_firewall_ssl_ssh_profile_modify
def fmgr_firewall_ssl_ssh_profile_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/firewall/ssl-ssh-profile'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/firewall/ssl-ssh-profile/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])

    return response


#############
# END METHODS
#############
  • main
def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        whitelist=dict(required=False, type="str", choices=["disable", "enable"]),
        use_ssl_server=dict(required=False, type="str", choices=["disable", "enable"]),
        untrusted_caname=dict(required=False, type="str"),
        ssl_exemptions_log=dict(required=False, type="str", choices=["disable", "enable"]),
        ssl_anomalies_log=dict(required=False, type="str", choices=["disable", "enable"]),
        server_cert_mode=dict(required=False, type="str", choices=["re-sign", "replace"]),
        server_cert=dict(required=False, type="str"),
        rpc_over_https=dict(required=False, type="str", choices=["disable", "enable"]),
        name=dict(required=False, type="str"),
        mapi_over_https=dict(required=False, type="str", choices=["disable", "enable"]),
        comment=dict(required=False, type="str"),
        caname=dict(required=False, type="str"),
        ftps=dict(required=False, type="list"),
        ftps_allow_invalid_server_cert=dict(required=False, type="str", choices=["disable", "enable"]),
        ftps_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        ftps_ports=dict(required=False, type="str"),
        ftps_status=dict(required=False, type="str", choices=["disable", "deep-inspection"]),
        ftps_unsupported_ssl=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        ftps_untrusted_cert=dict(required=False, type="str", choices=["allow", "block", "ignore"]),
        https=dict(required=False, type="list"),
        https_allow_invalid_server_cert=dict(required=False, type="str", choices=["disable", "enable"]),
        https_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        https_ports=dict(required=False, type="str"),
        https_status=dict(required=False, type="str", choices=["disable", "certificate-inspection", "deep-inspection"]),
        https_unsupported_ssl=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        https_untrusted_cert=dict(required=False, type="str", choices=["allow", "block", "ignore"]),
        imaps=dict(required=False, type="list"),
        imaps_allow_invalid_server_cert=dict(required=False, type="str", choices=["disable", "enable"]),
        imaps_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        imaps_ports=dict(required=False, type="str"),
        imaps_status=dict(required=False, type="str", choices=["disable", "deep-inspection"]),
        imaps_unsupported_ssl=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        imaps_untrusted_cert=dict(required=False, type="str", choices=["allow", "block", "ignore"]),
        pop3s=dict(required=False, type="list"),
        pop3s_allow_invalid_server_cert=dict(required=False, type="str", choices=["disable", "enable"]),
        pop3s_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        pop3s_ports=dict(required=False, type="str"),
        pop3s_status=dict(required=False, type="str", choices=["disable", "deep-inspection"]),
        pop3s_unsupported_ssl=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        pop3s_untrusted_cert=dict(required=False, type="str", choices=["allow", "block", "ignore"]),
        smtps=dict(required=False, type="list"),
        smtps_allow_invalid_server_cert=dict(required=False, type="str", choices=["disable", "enable"]),
        smtps_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        smtps_ports=dict(required=False, type="str"),
        smtps_status=dict(required=False, type="str", choices=["disable", "deep-inspection"]),
        smtps_unsupported_ssl=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        smtps_untrusted_cert=dict(required=False, type="str", choices=["allow", "block", "ignore"]),
        ssh=dict(required=False, type="list"),
        ssh_inspect_all=dict(required=False, type="str", choices=["disable", "deep-inspection"]),
        ssh_ports=dict(required=False, type="str"),
        ssh_ssh_algorithm=dict(required=False, type="str", choices=["compatible", "high-encryption"]),
        ssh_ssh_policy_check=dict(required=False, type="str", choices=["disable", "enable"]),
        ssh_ssh_tun_policy_check=dict(required=False, type="str", choices=["disable", "enable"]),
        ssh_status=dict(required=False, type="str", choices=["disable", "deep-inspection"]),
        ssh_unsupported_version=dict(required=False, type="str", choices=["block", "bypass"]),
        ssl=dict(required=False, type="list"),
        ssl_allow_invalid_server_cert=dict(required=False, type="str", choices=["disable", "enable"]),
        ssl_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        ssl_inspect_all=dict(required=False, type="str", choices=["disable", "certificate-inspection",
                                                                  "deep-inspection"]),
        ssl_unsupported_ssl=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        ssl_untrusted_cert=dict(required=False, type="str", choices=["allow", "block", "ignore"]),
        ssl_exempt=dict(required=False, type="list"),
        ssl_exempt_address=dict(required=False, type="str"),
        ssl_exempt_address6=dict(required=False, type="str"),
        ssl_exempt_fortiguard_category=dict(required=False, type="str"),
        ssl_exempt_regex=dict(required=False, type="str"),
        ssl_exempt_type=dict(required=False, type="str", choices=["fortiguard-category", "address", "address6",
                                                                  "wildcard-fqdn", "regex"]),
        ssl_exempt_wildcard_fqdn=dict(required=False, type="str"),
        ssl_server=dict(required=False, type="list"),
        ssl_server_ftps_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        ssl_server_https_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        ssl_server_imaps_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        ssl_server_ip=dict(required=False, type="str"),
        ssl_server_pop3s_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        ssl_server_smtps_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        ssl_server_ssl_other_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect",
                                                                                           "block"]),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "whitelist": module.params["whitelist"],
        "use-ssl-server": module.params["use_ssl_server"],
        "untrusted-caname": module.params["untrusted_caname"],
        "ssl-exemptions-log": module.params["ssl_exemptions_log"],
        "ssl-anomalies-log": module.params["ssl_anomalies_log"],
        "server-cert-mode": module.params["server_cert_mode"],
        "server-cert": module.params["server_cert"],
        "rpc-over-https": module.params["rpc_over_https"],
        "name": module.params["name"],
        "mapi-over-https": module.params["mapi_over_https"],
        "comment": module.params["comment"],
        "caname": module.params["caname"],
        "ftps": {
            "allow-invalid-server-cert": module.params["ftps_allow_invalid_server_cert"],
            "client-cert-request": module.params["ftps_client_cert_request"],
            "ports": module.params["ftps_ports"],
            "status": module.params["ftps_status"],
            "unsupported-ssl": module.params["ftps_unsupported_ssl"],
            "untrusted-cert": module.params["ftps_untrusted_cert"],
        },
        "https": {
            "allow-invalid-server-cert": module.params["https_allow_invalid_server_cert"],
            "client-cert-request": module.params["https_client_cert_request"],
            "ports": module.params["https_ports"],
            "status": module.params["https_status"],
            "unsupported-ssl": module.params["https_unsupported_ssl"],
            "untrusted-cert": module.params["https_untrusted_cert"],
        },
        "imaps": {
            "allow-invalid-server-cert": module.params["imaps_allow_invalid_server_cert"],
            "client-cert-request": module.params["imaps_client_cert_request"],
            "ports": module.params["imaps_ports"],
            "status": module.params["imaps_status"],
            "unsupported-ssl": module.params["imaps_unsupported_ssl"],
            "untrusted-cert": module.params["imaps_untrusted_cert"],
        },
        "pop3s": {
            "allow-invalid-server-cert": module.params["pop3s_allow_invalid_server_cert"],
            "client-cert-request": module.params["pop3s_client_cert_request"],
            "ports": module.params["pop3s_ports"],
            "status": module.params["pop3s_status"],
            "unsupported-ssl": module.params["pop3s_unsupported_ssl"],
            "untrusted-cert": module.params["pop3s_untrusted_cert"],
        },
        "smtps": {
            "allow-invalid-server-cert": module.params["smtps_allow_invalid_server_cert"],
            "client-cert-request": module.params["smtps_client_cert_request"],
            "ports": module.params["smtps_ports"],
            "status": module.params["smtps_status"],
            "unsupported-ssl": module.params["smtps_unsupported_ssl"],
            "untrusted-cert": module.params["smtps_untrusted_cert"],
        },
        "ssh": {
            "inspect-all": module.params["ssh_inspect_all"],
            "ports": module.params["ssh_ports"],
            "ssh-algorithm": module.params["ssh_ssh_algorithm"],
            "ssh-policy-check": module.params["ssh_ssh_policy_check"],
            "ssh-tun-policy-check": module.params["ssh_ssh_tun_policy_check"],
            "status": module.params["ssh_status"],
            "unsupported-version": module.params["ssh_unsupported_version"],
        },
        "ssl": {
            "allow-invalid-server-cert": module.params["ssl_allow_invalid_server_cert"],
            "client-cert-request": module.params["ssl_client_cert_request"],
            "inspect-all": module.params["ssl_inspect_all"],
            "unsupported-ssl": module.params["ssl_unsupported_ssl"],
            "untrusted-cert": module.params["ssl_untrusted_cert"],
        },
        "ssl-exempt": {
            "address": module.params["ssl_exempt_address"],
            "address6": module.params["ssl_exempt_address6"],
            "fortiguard-category": module.params["ssl_exempt_fortiguard_category"],
            "regex": module.params["ssl_exempt_regex"],
            "type": module.params["ssl_exempt_type"],
            "wildcard-fqdn": module.params["ssl_exempt_wildcard_fqdn"],
        },
        "ssl-server": {
            "ftps-client-cert-request": module.params["ssl_server_ftps_client_cert_request"],
            "https-client-cert-request": module.params["ssl_server_https_client_cert_request"],
            "imaps-client-cert-request": module.params["ssl_server_imaps_client_cert_request"],
            "ip": module.params["ssl_server_ip"],
            "pop3s-client-cert-request": module.params["ssl_server_pop3s_client_cert_request"],
            "smtps-client-cert-request": module.params["ssl_server_smtps_client_cert_request"],
            "ssl-other-client-cert-request": module.params["ssl_server_ssl_other_client_cert_request"],
        }
    }

    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['ftps', 'https', 'imaps', 'pop3s', 'smtps', 'ssh', 'ssl', 'ssl-exempt', 'ssl-server']
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)

    results = DEFAULT_RESULT_OBJ

    try:

        results = fmgr_firewall_ssl_ssh_profile_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {'status': ['preview'],
                    'supported_by': 'community',
                    'metadata_version': '1.1'}

DOCUMENTATION = '''
---
module: fmgr_secprof_ssl_ssh
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author:
    - Luke Weighall (@lweighall)
    - Andrew Welsh (@Ghilli3)
    - Jim Huber (@p4r4n0y1ng)
short_description: Manage SSL and SSH security profiles in FortiManager
description:
  -  Manage SSL and SSH security profiles in FortiManager via the FMG API

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: false
    default: root

  mode:
    description:
      - Sets one of three modes for managing the object.
      - Allows use of soft-adds instead of overwriting existing values
    choices: ['add', 'set', 'delete', 'update']
    required: false
    default: add

  whitelist:
    description:
      - Enable/disable exempting servers by FortiGuard whitelist.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  use_ssl_server:
    description:
      - Enable/disable the use of SSL server table for SSL offloading.
      - choice | disable | Don't use SSL server configuration.
      - choice | enable | Use SSL server configuration.
    required: false
    choices: ["disable", "enable"]

  untrusted_caname:
    description:
      - Untrusted CA certificate used by SSL Inspection.
    required: false

  ssl_exemptions_log:
    description:
      - Enable/disable logging SSL exemptions.
      - choice | disable | Disable logging SSL exemptions.
      - choice | enable | Enable logging SSL exemptions.
    required: false
    choices: ["disable", "enable"]

  ssl_anomalies_log:
    description:
      - Enable/disable logging SSL anomalies.
      - choice | disable | Disable logging SSL anomalies.
      - choice | enable | Enable logging SSL anomalies.
    required: false
    choices: ["disable", "enable"]

  server_cert_mode:
    description:
      - Re-sign or replace the server's certificate.
      - choice | re-sign | Multiple clients connecting to multiple servers.
      - choice | replace | Protect an SSL server.
    required: false
    choices: ["re-sign", "replace"]

  server_cert:
    description:
      - Certificate used by SSL Inspection to replace server certificate.
    required: false

  rpc_over_https:
    description:
      - Enable/disable inspection of RPC over HTTPS.
      - choice | disable | Disable inspection of RPC over HTTPS.
      - choice | enable | Enable inspection of RPC over HTTPS.
    required: false
    choices: ["disable", "enable"]

  name:
    description:
      - Name.
    required: false

  mapi_over_https:
    description:
      - Enable/disable inspection of MAPI over HTTPS.
      - choice | disable | Disable inspection of MAPI over HTTPS.
      - choice | enable | Enable inspection of MAPI over HTTPS.
    required: false
    choices: ["disable", "enable"]

  comment:
    description:
      - Optional comments.
    required: false

  caname:
    description:
      - CA certificate used by SSL Inspection.
    required: false

  ftps:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  ftps_allow_invalid_server_cert:
    description:
      - When enabled, allows SSL sessions whose server certificate validation failed.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  ftps_client_cert_request:
    description:
      - Action based on client certificate request failure.
      - choice | bypass | Bypass.
      - choice | inspect | Inspect.
      - choice | block | Block.
    required: false
    choices: ["bypass", "inspect", "block"]

  ftps_ports:
    description:
      - Ports to use for scanning (1 - 65535, default = 443).
    required: false

  ftps_status:
    description:
      - Configure protocol inspection status.
      - choice | disable | Disable.
      - choice | deep-inspection | Full SSL inspection.
    required: false
    choices: ["disable", "deep-inspection"]

  ftps_unsupported_ssl:
    description:
      - Action based on the SSL encryption used being unsupported.
      - choice | bypass | Bypass.
      - choice | inspect | Inspect.
      - choice | block | Block.
    required: false
    choices: ["bypass", "inspect", "block"]

  ftps_untrusted_cert:
    description:
      - Allow, ignore, or block the untrusted SSL session server certificate.
      - choice | allow | Allow the untrusted server certificate.
      - choice | block | Block the connection when an untrusted server certificate is detected.
      - choice | ignore | Always take the server certificate as trusted.
    required: false
    choices: ["allow", "block", "ignore"]

  https:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  https_allow_invalid_server_cert:
    description:
      - When enabled, allows SSL sessions whose server certificate validation failed.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  https_client_cert_request:
    description:
      - Action based on client certificate request failure.
      - choice | bypass | Bypass.
      - choice | inspect | Inspect.
      - choice | block | Block.
    required: false
    choices: ["bypass", "inspect", "block"]

  https_ports:
    description:
      - Ports to use for scanning (1 - 65535, default = 443).
    required: false

  https_status:
    description:
      - Configure protocol inspection status.
      - choice | disable | Disable.
      - choice | certificate-inspection | Inspect SSL handshake only.
      - choice | deep-inspection | Full SSL inspection.
    required: false
    choices: ["disable", "certificate-inspection", "deep-inspection"]

  https_unsupported_ssl:
    description:
      - Action based on the SSL encryption used being unsupported.
      - choice | bypass | Bypass.
      - choice | inspect | Inspect.
      - choice | block | Block.
    required: false
    choices: ["bypass", "inspect", "block"]

  https_untrusted_cert:
    description:
      - Allow, ignore, or block the untrusted SSL session server certificate.
      - choice | allow | Allow the untrusted server certificate.
      - choice | block | Block the connection when an untrusted server certificate is detected.
      - choice | ignore | Always take the server certificate as trusted.
    required: false
    choices: ["allow", "block", "ignore"]

  imaps:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  imaps_allow_invalid_server_cert:
    description:
      - When enabled, allows SSL sessions whose server certificate validation failed.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  imaps_client_cert_request:
    description:
      - Action based on client certificate request failure.
      - choice | bypass | Bypass.
      - choice | inspect | Inspect.
      - choice | block | Block.
    required: false
    choices: ["bypass", "inspect", "block"]

  imaps_ports:
    description:
      - Ports to use for scanning (1 - 65535, default = 443).
    required: false

  imaps_status:
    description:
      - Configure protocol inspection status.
      - choice | disable | Disable.
      - choice | deep-inspection | Full SSL inspection.
    required: false
    choices: ["disable", "deep-inspection"]

  imaps_unsupported_ssl:
    description:
      - Action based on the SSL encryption used being unsupported.
      - choice | bypass | Bypass.
      - choice | inspect | Inspect.
      - choice | block | Block.
    required: false
    choices: ["bypass", "inspect", "block"]

  imaps_untrusted_cert:
    description:
      - Allow, ignore, or block the untrusted SSL session server certificate.
      - choice | allow | Allow the untrusted server certificate.
      - choice | block | Block the connection when an untrusted server certificate is detected.
      - choice | ignore | Always take the server certificate as trusted.
    required: false
    choices: ["allow", "block", "ignore"]

  pop3s:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  pop3s_allow_invalid_server_cert:
    description:
      - When enabled, allows SSL sessions whose server certificate validation failed.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  pop3s_client_cert_request:
    description:
      - Action based on client certificate request failure.
      - choice | bypass | Bypass.
      - choice | inspect | Inspect.
      - choice | block | Block.
    required: false
    choices: ["bypass", "inspect", "block"]

  pop3s_ports:
    description:
      - Ports to use for scanning (1 - 65535, default = 443).
    required: false

  pop3s_status:
    description:
      - Configure protocol inspection status.
      - choice | disable | Disable.
      - choice | deep-inspection | Full SSL inspection.
    required: false
    choices: ["disable", "deep-inspection"]

  pop3s_unsupported_ssl:
    description:
      - Action based on the SSL encryption used being unsupported.
      - choice | bypass | Bypass.
      - choice | inspect | Inspect.
      - choice | block | Block.
    required: false
    choices: ["bypass", "inspect", "block"]

  pop3s_untrusted_cert:
    description:
      - Allow, ignore, or block the untrusted SSL session server certificate.
      - choice | allow | Allow the untrusted server certificate.
      - choice | block | Block the connection when an untrusted server certificate is detected.
      - choice | ignore | Always take the server certificate as trusted.
    required: false
    choices: ["allow", "block", "ignore"]

  smtps:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  smtps_allow_invalid_server_cert:
    description:
      - When enabled, allows SSL sessions whose server certificate validation failed.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  smtps_client_cert_request:
    description:
      - Action based on client certificate request failure.
      - choice | bypass | Bypass.
      - choice | inspect | Inspect.
      - choice | block | Block.
    required: false
    choices: ["bypass", "inspect", "block"]

  smtps_ports:
    description:
      - Ports to use for scanning (1 - 65535, default = 443).
    required: false

  smtps_status:
    description:
      - Configure protocol inspection status.
      - choice | disable | Disable.
      - choice | deep-inspection | Full SSL inspection.
    required: false
    choices: ["disable", "deep-inspection"]

  smtps_unsupported_ssl:
    description:
      - Action based on the SSL encryption used being unsupported.
      - choice | bypass | Bypass.
      - choice | inspect | Inspect.
      - choice | block | Block.
    required: false
    choices: ["bypass", "inspect", "block"]

  smtps_untrusted_cert:
    description:
      - Allow, ignore, or block the untrusted SSL session server certificate.
      - choice | allow | Allow the untrusted server certificate.
      - choice | block | Block the connection when an untrusted server certificate is detected.
      - choice | ignore | Always take the server certificate as trusted.
    required: false
    choices: ["allow", "block", "ignore"]

  ssh:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  ssh_inspect_all:
    description:
      - Level of SSL inspection.
      - choice | disable | Disable.
      - choice | deep-inspection | Full SSL inspection.
    required: false
    choices: ["disable", "deep-inspection"]

  ssh_ports:
    description:
      - Ports to use for scanning (1 - 65535, default = 443).
    required: false

  ssh_ssh_algorithm:
    description:
      - Relative strength of encryption algorithms accepted during negotiation.
      - choice | compatible | Allow a broader set of encryption algorithms for best compatibility.
      - choice | high-encryption | Allow only AES-CTR, AES-GCM ciphers and high encryption algorithms.
    required: false
    choices: ["compatible", "high-encryption"]

  ssh_ssh_policy_check:
    description:
      - Enable/disable SSH policy check.
      - choice | disable | Disable SSH policy check.
      - choice | enable | Enable SSH policy check.
    required: false
    choices: ["disable", "enable"]

  ssh_ssh_tun_policy_check:
    description:
      - Enable/disable SSH tunnel policy check.
      - choice | disable | Disable SSH tunnel policy check.
      - choice | enable | Enable SSH tunnel policy check.
    required: false
    choices: ["disable", "enable"]

  ssh_status:
    description:
      - Configure protocol inspection status.
      - choice | disable | Disable.
      - choice | deep-inspection | Full SSL inspection.
    required: false
    choices: ["disable", "deep-inspection"]

  ssh_unsupported_version:
    description:
      - Action based on SSH version being unsupported.
      - choice | block | Block.
      - choice | bypass | Bypass.
    required: false
    choices: ["block", "bypass"]

  ssl:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  ssl_allow_invalid_server_cert:
    description:
      - When enabled, allows SSL sessions whose server certificate validation failed.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  ssl_client_cert_request:
    description:
      - Action based on client certificate request failure.
      - choice | bypass | Bypass.
      - choice | inspect | Inspect.
      - choice | block | Block.
    required: false
    choices: ["bypass", "inspect", "block"]

  ssl_inspect_all:
    description:
      - Level of SSL inspection.
      - choice | disable | Disable.
      - choice | certificate-inspection | Inspect SSL handshake only.
      - choice | deep-inspection | Full SSL inspection.
    required: false
    choices: ["disable", "certificate-inspection", "deep-inspection"]

  ssl_unsupported_ssl:
    description:
      - Action based on the SSL encryption used being unsupported.
      - choice | bypass | Bypass.
      - choice | inspect | Inspect.
      - choice | block | Block.
    required: false
    choices: ["bypass", "inspect", "block"]

  ssl_untrusted_cert:
    description:
      - Allow, ignore, or block the untrusted SSL session server certificate.
      - choice | allow | Allow the untrusted server certificate.
      - choice | block | Block the connection when an untrusted server certificate is detected.
      - choice | ignore | Always take the server certificate as trusted.
    required: false
    choices: ["allow", "block", "ignore"]

  ssl_exempt:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  ssl_exempt_address:
    description:
      - IPv4 address object.
    required: false

  ssl_exempt_address6:
    description:
      - IPv6 address object.
    required: false

  ssl_exempt_fortiguard_category:
    description:
      - FortiGuard category ID.
    required: false

  ssl_exempt_regex:
    description:
      - Exempt servers by regular expression.
    required: false

  ssl_exempt_type:
    description:
      - Type of address object (IPv4 or IPv6) or FortiGuard category.
      - choice | fortiguard-category | FortiGuard category.
      - choice | address | Firewall IPv4 address.
      - choice | address6 | Firewall IPv6 address.
      - choice | wildcard-fqdn | Fully Qualified Domain Name with wildcard characters.
      - choice | regex | Regular expression FQDN.
    required: false
    choices: ["fortiguard-category", "address", "address6", "wildcard-fqdn", "regex"]

  ssl_exempt_wildcard_fqdn:
    description:
      - Exempt servers by wildcard FQDN.
    required: false

  ssl_server:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  ssl_server_ftps_client_cert_request:
    description:
      - Action based on client certificate request failure during the FTPS handshake.
      - choice | bypass | Bypass.
      - choice | inspect | Inspect.
      - choice | block | Block.
    required: false
    choices: ["bypass", "inspect", "block"]

  ssl_server_https_client_cert_request:
    description:
      - Action based on client certificate request failure during the HTTPS handshake.
      - choice | bypass | Bypass.
      - choice | inspect | Inspect.
      - choice | block | Block.
    required: false
    choices: ["bypass", "inspect", "block"]

  ssl_server_imaps_client_cert_request:
    description:
      - Action based on client certificate request failure during the IMAPS handshake.
      - choice | bypass | Bypass.
      - choice | inspect | Inspect.
      - choice | block | Block.
    required: false
    choices: ["bypass", "inspect", "block"]

  ssl_server_ip:
    description:
      - IPv4 address of the SSL server.
    required: false

  ssl_server_pop3s_client_cert_request:
    description:
      - Action based on client certificate request failure during the POP3S handshake.
      - choice | bypass | Bypass.
      - choice | inspect | Inspect.
      - choice | block | Block.
    required: false
    choices: ["bypass", "inspect", "block"]

  ssl_server_smtps_client_cert_request:
    description:
      - Action based on client certificate request failure during the SMTPS handshake.
      - choice | bypass | Bypass.
      - choice | inspect | Inspect.
      - choice | block | Block.
    required: false
    choices: ["bypass", "inspect", "block"]

  ssl_server_ssl_other_client_cert_request:
    description:
      - Action based on client certificate request failure during an SSL protocol handshake.
      - choice | bypass | Bypass.
      - choice | inspect | Inspect.
      - choice | block | Block.
    required: false
    choices: ["bypass", "inspect", "block"]


'''

EXAMPLES = '''
  - name: DELETE Profile
    fmgr_secprof_ssl_ssh:
      name: Ansible_SSL_SSH_Profile
      mode: delete

  - name: CREATE Profile
    fmgr_secprof_ssl_ssh:
      name: Ansible_SSL_SSH_Profile
      comment: "Created by Ansible Module TEST"
      mode: set
      mapi_over_https: enable
      rpc_over_https: enable
      server_cert_mode: replace
      ssl_anomalies_log: enable
      ssl_exemptions_log: enable
      use_ssl_server: enable
      whitelist: enable
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import FMGRMethods
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
from ansible.module_utils.network.fortimanager.common import prepare_dict
from ansible.module_utils.network.fortimanager.common import scrub_dict

###############
# START METHODS
###############


def fmgr_firewall_ssl_ssh_profile_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/firewall/ssl-ssh-profile'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/firewall/ssl-ssh-profile/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])

    return response


#############
# END METHODS
#############


def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        whitelist=dict(required=False, type="str", choices=["disable", "enable"]),
        use_ssl_server=dict(required=False, type="str", choices=["disable", "enable"]),
        untrusted_caname=dict(required=False, type="str"),
        ssl_exemptions_log=dict(required=False, type="str", choices=["disable", "enable"]),
        ssl_anomalies_log=dict(required=False, type="str", choices=["disable", "enable"]),
        server_cert_mode=dict(required=False, type="str", choices=["re-sign", "replace"]),
        server_cert=dict(required=False, type="str"),
        rpc_over_https=dict(required=False, type="str", choices=["disable", "enable"]),
        name=dict(required=False, type="str"),
        mapi_over_https=dict(required=False, type="str", choices=["disable", "enable"]),
        comment=dict(required=False, type="str"),
        caname=dict(required=False, type="str"),
        ftps=dict(required=False, type="list"),
        ftps_allow_invalid_server_cert=dict(required=False, type="str", choices=["disable", "enable"]),
        ftps_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        ftps_ports=dict(required=False, type="str"),
        ftps_status=dict(required=False, type="str", choices=["disable", "deep-inspection"]),
        ftps_unsupported_ssl=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        ftps_untrusted_cert=dict(required=False, type="str", choices=["allow", "block", "ignore"]),
        https=dict(required=False, type="list"),
        https_allow_invalid_server_cert=dict(required=False, type="str", choices=["disable", "enable"]),
        https_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        https_ports=dict(required=False, type="str"),
        https_status=dict(required=False, type="str", choices=["disable", "certificate-inspection", "deep-inspection"]),
        https_unsupported_ssl=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        https_untrusted_cert=dict(required=False, type="str", choices=["allow", "block", "ignore"]),
        imaps=dict(required=False, type="list"),
        imaps_allow_invalid_server_cert=dict(required=False, type="str", choices=["disable", "enable"]),
        imaps_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        imaps_ports=dict(required=False, type="str"),
        imaps_status=dict(required=False, type="str", choices=["disable", "deep-inspection"]),
        imaps_unsupported_ssl=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        imaps_untrusted_cert=dict(required=False, type="str", choices=["allow", "block", "ignore"]),
        pop3s=dict(required=False, type="list"),
        pop3s_allow_invalid_server_cert=dict(required=False, type="str", choices=["disable", "enable"]),
        pop3s_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        pop3s_ports=dict(required=False, type="str"),
        pop3s_status=dict(required=False, type="str", choices=["disable", "deep-inspection"]),
        pop3s_unsupported_ssl=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        pop3s_untrusted_cert=dict(required=False, type="str", choices=["allow", "block", "ignore"]),
        smtps=dict(required=False, type="list"),
        smtps_allow_invalid_server_cert=dict(required=False, type="str", choices=["disable", "enable"]),
        smtps_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        smtps_ports=dict(required=False, type="str"),
        smtps_status=dict(required=False, type="str", choices=["disable", "deep-inspection"]),
        smtps_unsupported_ssl=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        smtps_untrusted_cert=dict(required=False, type="str", choices=["allow", "block", "ignore"]),
        ssh=dict(required=False, type="list"),
        ssh_inspect_all=dict(required=False, type="str", choices=["disable", "deep-inspection"]),
        ssh_ports=dict(required=False, type="str"),
        ssh_ssh_algorithm=dict(required=False, type="str", choices=["compatible", "high-encryption"]),
        ssh_ssh_policy_check=dict(required=False, type="str", choices=["disable", "enable"]),
        ssh_ssh_tun_policy_check=dict(required=False, type="str", choices=["disable", "enable"]),
        ssh_status=dict(required=False, type="str", choices=["disable", "deep-inspection"]),
        ssh_unsupported_version=dict(required=False, type="str", choices=["block", "bypass"]),
        ssl=dict(required=False, type="list"),
        ssl_allow_invalid_server_cert=dict(required=False, type="str", choices=["disable", "enable"]),
        ssl_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        ssl_inspect_all=dict(required=False, type="str", choices=["disable", "certificate-inspection",
                                                                  "deep-inspection"]),
        ssl_unsupported_ssl=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        ssl_untrusted_cert=dict(required=False, type="str", choices=["allow", "block", "ignore"]),
        ssl_exempt=dict(required=False, type="list"),
        ssl_exempt_address=dict(required=False, type="str"),
        ssl_exempt_address6=dict(required=False, type="str"),
        ssl_exempt_fortiguard_category=dict(required=False, type="str"),
        ssl_exempt_regex=dict(required=False, type="str"),
        ssl_exempt_type=dict(required=False, type="str", choices=["fortiguard-category", "address", "address6",
                                                                  "wildcard-fqdn", "regex"]),
        ssl_exempt_wildcard_fqdn=dict(required=False, type="str"),
        ssl_server=dict(required=False, type="list"),
        ssl_server_ftps_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        ssl_server_https_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        ssl_server_imaps_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        ssl_server_ip=dict(required=False, type="str"),
        ssl_server_pop3s_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        ssl_server_smtps_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
        ssl_server_ssl_other_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect",
                                                                                           "block"]),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "whitelist": module.params["whitelist"],
        "use-ssl-server": module.params["use_ssl_server"],
        "untrusted-caname": module.params["untrusted_caname"],
        "ssl-exemptions-log": module.params["ssl_exemptions_log"],
        "ssl-anomalies-log": module.params["ssl_anomalies_log"],
        "server-cert-mode": module.params["server_cert_mode"],
        "server-cert": module.params["server_cert"],
        "rpc-over-https": module.params["rpc_over_https"],
        "name": module.params["name"],
        "mapi-over-https": module.params["mapi_over_https"],
        "comment": module.params["comment"],
        "caname": module.params["caname"],
        "ftps": {
            "allow-invalid-server-cert": module.params["ftps_allow_invalid_server_cert"],
            "client-cert-request": module.params["ftps_client_cert_request"],
            "ports": module.params["ftps_ports"],
            "status": module.params["ftps_status"],
            "unsupported-ssl": module.params["ftps_unsupported_ssl"],
            "untrusted-cert": module.params["ftps_untrusted_cert"],
        },
        "https": {
            "allow-invalid-server-cert": module.params["https_allow_invalid_server_cert"],
            "client-cert-request": module.params["https_client_cert_request"],
            "ports": module.params["https_ports"],
            "status": module.params["https_status"],
            "unsupported-ssl": module.params["https_unsupported_ssl"],
            "untrusted-cert": module.params["https_untrusted_cert"],
        },
        "imaps": {
            "allow-invalid-server-cert": module.params["imaps_allow_invalid_server_cert"],
            "client-cert-request": module.params["imaps_client_cert_request"],
            "ports": module.params["imaps_ports"],
            "status": module.params["imaps_status"],
            "unsupported-ssl": module.params["imaps_unsupported_ssl"],
            "untrusted-cert": module.params["imaps_untrusted_cert"],
        },
        "pop3s": {
            "allow-invalid-server-cert": module.params["pop3s_allow_invalid_server_cert"],
            "client-cert-request": module.params["pop3s_client_cert_request"],
            "ports": module.params["pop3s_ports"],
            "status": module.params["pop3s_status"],
            "unsupported-ssl": module.params["pop3s_unsupported_ssl"],
            "untrusted-cert": module.params["pop3s_untrusted_cert"],
        },
        "smtps": {
            "allow-invalid-server-cert": module.params["smtps_allow_invalid_server_cert"],
            "client-cert-request": module.params["smtps_client_cert_request"],
            "ports": module.params["smtps_ports"],
            "status": module.params["smtps_status"],
            "unsupported-ssl": module.params["smtps_unsupported_ssl"],
            "untrusted-cert": module.params["smtps_untrusted_cert"],
        },
        "ssh": {
            "inspect-all": module.params["ssh_inspect_all"],
            "ports": module.params["ssh_ports"],
            "ssh-algorithm": module.params["ssh_ssh_algorithm"],
            "ssh-policy-check": module.params["ssh_ssh_policy_check"],
            "ssh-tun-policy-check": module.params["ssh_ssh_tun_policy_check"],
            "status": module.params["ssh_status"],
            "unsupported-version": module.params["ssh_unsupported_version"],
        },
        "ssl": {
            "allow-invalid-server-cert": module.params["ssl_allow_invalid_server_cert"],
            "client-cert-request": module.params["ssl_client_cert_request"],
            "inspect-all": module.params["ssl_inspect_all"],
            "unsupported-ssl": module.params["ssl_unsupported_ssl"],
            "untrusted-cert": module.params["ssl_untrusted_cert"],
        },
        "ssl-exempt": {
            "address": module.params["ssl_exempt_address"],
            "address6": module.params["ssl_exempt_address6"],
            "fortiguard-category": module.params["ssl_exempt_fortiguard_category"],
            "regex": module.params["ssl_exempt_regex"],
            "type": module.params["ssl_exempt_type"],
            "wildcard-fqdn": module.params["ssl_exempt_wildcard_fqdn"],
        },
        "ssl-server": {
            "ftps-client-cert-request": module.params["ssl_server_ftps_client_cert_request"],
            "https-client-cert-request": module.params["ssl_server_https_client_cert_request"],
            "imaps-client-cert-request": module.params["ssl_server_imaps_client_cert_request"],
            "ip": module.params["ssl_server_ip"],
            "pop3s-client-cert-request": module.params["ssl_server_pop3s_client_cert_request"],
            "smtps-client-cert-request": module.params["ssl_server_smtps_client_cert_request"],
            "ssl-other-client-cert-request": module.params["ssl_server_ssl_other_client_cert_request"],
        }
    }

    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['ftps', 'https', 'imaps', 'pop3s', 'smtps', 'ssh', 'ssl', 'ssl-exempt', 'ssl-server']
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)

    results = DEFAULT_RESULT_OBJ

    try:

        results = fmgr_firewall_ssl_ssh_profile_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_secprof_voip

Metadata

Name: fmgr_secprof_voip

Description: Manage VOIP security profiles in FortiManager via API

Author(s):

  • Luke Weighall (github: @lweighall)
  • Andrew Welsh (github: @Ghilli3)
  • Jim Huber (github: @p4r4n0y1ng)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Andrew Welsh

Module Github Link

Parameters
adom
  • Description: The ADOM the configuration should belong to.
  • Required: False
  • default: root
comment
  • Description: Comment.
  • Required: False
mode
  • Description: Sets one of three modes for managing the object.

    Allows use of soft-adds instead of overwriting existing values

  • Required: False

  • default: add

  • choices: [‘add’, ‘set’, ‘delete’, ‘update’]

name
  • Description: Profile name.
  • Required: False
sccp
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

sccp_block_mcast
  • Description: Enable/disable block multicast RTP connections.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sccp_log_call_summary
  • Description: Enable/disable log summary of SCCP calls.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sccp_log_violations
  • Description: Enable/disable logging of SCCP violations.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sccp_max_calls
  • Description: Maximum calls per minute per SCCP client (max 65535).
  • Required: False
sccp_status
  • Description: Enable/disable SCCP.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sccp_verify_header
  • Description: Enable/disable verify SCCP header content.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

sip_ack_rate
  • Description: ACK request rate limit (per second, per policy).
  • Required: False
sip_block_ack
  • Description: Enable/disable block ACK requests.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_block_bye
  • Description: Enable/disable block BYE requests.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_block_cancel
  • Description: Enable/disable block CANCEL requests.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_block_geo_red_options
  • Description: Enable/disable block OPTIONS requests, but OPTIONS requests still notify for redundancy.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_block_info
  • Description: Enable/disable block INFO requests.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_block_invite
  • Description: Enable/disable block INVITE requests.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_block_long_lines
  • Description: Enable/disable block requests with headers exceeding max-line-length.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_block_message
  • Description: Enable/disable block MESSAGE requests.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_block_notify
  • Description: Enable/disable block NOTIFY requests.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_block_options
  • Description: Enable/disable block OPTIONS requests and no OPTIONS as notifying message for redundancy either.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_block_prack
  • Description: Enable/disable block prack requests.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_block_publish
  • Description: Enable/disable block PUBLISH requests.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_block_refer
  • Description: Enable/disable block REFER requests.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_block_register
  • Description: Enable/disable block REGISTER requests.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_block_subscribe
  • Description: Enable/disable block SUBSCRIBE requests.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_block_unknown
  • Description: Block unrecognized SIP requests (enabled by default).

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_block_update
  • Description: Enable/disable block UPDATE requests.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_bye_rate
  • Description: BYE request rate limit (per second, per policy).
  • Required: False
sip_call_keepalive
  • Description: Continue tracking calls with no RTP for this many minutes.
  • Required: False
sip_cancel_rate
  • Description: CANCEL request rate limit (per second, per policy).
  • Required: False
sip_contact_fixup
  • Description: Fixup contact anyway even if contact’s IP|port doesn’t match session’s IP|port.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_hnt_restrict_source_ip
  • Description: Enable/disable restrict RTP source IP to be the same as SIP source IP when HNT is enabled.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_hosted_nat_traversal
  • Description: Hosted NAT Traversal (HNT).

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_info_rate
  • Description: INFO request rate limit (per second, per policy).
  • Required: False
sip_invite_rate
  • Description: INVITE request rate limit (per second, per policy).
  • Required: False
sip_ips_rtp
  • Description: Enable/disable allow IPS on RTP.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_log_call_summary
  • Description: Enable/disable logging of SIP call summary.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_log_violations
  • Description: Enable/disable logging of SIP violations.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_malformed_header_allow
  • Description: Action for malformed Allow header.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_call_id
  • Description: Action for malformed Call-ID header.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_contact
  • Description: Action for malformed Contact header.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_content_length
  • Description: Action for malformed Content-Length header.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_content_type
  • Description: Action for malformed Content-Type header.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_cseq
  • Description: Action for malformed CSeq header.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_expires
  • Description: Action for malformed Expires header.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_from
  • Description: Action for malformed From header.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_max_forwards
  • Description: Action for malformed Max-Forwards header.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_p_asserted_identity
  • Description: Action for malformed P-Asserted-Identity header.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_rack
  • Description: Action for malformed RAck header.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_record_route
  • Description: Action for malformed Record-Route header.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_route
  • Description: Action for malformed Route header.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_rseq
  • Description: Action for malformed RSeq header.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_sdp_a
  • Description: Action for malformed SDP a line.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_sdp_b
  • Description: Action for malformed SDP b line.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_sdp_c
  • Description: Action for malformed SDP c line.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_sdp_i
  • Description: Action for malformed SDP i line.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_sdp_k
  • Description: Action for malformed SDP k line.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_sdp_m
  • Description: Action for malformed SDP m line.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_sdp_o
  • Description: Action for malformed SDP o line.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_sdp_r
  • Description: Action for malformed SDP r line.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_sdp_s
  • Description: Action for malformed SDP s line.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_sdp_t
  • Description: Action for malformed SDP t line.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_sdp_v
  • Description: Action for malformed SDP v line.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_sdp_z
  • Description: Action for malformed SDP z line.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_to
  • Description: Action for malformed To header.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_header_via
  • Description: Action for malformed VIA header.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_malformed_request_line
  • Description: Action for malformed request line.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_max_body_length
  • Description: Maximum SIP message body length (0 meaning no limit).
  • Required: False
sip_max_dialogs
  • Description: Maximum number of concurrent calls/dialogs (per policy).
  • Required: False
sip_max_idle_dialogs
  • Description: Maximum number established but idle dialogs to retain (per policy).
  • Required: False
sip_max_line_length
  • Description: Maximum SIP header line length (78-4096).
  • Required: False
sip_message_rate
  • Description: MESSAGE request rate limit (per second, per policy).
  • Required: False
sip_nat_trace
  • Description: Enable/disable preservation of original IP in SDP i line.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_no_sdp_fixup
  • Description: Enable/disable no SDP fix-up.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_notify_rate
  • Description: NOTIFY request rate limit (per second, per policy).
  • Required: False
sip_open_contact_pinhole
  • Description: Enable/disable open pinhole for non-REGISTER Contact port.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_open_record_route_pinhole
  • Description: Enable/disable open pinhole for Record-Route port.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_open_register_pinhole
  • Description: Enable/disable open pinhole for REGISTER Contact port.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_open_via_pinhole
  • Description: Enable/disable open pinhole for Via port.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_options_rate
  • Description: OPTIONS request rate limit (per second, per policy).
  • Required: False
sip_prack_rate
  • Description: PRACK request rate limit (per second, per policy).
  • Required: False
sip_preserve_override
  • Description: Override i line to preserve original IPS (default| append).

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_provisional_invite_expiry_time
  • Description: Expiry time for provisional INVITE (10 - 3600 sec).
  • Required: False
sip_publish_rate
  • Description: PUBLISH request rate limit (per second, per policy).
  • Required: False
sip_refer_rate
  • Description: REFER request rate limit (per second, per policy).
  • Required: False
sip_register_contact_trace
  • Description: Enable/disable trace original IP/port within the contact header of REGISTER requests.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_register_rate
  • Description: REGISTER request rate limit (per second, per policy).
  • Required: False
sip_rfc2543_branch
  • Description: Enable/disable support via branch compliant with RFC 2543.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_rtp
  • Description: Enable/disable create pinholes for RTP traffic to traverse firewall.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_ssl_algorithm
  • Description: Relative strength of encryption algorithms accepted in negotiation.

    choice | high | High encryption. Allow only AES and ChaCha.

    choice | medium | Medium encryption. Allow AES, ChaCha, 3DES, and RC4.

    choice | low | Low encryption. Allow AES, ChaCha, 3DES, RC4, and DES.

  • Required: False

  • choices: [‘high’, ‘medium’, ‘low’]

sip_ssl_auth_client
  • Description: Require a client certificate and authenticate it with the peer/peergrp.
  • Required: False
sip_ssl_auth_server
  • Description: Authenticate the server’s certificate with the peer/peergrp.
  • Required: False
sip_ssl_client_certificate
  • Description: Name of Certificate to offer to server if requested.
  • Required: False
sip_ssl_client_renegotiation
  • Description: Allow/block client renegotiation by server.

    choice | allow | Allow a SSL client to renegotiate.

    choice | deny | Abort any SSL connection that attempts to renegotiate.

    choice | secure | Reject any SSL connection that does not offer a RFC 5746 Secure Renegotiation Indication.

  • Required: False

  • choices: [‘allow’, ‘deny’, ‘secure’]

sip_ssl_max_version
  • Description: Highest SSL/TLS version to negotiate.

    choice | ssl-3.0 | SSL 3.0.

    choice | tls-1.0 | TLS 1.0.

    choice | tls-1.1 | TLS 1.1.

    choice | tls-1.2 | TLS 1.2.

  • Required: False

  • choices: [‘ssl-3.0’, ‘tls-1.0’, ‘tls-1.1’, ‘tls-1.2’]

sip_ssl_min_version
  • Description: Lowest SSL/TLS version to negotiate.

    choice | ssl-3.0 | SSL 3.0.

    choice | tls-1.0 | TLS 1.0.

    choice | tls-1.1 | TLS 1.1.

    choice | tls-1.2 | TLS 1.2.

  • Required: False

  • choices: [‘ssl-3.0’, ‘tls-1.0’, ‘tls-1.1’, ‘tls-1.2’]

sip_ssl_mode
  • Description: SSL/TLS mode for encryption &amp; decryption of traffic.

    choice | off | No SSL.

    choice | full | Client to FortiGate and FortiGate to Server SSL.

  • Required: False

  • choices: [‘off’, ‘full’]

sip_ssl_pfs
  • Description: SSL Perfect Forward Secrecy.

    choice | require | PFS mandatory.

    choice | deny | PFS rejected.

    choice | allow | PFS allowed.

  • Required: False

  • choices: [‘require’, ‘deny’, ‘allow’]

sip_ssl_send_empty_frags
  • Description: Send empty fragments to avoid attack on CBC IV (SSL 3.0 &amp; TLS 1.0 only).

    choice | disable | Do not send empty fragments.

    choice | enable | Send empty fragments.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_ssl_server_certificate
  • Description: Name of Certificate return to the client in every SSL connection.
  • Required: False
sip_status
  • Description: Enable/disable SIP.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_strict_register
  • Description: Enable/disable only allow the registrar to connect.

    choice | disable | Disable status.

    choice | enable | Enable status.

  • Required: False

  • choices: [‘disable’, ‘enable’]

sip_subscribe_rate
  • Description: SUBSCRIBE request rate limit (per second, per policy).
  • Required: False
sip_unknown_header
  • Description: Action for unknown SIP header.

    choice | pass | Bypass malformed messages.

    choice | discard | Discard malformed messages.

    choice | respond | Respond with error code.

  • Required: False

  • choices: [‘pass’, ‘discard’, ‘respond’]

sip_update_rate
  • Description: UPDATE request rate limit (per second, per policy).
  • Required: False
Functions
  • fmgr_voip_profile_modify
def fmgr_voip_profile_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/voip/profile'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/voip/profile/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])

    return response


#############
# END METHODS
#############
  • main
def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        name=dict(required=False, type="str"),
        comment=dict(required=False, type="str"),
        sccp=dict(required=False, type="dict"),
        sccp_block_mcast=dict(required=False, type="str", choices=["disable", "enable"]),
        sccp_log_call_summary=dict(required=False, type="str", choices=["disable", "enable"]),
        sccp_log_violations=dict(required=False, type="str", choices=["disable", "enable"]),
        sccp_max_calls=dict(required=False, type="int"),
        sccp_status=dict(required=False, type="str", choices=["disable", "enable"]),
        sccp_verify_header=dict(required=False, type="str", choices=["disable", "enable"]),
        sip=dict(required=False, type="dict"),
        sip_ack_rate=dict(required=False, type="int"),
        sip_block_ack=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_bye=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_cancel=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_geo_red_options=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_info=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_invite=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_long_lines=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_message=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_notify=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_options=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_prack=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_publish=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_refer=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_register=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_subscribe=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_unknown=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_update=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_bye_rate=dict(required=False, type="int"),
        sip_call_keepalive=dict(required=False, type="int"),
        sip_cancel_rate=dict(required=False, type="int"),
        sip_contact_fixup=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_hnt_restrict_source_ip=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_hosted_nat_traversal=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_info_rate=dict(required=False, type="int"),
        sip_invite_rate=dict(required=False, type="int"),
        sip_ips_rtp=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_log_call_summary=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_log_violations=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_malformed_header_allow=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_call_id=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_contact=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_content_length=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_content_type=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_cseq=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_expires=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_from=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_max_forwards=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_p_asserted_identity=dict(required=False, type="str", choices=["pass",
                                                                                           "discard",
                                                                                           "respond"]),
        sip_malformed_header_rack=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_record_route=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_route=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_rseq=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_sdp_a=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_sdp_b=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_sdp_c=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_sdp_i=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_sdp_k=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_sdp_m=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_sdp_o=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_sdp_r=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_sdp_s=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_sdp_t=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_sdp_v=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_sdp_z=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_to=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_via=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_request_line=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_max_body_length=dict(required=False, type="int"),
        sip_max_dialogs=dict(required=False, type="int"),
        sip_max_idle_dialogs=dict(required=False, type="int"),
        sip_max_line_length=dict(required=False, type="int"),
        sip_message_rate=dict(required=False, type="int"),
        sip_nat_trace=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_no_sdp_fixup=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_notify_rate=dict(required=False, type="int"),
        sip_open_contact_pinhole=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_open_record_route_pinhole=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_open_register_pinhole=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_open_via_pinhole=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_options_rate=dict(required=False, type="int"),
        sip_prack_rate=dict(required=False, type="int"),
        sip_preserve_override=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_provisional_invite_expiry_time=dict(required=False, type="int"),
        sip_publish_rate=dict(required=False, type="int"),
        sip_refer_rate=dict(required=False, type="int"),
        sip_register_contact_trace=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_register_rate=dict(required=False, type="int"),
        sip_rfc2543_branch=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_rtp=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_ssl_algorithm=dict(required=False, type="str", choices=["high", "medium", "low"]),
        sip_ssl_auth_client=dict(required=False, type="str"),
        sip_ssl_auth_server=dict(required=False, type="str"),
        sip_ssl_client_certificate=dict(required=False, type="str"),
        sip_ssl_client_renegotiation=dict(required=False, type="str", choices=["allow", "deny", "secure"]),
        sip_ssl_max_version=dict(required=False, type="str", choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
        sip_ssl_min_version=dict(required=False, type="str", choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
        sip_ssl_mode=dict(required=False, type="str", choices=["off", "full"]),
        sip_ssl_pfs=dict(required=False, type="str", choices=["require", "deny", "allow"]),
        sip_ssl_send_empty_frags=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_ssl_server_certificate=dict(required=False, type="str"),
        sip_status=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_strict_register=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_subscribe_rate=dict(required=False, type="int"),
        sip_unknown_header=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_update_rate=dict(required=False, type="int"),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "name": module.params["name"],
        "comment": module.params["comment"],
        "sccp": {
            "block-mcast": module.params["sccp_block_mcast"],
            "log-call-summary": module.params["sccp_log_call_summary"],
            "log-violations": module.params["sccp_log_violations"],
            "max-calls": module.params["sccp_max_calls"],
            "status": module.params["sccp_status"],
            "verify-header": module.params["sccp_verify_header"],
        },
        "sip": {
            "ack-rate": module.params["sip_ack_rate"],
            "block-ack": module.params["sip_block_ack"],
            "block-bye": module.params["sip_block_bye"],
            "block-cancel": module.params["sip_block_cancel"],
            "block-geo-red-options": module.params["sip_block_geo_red_options"],
            "block-info": module.params["sip_block_info"],
            "block-invite": module.params["sip_block_invite"],
            "block-long-lines": module.params["sip_block_long_lines"],
            "block-message": module.params["sip_block_message"],
            "block-notify": module.params["sip_block_notify"],
            "block-options": module.params["sip_block_options"],
            "block-prack": module.params["sip_block_prack"],
            "block-publish": module.params["sip_block_publish"],
            "block-refer": module.params["sip_block_refer"],
            "block-register": module.params["sip_block_register"],
            "block-subscribe": module.params["sip_block_subscribe"],
            "block-unknown": module.params["sip_block_unknown"],
            "block-update": module.params["sip_block_update"],
            "bye-rate": module.params["sip_bye_rate"],
            "call-keepalive": module.params["sip_call_keepalive"],
            "cancel-rate": module.params["sip_cancel_rate"],
            "contact-fixup": module.params["sip_contact_fixup"],
            "hnt-restrict-source-ip": module.params["sip_hnt_restrict_source_ip"],
            "hosted-nat-traversal": module.params["sip_hosted_nat_traversal"],
            "info-rate": module.params["sip_info_rate"],
            "invite-rate": module.params["sip_invite_rate"],
            "ips-rtp": module.params["sip_ips_rtp"],
            "log-call-summary": module.params["sip_log_call_summary"],
            "log-violations": module.params["sip_log_violations"],
            "malformed-header-allow": module.params["sip_malformed_header_allow"],
            "malformed-header-call-id": module.params["sip_malformed_header_call_id"],
            "malformed-header-contact": module.params["sip_malformed_header_contact"],
            "malformed-header-content-length": module.params["sip_malformed_header_content_length"],
            "malformed-header-content-type": module.params["sip_malformed_header_content_type"],
            "malformed-header-cseq": module.params["sip_malformed_header_cseq"],
            "malformed-header-expires": module.params["sip_malformed_header_expires"],
            "malformed-header-from": module.params["sip_malformed_header_from"],
            "malformed-header-max-forwards": module.params["sip_malformed_header_max_forwards"],
            "malformed-header-p-asserted-identity": module.params["sip_malformed_header_p_asserted_identity"],
            "malformed-header-rack": module.params["sip_malformed_header_rack"],
            "malformed-header-record-route": module.params["sip_malformed_header_record_route"],
            "malformed-header-route": module.params["sip_malformed_header_route"],
            "malformed-header-rseq": module.params["sip_malformed_header_rseq"],
            "malformed-header-sdp-a": module.params["sip_malformed_header_sdp_a"],
            "malformed-header-sdp-b": module.params["sip_malformed_header_sdp_b"],
            "malformed-header-sdp-c": module.params["sip_malformed_header_sdp_c"],
            "malformed-header-sdp-i": module.params["sip_malformed_header_sdp_i"],
            "malformed-header-sdp-k": module.params["sip_malformed_header_sdp_k"],
            "malformed-header-sdp-m": module.params["sip_malformed_header_sdp_m"],
            "malformed-header-sdp-o": module.params["sip_malformed_header_sdp_o"],
            "malformed-header-sdp-r": module.params["sip_malformed_header_sdp_r"],
            "malformed-header-sdp-s": module.params["sip_malformed_header_sdp_s"],
            "malformed-header-sdp-t": module.params["sip_malformed_header_sdp_t"],
            "malformed-header-sdp-v": module.params["sip_malformed_header_sdp_v"],
            "malformed-header-sdp-z": module.params["sip_malformed_header_sdp_z"],
            "malformed-header-to": module.params["sip_malformed_header_to"],
            "malformed-header-via": module.params["sip_malformed_header_via"],
            "malformed-request-line": module.params["sip_malformed_request_line"],
            "max-body-length": module.params["sip_max_body_length"],
            "max-dialogs": module.params["sip_max_dialogs"],
            "max-idle-dialogs": module.params["sip_max_idle_dialogs"],
            "max-line-length": module.params["sip_max_line_length"],
            "message-rate": module.params["sip_message_rate"],
            "nat-trace": module.params["sip_nat_trace"],
            "no-sdp-fixup": module.params["sip_no_sdp_fixup"],
            "notify-rate": module.params["sip_notify_rate"],
            "open-contact-pinhole": module.params["sip_open_contact_pinhole"],
            "open-record-route-pinhole": module.params["sip_open_record_route_pinhole"],
            "open-register-pinhole": module.params["sip_open_register_pinhole"],
            "open-via-pinhole": module.params["sip_open_via_pinhole"],
            "options-rate": module.params["sip_options_rate"],
            "prack-rate": module.params["sip_prack_rate"],
            "preserve-override": module.params["sip_preserve_override"],
            "provisional-invite-expiry-time": module.params["sip_provisional_invite_expiry_time"],
            "publish-rate": module.params["sip_publish_rate"],
            "refer-rate": module.params["sip_refer_rate"],
            "register-contact-trace": module.params["sip_register_contact_trace"],
            "register-rate": module.params["sip_register_rate"],
            "rfc2543-branch": module.params["sip_rfc2543_branch"],
            "rtp": module.params["sip_rtp"],
            "ssl-algorithm": module.params["sip_ssl_algorithm"],
            "ssl-auth-client": module.params["sip_ssl_auth_client"],
            "ssl-auth-server": module.params["sip_ssl_auth_server"],
            "ssl-client-certificate": module.params["sip_ssl_client_certificate"],
            "ssl-client-renegotiation": module.params["sip_ssl_client_renegotiation"],
            "ssl-max-version": module.params["sip_ssl_max_version"],
            "ssl-min-version": module.params["sip_ssl_min_version"],
            "ssl-mode": module.params["sip_ssl_mode"],
            "ssl-pfs": module.params["sip_ssl_pfs"],
            "ssl-send-empty-frags": module.params["sip_ssl_send_empty_frags"],
            "ssl-server-certificate": module.params["sip_ssl_server_certificate"],
            "status": module.params["sip_status"],
            "strict-register": module.params["sip_strict_register"],
            "subscribe-rate": module.params["sip_subscribe_rate"],
            "unknown-header": module.params["sip_unknown_header"],
            "update-rate": module.params["sip_update_rate"],
        }
    }

    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['sccp', 'sip']
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)
    module.paramgram = paramgram

    results = DEFAULT_RESULT_OBJ
    try:

        results = fmgr_voip_profile_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {'status': ['preview'],
                    'supported_by': 'community',
                    'metadata_version': '1.1'}

DOCUMENTATION = '''
---
module: fmgr_secprof_voip
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author:
    - Luke Weighall (@lweighall)
    - Andrew Welsh (@Ghilli3)
    - Jim Huber (@p4r4n0y1ng)
short_description: VOIP security profiles in FMG
description:
  -  Manage VOIP security profiles in FortiManager via API

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: false
    default: root

  mode:
    description:
      - Sets one of three modes for managing the object.
      - Allows use of soft-adds instead of overwriting existing values
    choices: ['add', 'set', 'delete', 'update']
    required: false
    default: add

  name:
    description:
      - Profile name.
    required: false

  comment:
    description:
      - Comment.
    required: false

  sccp:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  sccp_block_mcast:
    description:
      - Enable/disable block multicast RTP connections.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sccp_log_call_summary:
    description:
      - Enable/disable log summary of SCCP calls.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sccp_log_violations:
    description:
      - Enable/disable logging of SCCP violations.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sccp_max_calls:
    description:
      - Maximum calls per minute per SCCP client (max 65535).
    required: false

  sccp_status:
    description:
      - Enable/disable SCCP.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sccp_verify_header:
    description:
      - Enable/disable verify SCCP header content.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  sip_ack_rate:
    description:
      - ACK request rate limit (per second, per policy).
    required: false

  sip_block_ack:
    description:
      - Enable/disable block ACK requests.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_block_bye:
    description:
      - Enable/disable block BYE requests.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_block_cancel:
    description:
      - Enable/disable block CANCEL requests.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_block_geo_red_options:
    description:
      - Enable/disable block OPTIONS requests, but OPTIONS requests still notify for redundancy.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_block_info:
    description:
      - Enable/disable block INFO requests.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_block_invite:
    description:
      - Enable/disable block INVITE requests.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_block_long_lines:
    description:
      - Enable/disable block requests with headers exceeding max-line-length.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_block_message:
    description:
      - Enable/disable block MESSAGE requests.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_block_notify:
    description:
      - Enable/disable block NOTIFY requests.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_block_options:
    description:
      - Enable/disable block OPTIONS requests and no OPTIONS as notifying message for redundancy either.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_block_prack:
    description:
      - Enable/disable block prack requests.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_block_publish:
    description:
      - Enable/disable block PUBLISH requests.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_block_refer:
    description:
      - Enable/disable block REFER requests.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_block_register:
    description:
      - Enable/disable block REGISTER requests.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_block_subscribe:
    description:
      - Enable/disable block SUBSCRIBE requests.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_block_unknown:
    description:
      - Block unrecognized SIP requests (enabled by default).
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_block_update:
    description:
      - Enable/disable block UPDATE requests.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_bye_rate:
    description:
      - BYE request rate limit (per second, per policy).
    required: false

  sip_call_keepalive:
    description:
      - Continue tracking calls with no RTP for this many minutes.
    required: false

  sip_cancel_rate:
    description:
      - CANCEL request rate limit (per second, per policy).
    required: false

  sip_contact_fixup:
    description:
      - Fixup contact anyway even if contact's IP|port doesn't match session's IP|port.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_hnt_restrict_source_ip:
    description:
      - Enable/disable restrict RTP source IP to be the same as SIP source IP when HNT is enabled.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_hosted_nat_traversal:
    description:
      - Hosted NAT Traversal (HNT).
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_info_rate:
    description:
      - INFO request rate limit (per second, per policy).
    required: false

  sip_invite_rate:
    description:
      - INVITE request rate limit (per second, per policy).
    required: false

  sip_ips_rtp:
    description:
      - Enable/disable allow IPS on RTP.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_log_call_summary:
    description:
      - Enable/disable logging of SIP call summary.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_log_violations:
    description:
      - Enable/disable logging of SIP violations.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_malformed_header_allow:
    description:
      - Action for malformed Allow header.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_call_id:
    description:
      - Action for malformed Call-ID header.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_contact:
    description:
      - Action for malformed Contact header.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_content_length:
    description:
      - Action for malformed Content-Length header.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_content_type:
    description:
      - Action for malformed Content-Type header.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_cseq:
    description:
      - Action for malformed CSeq header.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_expires:
    description:
      - Action for malformed Expires header.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_from:
    description:
      - Action for malformed From header.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_max_forwards:
    description:
      - Action for malformed Max-Forwards header.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_p_asserted_identity:
    description:
      - Action for malformed P-Asserted-Identity header.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_rack:
    description:
      - Action for malformed RAck header.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_record_route:
    description:
      - Action for malformed Record-Route header.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_route:
    description:
      - Action for malformed Route header.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_rseq:
    description:
      - Action for malformed RSeq header.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_sdp_a:
    description:
      - Action for malformed SDP a line.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_sdp_b:
    description:
      - Action for malformed SDP b line.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_sdp_c:
    description:
      - Action for malformed SDP c line.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_sdp_i:
    description:
      - Action for malformed SDP i line.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_sdp_k:
    description:
      - Action for malformed SDP k line.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_sdp_m:
    description:
      - Action for malformed SDP m line.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_sdp_o:
    description:
      - Action for malformed SDP o line.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_sdp_r:
    description:
      - Action for malformed SDP r line.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_sdp_s:
    description:
      - Action for malformed SDP s line.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_sdp_t:
    description:
      - Action for malformed SDP t line.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_sdp_v:
    description:
      - Action for malformed SDP v line.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_sdp_z:
    description:
      - Action for malformed SDP z line.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_to:
    description:
      - Action for malformed To header.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_header_via:
    description:
      - Action for malformed VIA header.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_malformed_request_line:
    description:
      - Action for malformed request line.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_max_body_length:
    description:
      - Maximum SIP message body length (0 meaning no limit).
    required: false

  sip_max_dialogs:
    description:
      - Maximum number of concurrent calls/dialogs (per policy).
    required: false

  sip_max_idle_dialogs:
    description:
      - Maximum number established but idle dialogs to retain (per policy).
    required: false

  sip_max_line_length:
    description:
      - Maximum SIP header line length (78-4096).
    required: false

  sip_message_rate:
    description:
      - MESSAGE request rate limit (per second, per policy).
    required: false

  sip_nat_trace:
    description:
      - Enable/disable preservation of original IP in SDP i line.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_no_sdp_fixup:
    description:
      - Enable/disable no SDP fix-up.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_notify_rate:
    description:
      - NOTIFY request rate limit (per second, per policy).
    required: false

  sip_open_contact_pinhole:
    description:
      - Enable/disable open pinhole for non-REGISTER Contact port.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_open_record_route_pinhole:
    description:
      - Enable/disable open pinhole for Record-Route port.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_open_register_pinhole:
    description:
      - Enable/disable open pinhole for REGISTER Contact port.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_open_via_pinhole:
    description:
      - Enable/disable open pinhole for Via port.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_options_rate:
    description:
      - OPTIONS request rate limit (per second, per policy).
    required: false

  sip_prack_rate:
    description:
      - PRACK request rate limit (per second, per policy).
    required: false

  sip_preserve_override:
    description:
      - Override i line to preserve original IPS (default| append).
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_provisional_invite_expiry_time:
    description:
      - Expiry time for provisional INVITE (10 - 3600 sec).
    required: false

  sip_publish_rate:
    description:
      - PUBLISH request rate limit (per second, per policy).
    required: false

  sip_refer_rate:
    description:
      - REFER request rate limit (per second, per policy).
    required: false

  sip_register_contact_trace:
    description:
      - Enable/disable trace original IP/port within the contact header of REGISTER requests.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_register_rate:
    description:
      - REGISTER request rate limit (per second, per policy).
    required: false

  sip_rfc2543_branch:
    description:
      - Enable/disable support via branch compliant with RFC 2543.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_rtp:
    description:
      - Enable/disable create pinholes for RTP traffic to traverse firewall.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_ssl_algorithm:
    description:
      - Relative strength of encryption algorithms accepted in negotiation.
      - choice | high | High encryption. Allow only AES and ChaCha.
      - choice | medium | Medium encryption. Allow AES, ChaCha, 3DES, and RC4.
      - choice | low | Low encryption. Allow AES, ChaCha, 3DES, RC4, and DES.
    required: false
    choices: ["high", "medium", "low"]

  sip_ssl_auth_client:
    description:
      - Require a client certificate and authenticate it with the peer/peergrp.
    required: false

  sip_ssl_auth_server:
    description:
      - Authenticate the server's certificate with the peer/peergrp.
    required: false

  sip_ssl_client_certificate:
    description:
      - Name of Certificate to offer to server if requested.
    required: false

  sip_ssl_client_renegotiation:
    description:
      - Allow/block client renegotiation by server.
      - choice | allow | Allow a SSL client to renegotiate.
      - choice | deny | Abort any SSL connection that attempts to renegotiate.
      - choice | secure | Reject any SSL connection that does not offer a RFC 5746 Secure Renegotiation Indication.
    required: false
    choices: ["allow", "deny", "secure"]

  sip_ssl_max_version:
    description:
      - Highest SSL/TLS version to negotiate.
      - choice | ssl-3.0 | SSL 3.0.
      - choice | tls-1.0 | TLS 1.0.
      - choice | tls-1.1 | TLS 1.1.
      - choice | tls-1.2 | TLS 1.2.
    required: false
    choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]

  sip_ssl_min_version:
    description:
      - Lowest SSL/TLS version to negotiate.
      - choice | ssl-3.0 | SSL 3.0.
      - choice | tls-1.0 | TLS 1.0.
      - choice | tls-1.1 | TLS 1.1.
      - choice | tls-1.2 | TLS 1.2.
    required: false
    choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]

  sip_ssl_mode:
    description:
      - SSL/TLS mode for encryption &amp; decryption of traffic.
      - choice | off | No SSL.
      - choice | full | Client to FortiGate and FortiGate to Server SSL.
    required: false
    choices: ["off", "full"]

  sip_ssl_pfs:
    description:
      - SSL Perfect Forward Secrecy.
      - choice | require | PFS mandatory.
      - choice | deny | PFS rejected.
      - choice | allow | PFS allowed.
    required: false
    choices: ["require", "deny", "allow"]

  sip_ssl_send_empty_frags:
    description:
      - Send empty fragments to avoid attack on CBC IV (SSL 3.0 &amp; TLS 1.0 only).
      - choice | disable | Do not send empty fragments.
      - choice | enable | Send empty fragments.
    required: false
    choices: ["disable", "enable"]

  sip_ssl_server_certificate:
    description:
      - Name of Certificate return to the client in every SSL connection.
    required: false

  sip_status:
    description:
      - Enable/disable SIP.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_strict_register:
    description:
      - Enable/disable only allow the registrar to connect.
      - choice | disable | Disable status.
      - choice | enable | Enable status.
    required: false
    choices: ["disable", "enable"]

  sip_subscribe_rate:
    description:
      - SUBSCRIBE request rate limit (per second, per policy).
    required: false

  sip_unknown_header:
    description:
      - Action for unknown SIP header.
      - choice | pass | Bypass malformed messages.
      - choice | discard | Discard malformed messages.
      - choice | respond | Respond with error code.
    required: false
    choices: ["pass", "discard", "respond"]

  sip_update_rate:
    description:
      - UPDATE request rate limit (per second, per policy).
    required: false


'''

EXAMPLES = '''
  - name: DELETE Profile
    fmgr_secprof_voip:
      name: "Ansible_VOIP_Profile"
      mode: "delete"

  - name: Create FMGR_VOIP_PROFILE
    fmgr_secprof_voip:
      mode: "set"
      adom: "root"
      name: "Ansible_VOIP_Profile"
      comment: "Created by Ansible"
      sccp: {block-mcast: "enable", log-call-summary: "enable", log-violations: "enable", status: "enable"}
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
from ansible.module_utils.network.fortimanager.common import prepare_dict
from ansible.module_utils.network.fortimanager.common import scrub_dict


###############
# START METHODS
###############


def fmgr_voip_profile_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/voip/profile'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/voip/profile/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])

    return response


#############
# END METHODS
#############


def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        name=dict(required=False, type="str"),
        comment=dict(required=False, type="str"),
        sccp=dict(required=False, type="dict"),
        sccp_block_mcast=dict(required=False, type="str", choices=["disable", "enable"]),
        sccp_log_call_summary=dict(required=False, type="str", choices=["disable", "enable"]),
        sccp_log_violations=dict(required=False, type="str", choices=["disable", "enable"]),
        sccp_max_calls=dict(required=False, type="int"),
        sccp_status=dict(required=False, type="str", choices=["disable", "enable"]),
        sccp_verify_header=dict(required=False, type="str", choices=["disable", "enable"]),
        sip=dict(required=False, type="dict"),
        sip_ack_rate=dict(required=False, type="int"),
        sip_block_ack=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_bye=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_cancel=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_geo_red_options=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_info=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_invite=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_long_lines=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_message=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_notify=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_options=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_prack=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_publish=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_refer=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_register=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_subscribe=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_unknown=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_block_update=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_bye_rate=dict(required=False, type="int"),
        sip_call_keepalive=dict(required=False, type="int"),
        sip_cancel_rate=dict(required=False, type="int"),
        sip_contact_fixup=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_hnt_restrict_source_ip=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_hosted_nat_traversal=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_info_rate=dict(required=False, type="int"),
        sip_invite_rate=dict(required=False, type="int"),
        sip_ips_rtp=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_log_call_summary=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_log_violations=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_malformed_header_allow=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_call_id=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_contact=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_content_length=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_content_type=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_cseq=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_expires=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_from=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_max_forwards=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_p_asserted_identity=dict(required=False, type="str", choices=["pass",
                                                                                           "discard",
                                                                                           "respond"]),
        sip_malformed_header_rack=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_record_route=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_route=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_rseq=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_sdp_a=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_sdp_b=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_sdp_c=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_sdp_i=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_sdp_k=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_sdp_m=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_sdp_o=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_sdp_r=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_sdp_s=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_sdp_t=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_sdp_v=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_sdp_z=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_to=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_header_via=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_malformed_request_line=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_max_body_length=dict(required=False, type="int"),
        sip_max_dialogs=dict(required=False, type="int"),
        sip_max_idle_dialogs=dict(required=False, type="int"),
        sip_max_line_length=dict(required=False, type="int"),
        sip_message_rate=dict(required=False, type="int"),
        sip_nat_trace=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_no_sdp_fixup=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_notify_rate=dict(required=False, type="int"),
        sip_open_contact_pinhole=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_open_record_route_pinhole=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_open_register_pinhole=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_open_via_pinhole=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_options_rate=dict(required=False, type="int"),
        sip_prack_rate=dict(required=False, type="int"),
        sip_preserve_override=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_provisional_invite_expiry_time=dict(required=False, type="int"),
        sip_publish_rate=dict(required=False, type="int"),
        sip_refer_rate=dict(required=False, type="int"),
        sip_register_contact_trace=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_register_rate=dict(required=False, type="int"),
        sip_rfc2543_branch=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_rtp=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_ssl_algorithm=dict(required=False, type="str", choices=["high", "medium", "low"]),
        sip_ssl_auth_client=dict(required=False, type="str"),
        sip_ssl_auth_server=dict(required=False, type="str"),
        sip_ssl_client_certificate=dict(required=False, type="str"),
        sip_ssl_client_renegotiation=dict(required=False, type="str", choices=["allow", "deny", "secure"]),
        sip_ssl_max_version=dict(required=False, type="str", choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
        sip_ssl_min_version=dict(required=False, type="str", choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
        sip_ssl_mode=dict(required=False, type="str", choices=["off", "full"]),
        sip_ssl_pfs=dict(required=False, type="str", choices=["require", "deny", "allow"]),
        sip_ssl_send_empty_frags=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_ssl_server_certificate=dict(required=False, type="str"),
        sip_status=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_strict_register=dict(required=False, type="str", choices=["disable", "enable"]),
        sip_subscribe_rate=dict(required=False, type="int"),
        sip_unknown_header=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
        sip_update_rate=dict(required=False, type="int"),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "name": module.params["name"],
        "comment": module.params["comment"],
        "sccp": {
            "block-mcast": module.params["sccp_block_mcast"],
            "log-call-summary": module.params["sccp_log_call_summary"],
            "log-violations": module.params["sccp_log_violations"],
            "max-calls": module.params["sccp_max_calls"],
            "status": module.params["sccp_status"],
            "verify-header": module.params["sccp_verify_header"],
        },
        "sip": {
            "ack-rate": module.params["sip_ack_rate"],
            "block-ack": module.params["sip_block_ack"],
            "block-bye": module.params["sip_block_bye"],
            "block-cancel": module.params["sip_block_cancel"],
            "block-geo-red-options": module.params["sip_block_geo_red_options"],
            "block-info": module.params["sip_block_info"],
            "block-invite": module.params["sip_block_invite"],
            "block-long-lines": module.params["sip_block_long_lines"],
            "block-message": module.params["sip_block_message"],
            "block-notify": module.params["sip_block_notify"],
            "block-options": module.params["sip_block_options"],
            "block-prack": module.params["sip_block_prack"],
            "block-publish": module.params["sip_block_publish"],
            "block-refer": module.params["sip_block_refer"],
            "block-register": module.params["sip_block_register"],
            "block-subscribe": module.params["sip_block_subscribe"],
            "block-unknown": module.params["sip_block_unknown"],
            "block-update": module.params["sip_block_update"],
            "bye-rate": module.params["sip_bye_rate"],
            "call-keepalive": module.params["sip_call_keepalive"],
            "cancel-rate": module.params["sip_cancel_rate"],
            "contact-fixup": module.params["sip_contact_fixup"],
            "hnt-restrict-source-ip": module.params["sip_hnt_restrict_source_ip"],
            "hosted-nat-traversal": module.params["sip_hosted_nat_traversal"],
            "info-rate": module.params["sip_info_rate"],
            "invite-rate": module.params["sip_invite_rate"],
            "ips-rtp": module.params["sip_ips_rtp"],
            "log-call-summary": module.params["sip_log_call_summary"],
            "log-violations": module.params["sip_log_violations"],
            "malformed-header-allow": module.params["sip_malformed_header_allow"],
            "malformed-header-call-id": module.params["sip_malformed_header_call_id"],
            "malformed-header-contact": module.params["sip_malformed_header_contact"],
            "malformed-header-content-length": module.params["sip_malformed_header_content_length"],
            "malformed-header-content-type": module.params["sip_malformed_header_content_type"],
            "malformed-header-cseq": module.params["sip_malformed_header_cseq"],
            "malformed-header-expires": module.params["sip_malformed_header_expires"],
            "malformed-header-from": module.params["sip_malformed_header_from"],
            "malformed-header-max-forwards": module.params["sip_malformed_header_max_forwards"],
            "malformed-header-p-asserted-identity": module.params["sip_malformed_header_p_asserted_identity"],
            "malformed-header-rack": module.params["sip_malformed_header_rack"],
            "malformed-header-record-route": module.params["sip_malformed_header_record_route"],
            "malformed-header-route": module.params["sip_malformed_header_route"],
            "malformed-header-rseq": module.params["sip_malformed_header_rseq"],
            "malformed-header-sdp-a": module.params["sip_malformed_header_sdp_a"],
            "malformed-header-sdp-b": module.params["sip_malformed_header_sdp_b"],
            "malformed-header-sdp-c": module.params["sip_malformed_header_sdp_c"],
            "malformed-header-sdp-i": module.params["sip_malformed_header_sdp_i"],
            "malformed-header-sdp-k": module.params["sip_malformed_header_sdp_k"],
            "malformed-header-sdp-m": module.params["sip_malformed_header_sdp_m"],
            "malformed-header-sdp-o": module.params["sip_malformed_header_sdp_o"],
            "malformed-header-sdp-r": module.params["sip_malformed_header_sdp_r"],
            "malformed-header-sdp-s": module.params["sip_malformed_header_sdp_s"],
            "malformed-header-sdp-t": module.params["sip_malformed_header_sdp_t"],
            "malformed-header-sdp-v": module.params["sip_malformed_header_sdp_v"],
            "malformed-header-sdp-z": module.params["sip_malformed_header_sdp_z"],
            "malformed-header-to": module.params["sip_malformed_header_to"],
            "malformed-header-via": module.params["sip_malformed_header_via"],
            "malformed-request-line": module.params["sip_malformed_request_line"],
            "max-body-length": module.params["sip_max_body_length"],
            "max-dialogs": module.params["sip_max_dialogs"],
            "max-idle-dialogs": module.params["sip_max_idle_dialogs"],
            "max-line-length": module.params["sip_max_line_length"],
            "message-rate": module.params["sip_message_rate"],
            "nat-trace": module.params["sip_nat_trace"],
            "no-sdp-fixup": module.params["sip_no_sdp_fixup"],
            "notify-rate": module.params["sip_notify_rate"],
            "open-contact-pinhole": module.params["sip_open_contact_pinhole"],
            "open-record-route-pinhole": module.params["sip_open_record_route_pinhole"],
            "open-register-pinhole": module.params["sip_open_register_pinhole"],
            "open-via-pinhole": module.params["sip_open_via_pinhole"],
            "options-rate": module.params["sip_options_rate"],
            "prack-rate": module.params["sip_prack_rate"],
            "preserve-override": module.params["sip_preserve_override"],
            "provisional-invite-expiry-time": module.params["sip_provisional_invite_expiry_time"],
            "publish-rate": module.params["sip_publish_rate"],
            "refer-rate": module.params["sip_refer_rate"],
            "register-contact-trace": module.params["sip_register_contact_trace"],
            "register-rate": module.params["sip_register_rate"],
            "rfc2543-branch": module.params["sip_rfc2543_branch"],
            "rtp": module.params["sip_rtp"],
            "ssl-algorithm": module.params["sip_ssl_algorithm"],
            "ssl-auth-client": module.params["sip_ssl_auth_client"],
            "ssl-auth-server": module.params["sip_ssl_auth_server"],
            "ssl-client-certificate": module.params["sip_ssl_client_certificate"],
            "ssl-client-renegotiation": module.params["sip_ssl_client_renegotiation"],
            "ssl-max-version": module.params["sip_ssl_max_version"],
            "ssl-min-version": module.params["sip_ssl_min_version"],
            "ssl-mode": module.params["sip_ssl_mode"],
            "ssl-pfs": module.params["sip_ssl_pfs"],
            "ssl-send-empty-frags": module.params["sip_ssl_send_empty_frags"],
            "ssl-server-certificate": module.params["sip_ssl_server_certificate"],
            "status": module.params["sip_status"],
            "strict-register": module.params["sip_strict_register"],
            "subscribe-rate": module.params["sip_subscribe_rate"],
            "unknown-header": module.params["sip_unknown_header"],
            "update-rate": module.params["sip_update_rate"],
        }
    }

    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['sccp', 'sip']
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)
    module.paramgram = paramgram

    results = DEFAULT_RESULT_OBJ
    try:

        results = fmgr_voip_profile_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_secprof_waf

Metadata

Name: fmgr_secprof_waf

Description: Manage web application firewall security profiles for FGTs via FMG

Author(s):

  • Luke Weighall (github: @lweighall)
  • Andrew Welsh (github: @Ghilli3)
  • Jim Huber (github: @p4r4n0y1ng)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Andrew Welsh

Module Github Link

Parameters
address_list
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

address_list_blocked_address
  • Description: Blocked address.
  • Required: False
address_list_blocked_log
  • Description: Enable/disable logging on blocked addresses.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

address_list_severity
  • Description: Severity.

    choice | low | Low severity.

    choice | medium | Medium severity.

    choice | high | High severity.

  • Required: False

  • choices: [‘low’, ‘medium’, ‘high’]

address_list_status
  • Description: Status.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

address_list_trusted_address
  • Description: Trusted address.
  • Required: False
adom
  • Description: The ADOM the configuration should belong to.
  • Required: False
  • default: root
comment
  • Description: Comment.
  • Required: False
constraint
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

constraint_content_length_action
  • Description: Action.

    choice | allow | Allow.

    choice | block | Block.

  • Required: False

  • choices: [‘allow’, ‘block’]

constraint_content_length_length
  • Description: Length of HTTP content in bytes (0 to 2147483647).
  • Required: False
constraint_content_length_log
  • Description: Enable/disable logging.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_content_length_severity
  • Description: Severity.

    choice | low | Low severity.

    choice | medium | Medium severity.

    choice | high | High severity.

  • Required: False

  • choices: [‘low’, ‘medium’, ‘high’]

constraint_content_length_status
  • Description: Enable/disable the constraint.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_exception_address
  • Description: Host address.
  • Required: False
constraint_exception_content_length
  • Description: HTTP content length in request.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_exception_header_length
  • Description: HTTP header length in request.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_exception_hostname
  • Description: Enable/disable hostname check.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_exception_line_length
  • Description: HTTP line length in request.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_exception_malformed
  • Description: Enable/disable malformed HTTP request check.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_exception_max_header_line
  • Description: Maximum number of HTTP header line.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_exception_max_range_segment
  • Description: Maximum number of range segments in HTTP range line.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_exception_max_url_param
  • Description: Maximum number of parameters in URL.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_exception_method
  • Description: Enable/disable HTTP method check.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_exception_param_length
  • Description: Maximum length of parameter in URL, HTTP POST request or HTTP body.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_exception_pattern
  • Description: URL pattern.
  • Required: False
constraint_exception_regex
  • Description: Enable/disable regular expression based pattern match.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_exception_url_param_length
  • Description: Maximum length of parameter in URL.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_exception_version
  • Description: Enable/disable HTTP version check.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_header_length_action
  • Description: Action.

    choice | allow | Allow.

    choice | block | Block.

  • Required: False

  • choices: [‘allow’, ‘block’]

constraint_header_length_length
  • Description: Length of HTTP header in bytes (0 to 2147483647).
  • Required: False
constraint_header_length_log
  • Description: Enable/disable logging.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_header_length_severity
  • Description: Severity.

    choice | low | Low severity.

    choice | medium | Medium severity.

    choice | high | High severity.

  • Required: False

  • choices: [‘low’, ‘medium’, ‘high’]

constraint_header_length_status
  • Description: Enable/disable the constraint.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_hostname_action
  • Description: Action for a hostname constraint.

    choice | allow | Allow.

    choice | block | Block.

  • Required: False

  • choices: [‘allow’, ‘block’]

constraint_hostname_log
  • Description: Enable/disable logging.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_hostname_severity
  • Description: Severity.

    choice | low | Low severity.

    choice | medium | Medium severity.

    choice | high | High severity.

  • Required: False

  • choices: [‘low’, ‘medium’, ‘high’]

constraint_hostname_status
  • Description: Enable/disable the constraint.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_line_length_action
  • Description: Action.

    choice | allow | Allow.

    choice | block | Block.

  • Required: False

  • choices: [‘allow’, ‘block’]

constraint_line_length_length
  • Description: Length of HTTP line in bytes (0 to 2147483647).
  • Required: False
constraint_line_length_log
  • Description: Enable/disable logging.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_line_length_severity
  • Description: Severity.

    choice | low | Low severity.

    choice | medium | Medium severity.

    choice | high | High severity.

  • Required: False

  • choices: [‘low’, ‘medium’, ‘high’]

constraint_line_length_status
  • Description: Enable/disable the constraint.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_malformed_action
  • Description: Action.

    choice | allow | Allow.

    choice | block | Block.

  • Required: False

  • choices: [‘allow’, ‘block’]

constraint_malformed_log
  • Description: Enable/disable logging.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_malformed_severity
  • Description: Severity.

    choice | low | Low severity.

    choice | medium | Medium severity.

    choice | high | High severity.

  • Required: False

  • choices: [‘low’, ‘medium’, ‘high’]

constraint_malformed_status
  • Description: Enable/disable the constraint.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_max_header_line_action
  • Description: Action.

    choice | allow | Allow.

    choice | block | Block.

  • Required: False

  • choices: [‘allow’, ‘block’]

constraint_max_header_line_log
  • Description: Enable/disable logging.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_max_header_line_max_header_line
  • Description: Maximum number HTTP header lines (0 to 2147483647).
  • Required: False
constraint_max_header_line_severity
  • Description: Severity.

    choice | low | Low severity.

    choice | medium | Medium severity.

    choice | high | High severity.

  • Required: False

  • choices: [‘low’, ‘medium’, ‘high’]

constraint_max_header_line_status
  • Description: Enable/disable the constraint.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_max_range_segment_action
  • Description: Action.

    choice | allow | Allow.

    choice | block | Block.

  • Required: False

  • choices: [‘allow’, ‘block’]

constraint_max_range_segment_log
  • Description: Enable/disable logging.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_max_range_segment_max_range_segment
  • Description: Maximum number of range segments in HTTP range line (0 to 2147483647).
  • Required: False
constraint_max_range_segment_severity
  • Description: Severity.

    choice | low | Low severity.

    choice | medium | Medium severity.

    choice | high | High severity.

  • Required: False

  • choices: [‘low’, ‘medium’, ‘high’]

constraint_max_range_segment_status
  • Description: Enable/disable the constraint.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_max_url_param_action
  • Description: Action.

    choice | allow | Allow.

    choice | block | Block.

  • Required: False

  • choices: [‘allow’, ‘block’]

constraint_max_url_param_log
  • Description: Enable/disable logging.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_max_url_param_max_url_param
  • Description: Maximum number of parameters in URL (0 to 2147483647).
  • Required: False
constraint_max_url_param_severity
  • Description: Severity.

    choice | low | Low severity.

    choice | medium | Medium severity.

    choice | high | High severity.

  • Required: False

  • choices: [‘low’, ‘medium’, ‘high’]

constraint_max_url_param_status
  • Description: Enable/disable the constraint.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_method_action
  • Description: Action.

    choice | allow | Allow.

    choice | block | Block.

  • Required: False

  • choices: [‘allow’, ‘block’]

constraint_method_log
  • Description: Enable/disable logging.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_method_severity
  • Description: Severity.

    choice | low | Low severity.

    choice | medium | Medium severity.

    choice | high | High severity.

  • Required: False

  • choices: [‘low’, ‘medium’, ‘high’]

constraint_method_status
  • Description: Enable/disable the constraint.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_param_length_action
  • Description: Action.

    choice | allow | Allow.

    choice | block | Block.

  • Required: False

  • choices: [‘allow’, ‘block’]

constraint_param_length_length
  • Description: Maximum length of parameter in URL, HTTP POST request or HTTP body in bytes (0 to 2147483647).
  • Required: False
constraint_param_length_log
  • Description: Enable/disable logging.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_param_length_severity
  • Description: Severity.

    choice | low | Low severity.

    choice | medium | Medium severity.

    choice | high | High severity.

  • Required: False

  • choices: [‘low’, ‘medium’, ‘high’]

constraint_param_length_status
  • Description: Enable/disable the constraint.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_url_param_length_action
  • Description: Action.

    choice | allow | Allow.

    choice | block | Block.

  • Required: False

  • choices: [‘allow’, ‘block’]

constraint_url_param_length_length
  • Description: Maximum length of URL parameter in bytes (0 to 2147483647).
  • Required: False
constraint_url_param_length_log
  • Description: Enable/disable logging.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_url_param_length_severity
  • Description: Severity.

    choice | low | Low severity.

    choice | medium | Medium severity.

    choice | high | High severity.

  • Required: False

  • choices: [‘low’, ‘medium’, ‘high’]

constraint_url_param_length_status
  • Description: Enable/disable the constraint.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_version_action
  • Description: Action.

    choice | allow | Allow.

    choice | block | Block.

  • Required: False

  • choices: [‘allow’, ‘block’]

constraint_version_log
  • Description: Enable/disable logging.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

constraint_version_severity
  • Description: Severity.

    choice | low | Low severity.

    choice | medium | Medium severity.

    choice | high | High severity.

  • Required: False

  • choices: [‘low’, ‘medium’, ‘high’]

constraint_version_status
  • Description: Enable/disable the constraint.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

extended_log
  • Description: Enable/disable extended logging.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

external
  • Description: Disable/Enable external HTTP Inspection.

    choice | disable | Disable external inspection.

    choice | enable | Enable external inspection.

  • Required: False

  • choices: [‘disable’, ‘enable’]

method
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

method_default_allowed_methods
  • Description: Methods.

    FLAG Based Options. Specify multiple in list form.

    flag | delete | HTTP DELETE method.

    flag | get | HTTP GET method.

    flag | head | HTTP HEAD method.

    flag | options | HTTP OPTIONS method.

    flag | post | HTTP POST method.

    flag | put | HTTP PUT method.

    flag | trace | HTTP TRACE method.

    flag | others | Other HTTP methods.

    flag | connect | HTTP CONNECT method.

  • Required: False

  • choices: [‘delete’, ‘get’, ‘head’, ‘options’, ‘post’, ‘put’, ‘trace’, ‘others’, ‘connect’]

method_log
  • Description: Enable/disable logging.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

method_method_policy_address
  • Description: Host address.
  • Required: False
method_method_policy_allowed_methods
  • Description: Allowed Methods.

    FLAG Based Options. Specify multiple in list form.

    flag | delete | HTTP DELETE method.

    flag | get | HTTP GET method.

    flag | head | HTTP HEAD method.

    flag | options | HTTP OPTIONS method.

    flag | post | HTTP POST method.

    flag | put | HTTP PUT method.

    flag | trace | HTTP TRACE method.

    flag | others | Other HTTP methods.

    flag | connect | HTTP CONNECT method.

  • Required: False

  • choices: [‘delete’, ‘get’, ‘head’, ‘options’, ‘post’, ‘put’, ‘trace’, ‘others’, ‘connect’]

method_method_policy_pattern
  • Description: URL pattern.
  • Required: False
method_method_policy_regex
  • Description: Enable/disable regular expression based pattern match.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

method_severity
  • Description: Severity.

    choice | low | low severity

    choice | medium | medium severity

    choice | high | High severity

  • Required: False

  • choices: [‘low’, ‘medium’, ‘high’]

method_status
  • Description: Status.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

mode
  • Description: Sets one of three modes for managing the object.

    Allows use of soft-adds instead of overwriting existing values

  • Required: False

  • default: add

  • choices: [‘add’, ‘set’, ‘delete’, ‘update’]

name
  • Description: WAF Profile name.
  • Required: False
signature
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

signature_credit_card_detection_threshold
  • Description: The minimum number of Credit cards to detect violation.
  • Required: False
signature_custom_signature_action
  • Description: Action.

    choice | allow | Allow.

    choice | block | Block.

    choice | erase | Erase credit card numbers.

  • Required: False

  • choices: [‘allow’, ‘block’, ‘erase’]

signature_custom_signature_case_sensitivity
  • Description: Case sensitivity in pattern.

    choice | disable | Case insensitive in pattern.

    choice | enable | Case sensitive in pattern.

  • Required: False

  • choices: [‘disable’, ‘enable’]

signature_custom_signature_direction
  • Description: Traffic direction.

    choice | request | Match HTTP request.

    choice | response | Match HTTP response.

  • Required: False

  • choices: [‘request’, ‘response’]

signature_custom_signature_log
  • Description: Enable/disable logging.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

signature_custom_signature_name
  • Description: Signature name.
  • Required: False
signature_custom_signature_pattern
  • Description: Match pattern.
  • Required: False
signature_custom_signature_severity
  • Description: Severity.

    choice | low | Low severity.

    choice | medium | Medium severity.

    choice | high | High severity.

  • Required: False

  • choices: [‘low’, ‘medium’, ‘high’]

signature_custom_signature_status
  • Description: Status.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

signature_custom_signature_target
  • Description: Match HTTP target.

    FLAG Based Options. Specify multiple in list form.

    flag | arg | HTTP arguments.

    flag | arg-name | Names of HTTP arguments.

    flag | req-body | HTTP request body.

    flag | req-cookie | HTTP request cookies.

    flag | req-cookie-name | HTTP request cookie names.

    flag | req-filename | HTTP request file name.

    flag | req-header | HTTP request headers.

    flag | req-header-name | HTTP request header names.

    flag | req-raw-uri | Raw URI of HTTP request.

    flag | req-uri | URI of HTTP request.

    flag | resp-body | HTTP response body.

    flag | resp-hdr | HTTP response headers.

    flag | resp-status | HTTP response status.

  • Required: False

  • choices: [‘arg’, ‘arg-name’, ‘req-body’, ‘req-cookie’, ‘req-cookie-name’, ‘req-filename’, ‘req-header’, ‘req-header-name’, ‘req-raw-uri’, ‘req-uri’, ‘resp-body’, ‘resp-hdr’, ‘resp-status’]

signature_disabled_signature
  • Description: Disabled signatures
  • Required: False
signature_disabled_sub_class
  • Description: Disabled signature subclasses.
  • Required: False
signature_main_class_action
  • Description: Action.

    choice | allow | Allow.

    choice | block | Block.

    choice | erase | Erase credit card numbers.

  • Required: False

  • choices: [‘allow’, ‘block’, ‘erase’]

signature_main_class_log
  • Description: Enable/disable logging.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

signature_main_class_severity
  • Description: Severity.

    choice | low | Low severity.

    choice | medium | Medium severity.

    choice | high | High severity.

  • Required: False

  • choices: [‘low’, ‘medium’, ‘high’]

signature_main_class_status
  • Description: Status.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

url_access
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

url_access_access_pattern_negate
  • Description: Enable/disable match negation.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

url_access_access_pattern_pattern
  • Description: URL pattern.
  • Required: False
url_access_access_pattern_regex
  • Description: Enable/disable regular expression based pattern match.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

url_access_access_pattern_srcaddr
  • Description: Source address.
  • Required: False
url_access_action
  • Description: Action.

    choice | bypass | Allow the HTTP request, also bypass further WAF scanning.

    choice | permit | Allow the HTTP request, and continue further WAF scanning.

    choice | block | Block HTTP request.

  • Required: False

  • choices: [‘bypass’, ‘permit’, ‘block’]

url_access_address
  • Description: Host address.
  • Required: False
url_access_log
  • Description: Enable/disable logging.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

url_access_severity
  • Description: Severity.

    choice | low | Low severity.

    choice | medium | Medium severity.

    choice | high | High severity.

  • Required: False

  • choices: [‘low’, ‘medium’, ‘high’]

Functions
  • fmgr_waf_profile_modify
def fmgr_waf_profile_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    mode = paramgram["mode"]
    adom = paramgram["adom"]
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/waf/profile'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/waf/profile/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])

    return response


#############
# END METHODS
#############
  • main
def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        name=dict(required=False, type="str"),
        external=dict(required=False, type="str", choices=["disable", "enable"]),
        extended_log=dict(required=False, type="str", choices=["disable", "enable"]),
        comment=dict(required=False, type="str"),
        address_list=dict(required=False, type="list"),
        address_list_blocked_address=dict(required=False, type="str"),
        address_list_blocked_log=dict(required=False, type="str", choices=["disable", "enable"]),
        address_list_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        address_list_status=dict(required=False, type="str", choices=["disable", "enable"]),
        address_list_trusted_address=dict(required=False, type="str"),
        constraint=dict(required=False, type="list"),

        constraint_content_length_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_content_length_length=dict(required=False, type="int"),
        constraint_content_length_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_content_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_content_length_status=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_exception_address=dict(required=False, type="str"),
        constraint_exception_content_length=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_header_length=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_hostname=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_line_length=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_malformed=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_max_cookie=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_max_header_line=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_max_range_segment=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_max_url_param=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_method=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_param_length=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_pattern=dict(required=False, type="str"),
        constraint_exception_regex=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_url_param_length=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_version=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_header_length_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_header_length_length=dict(required=False, type="int"),
        constraint_header_length_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_header_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_header_length_status=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_hostname_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_hostname_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_hostname_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_hostname_status=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_line_length_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_line_length_length=dict(required=False, type="int"),
        constraint_line_length_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_line_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_line_length_status=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_malformed_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_malformed_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_malformed_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_malformed_status=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_max_cookie_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_max_cookie_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_max_cookie_max_cookie=dict(required=False, type="int"),
        constraint_max_cookie_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_max_cookie_status=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_max_header_line_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_max_header_line_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_max_header_line_max_header_line=dict(required=False, type="int"),
        constraint_max_header_line_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_max_header_line_status=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_max_range_segment_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_max_range_segment_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_max_range_segment_max_range_segment=dict(required=False, type="int"),
        constraint_max_range_segment_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_max_range_segment_status=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_max_url_param_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_max_url_param_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_max_url_param_max_url_param=dict(required=False, type="int"),
        constraint_max_url_param_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_max_url_param_status=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_method_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_method_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_method_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_method_status=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_param_length_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_param_length_length=dict(required=False, type="int"),
        constraint_param_length_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_param_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_param_length_status=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_url_param_length_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_url_param_length_length=dict(required=False, type="int"),
        constraint_url_param_length_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_url_param_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_url_param_length_status=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_version_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_version_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_version_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_version_status=dict(required=False, type="str", choices=["disable", "enable"]),
        method=dict(required=False, type="list"),
        method_default_allowed_methods=dict(required=False, type="str", choices=["delete",
                                                                                 "get",
                                                                                 "head",
                                                                                 "options",
                                                                                 "post",
                                                                                 "put",
                                                                                 "trace",
                                                                                 "others",
                                                                                 "connect"]),
        method_log=dict(required=False, type="str", choices=["disable", "enable"]),
        method_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        method_status=dict(required=False, type="str", choices=["disable", "enable"]),

        method_method_policy_address=dict(required=False, type="str"),
        method_method_policy_allowed_methods=dict(required=False, type="str", choices=["delete",
                                                                                       "get",
                                                                                       "head",
                                                                                       "options",
                                                                                       "post",
                                                                                       "put",
                                                                                       "trace",
                                                                                       "others",
                                                                                       "connect"]),
        method_method_policy_pattern=dict(required=False, type="str"),
        method_method_policy_regex=dict(required=False, type="str", choices=["disable", "enable"]),
        signature=dict(required=False, type="list"),
        signature_credit_card_detection_threshold=dict(required=False, type="int"),
        signature_disabled_signature=dict(required=False, type="str"),
        signature_disabled_sub_class=dict(required=False, type="str"),

        signature_custom_signature_action=dict(required=False, type="str", choices=["allow", "block", "erase"]),
        signature_custom_signature_case_sensitivity=dict(required=False, type="str", choices=["disable", "enable"]),
        signature_custom_signature_direction=dict(required=False, type="str", choices=["request", "response"]),
        signature_custom_signature_log=dict(required=False, type="str", choices=["disable", "enable"]),
        signature_custom_signature_name=dict(required=False, type="str"),
        signature_custom_signature_pattern=dict(required=False, type="str"),
        signature_custom_signature_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        signature_custom_signature_status=dict(required=False, type="str", choices=["disable", "enable"]),
        signature_custom_signature_target=dict(required=False, type="str", choices=["arg",
                                                                                    "arg-name",
                                                                                    "req-body",
                                                                                    "req-cookie",
                                                                                    "req-cookie-name",
                                                                                    "req-filename",
                                                                                    "req-header",
                                                                                    "req-header-name",
                                                                                    "req-raw-uri",
                                                                                    "req-uri",
                                                                                    "resp-body",
                                                                                    "resp-hdr",
                                                                                    "resp-status"]),

        signature_main_class_action=dict(required=False, type="str", choices=["allow", "block", "erase"]),
        signature_main_class_log=dict(required=False, type="str", choices=["disable", "enable"]),
        signature_main_class_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        signature_main_class_status=dict(required=False, type="str", choices=["disable", "enable"]),
        url_access=dict(required=False, type="list"),
        url_access_action=dict(required=False, type="str", choices=["bypass", "permit", "block"]),
        url_access_address=dict(required=False, type="str"),
        url_access_log=dict(required=False, type="str", choices=["disable", "enable"]),
        url_access_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),

        url_access_access_pattern_negate=dict(required=False, type="str", choices=["disable", "enable"]),
        url_access_access_pattern_pattern=dict(required=False, type="str"),
        url_access_access_pattern_regex=dict(required=False, type="str", choices=["disable", "enable"]),
        url_access_access_pattern_srcaddr=dict(required=False, type="str"),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "name": module.params["name"],
        "external": module.params["external"],
        "extended-log": module.params["extended_log"],
        "comment": module.params["comment"],
        "address-list": {
            "blocked-address": module.params["address_list_blocked_address"],
            "blocked-log": module.params["address_list_blocked_log"],
            "severity": module.params["address_list_severity"],
            "status": module.params["address_list_status"],
            "trusted-address": module.params["address_list_trusted_address"],
        },
        "constraint": {
            "content-length": {
                "action": module.params["constraint_content_length_action"],
                "length": module.params["constraint_content_length_length"],
                "log": module.params["constraint_content_length_log"],
                "severity": module.params["constraint_content_length_severity"],
                "status": module.params["constraint_content_length_status"],
            },
            "exception": {
                "address": module.params["constraint_exception_address"],
                "content-length": module.params["constraint_exception_content_length"],
                "header-length": module.params["constraint_exception_header_length"],
                "hostname": module.params["constraint_exception_hostname"],
                "line-length": module.params["constraint_exception_line_length"],
                "malformed": module.params["constraint_exception_malformed"],
                "max-cookie": module.params["constraint_exception_max_cookie"],
                "max-header-line": module.params["constraint_exception_max_header_line"],
                "max-range-segment": module.params["constraint_exception_max_range_segment"],
                "max-url-param": module.params["constraint_exception_max_url_param"],
                "method": module.params["constraint_exception_method"],
                "param-length": module.params["constraint_exception_param_length"],
                "pattern": module.params["constraint_exception_pattern"],
                "regex": module.params["constraint_exception_regex"],
                "url-param-length": module.params["constraint_exception_url_param_length"],
                "version": module.params["constraint_exception_version"],
            },
            "header-length": {
                "action": module.params["constraint_header_length_action"],
                "length": module.params["constraint_header_length_length"],
                "log": module.params["constraint_header_length_log"],
                "severity": module.params["constraint_header_length_severity"],
                "status": module.params["constraint_header_length_status"],
            },
            "hostname": {
                "action": module.params["constraint_hostname_action"],
                "log": module.params["constraint_hostname_log"],
                "severity": module.params["constraint_hostname_severity"],
                "status": module.params["constraint_hostname_status"],
            },
            "line-length": {
                "action": module.params["constraint_line_length_action"],
                "length": module.params["constraint_line_length_length"],
                "log": module.params["constraint_line_length_log"],
                "severity": module.params["constraint_line_length_severity"],
                "status": module.params["constraint_line_length_status"],
            },
            "malformed": {
                "action": module.params["constraint_malformed_action"],
                "log": module.params["constraint_malformed_log"],
                "severity": module.params["constraint_malformed_severity"],
                "status": module.params["constraint_malformed_status"],
            },
            "max-cookie": {
                "action": module.params["constraint_max_cookie_action"],
                "log": module.params["constraint_max_cookie_log"],
                "max-cookie": module.params["constraint_max_cookie_max_cookie"],
                "severity": module.params["constraint_max_cookie_severity"],
                "status": module.params["constraint_max_cookie_status"],
            },
            "max-header-line": {
                "action": module.params["constraint_max_header_line_action"],
                "log": module.params["constraint_max_header_line_log"],
                "max-header-line": module.params["constraint_max_header_line_max_header_line"],
                "severity": module.params["constraint_max_header_line_severity"],
                "status": module.params["constraint_max_header_line_status"],
            },
            "max-range-segment": {
                "action": module.params["constraint_max_range_segment_action"],
                "log": module.params["constraint_max_range_segment_log"],
                "max-range-segment": module.params["constraint_max_range_segment_max_range_segment"],
                "severity": module.params["constraint_max_range_segment_severity"],
                "status": module.params["constraint_max_range_segment_status"],
            },
            "max-url-param": {
                "action": module.params["constraint_max_url_param_action"],
                "log": module.params["constraint_max_url_param_log"],
                "max-url-param": module.params["constraint_max_url_param_max_url_param"],
                "severity": module.params["constraint_max_url_param_severity"],
                "status": module.params["constraint_max_url_param_status"],
            },
            "method": {
                "action": module.params["constraint_method_action"],
                "log": module.params["constraint_method_log"],
                "severity": module.params["constraint_method_severity"],
                "status": module.params["constraint_method_status"],
            },
            "param-length": {
                "action": module.params["constraint_param_length_action"],
                "length": module.params["constraint_param_length_length"],
                "log": module.params["constraint_param_length_log"],
                "severity": module.params["constraint_param_length_severity"],
                "status": module.params["constraint_param_length_status"],
            },
            "url-param-length": {
                "action": module.params["constraint_url_param_length_action"],
                "length": module.params["constraint_url_param_length_length"],
                "log": module.params["constraint_url_param_length_log"],
                "severity": module.params["constraint_url_param_length_severity"],
                "status": module.params["constraint_url_param_length_status"],
            },
            "version": {
                "action": module.params["constraint_version_action"],
                "log": module.params["constraint_version_log"],
                "severity": module.params["constraint_version_severity"],
                "status": module.params["constraint_version_status"],
            },
        },
        "method": {
            "default-allowed-methods": module.params["method_default_allowed_methods"],
            "log": module.params["method_log"],
            "severity": module.params["method_severity"],
            "status": module.params["method_status"],
            "method-policy": {
                "address": module.params["method_method_policy_address"],
                "allowed-methods": module.params["method_method_policy_allowed_methods"],
                "pattern": module.params["method_method_policy_pattern"],
                "regex": module.params["method_method_policy_regex"],
            },
        },
        "signature": {
            "credit-card-detection-threshold": module.params["signature_credit_card_detection_threshold"],
            "disabled-signature": module.params["signature_disabled_signature"],
            "disabled-sub-class": module.params["signature_disabled_sub_class"],
            "custom-signature": {
                "action": module.params["signature_custom_signature_action"],
                "case-sensitivity": module.params["signature_custom_signature_case_sensitivity"],
                "direction": module.params["signature_custom_signature_direction"],
                "log": module.params["signature_custom_signature_log"],
                "name": module.params["signature_custom_signature_name"],
                "pattern": module.params["signature_custom_signature_pattern"],
                "severity": module.params["signature_custom_signature_severity"],
                "status": module.params["signature_custom_signature_status"],
                "target": module.params["signature_custom_signature_target"],
            },
            "main-class": {
                "action": module.params["signature_main_class_action"],
                "log": module.params["signature_main_class_log"],
                "severity": module.params["signature_main_class_severity"],
                "status": module.params["signature_main_class_status"],
            },
        },
        "url-access": {
            "action": module.params["url_access_action"],
            "address": module.params["url_access_address"],
            "log": module.params["url_access_log"],
            "severity": module.params["url_access_severity"],
            "access-pattern": {
                "negate": module.params["url_access_access_pattern_negate"],
                "pattern": module.params["url_access_access_pattern_pattern"],
                "regex": module.params["url_access_access_pattern_regex"],
                "srcaddr": module.params["url_access_access_pattern_srcaddr"],
            }
        }
    }

    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['address-list', 'constraint', 'method', 'signature', 'url-access']
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)

    results = DEFAULT_RESULT_OBJ

    try:
        results = fmgr_waf_profile_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function

__metaclass__ = type

ANSIBLE_METADATA = {'status': ['preview'],
                    'supported_by': 'community',
                    'metadata_version': '1.1'}

DOCUMENTATION = '''
---
module: fmgr_secprof_waf
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author:
    - Luke Weighall (@lweighall)
    - Andrew Welsh (@Ghilli3)
    - Jim Huber (@p4r4n0y1ng)
short_description: FortiManager web application firewall security profile
description:
  -  Manage web application firewall security profiles for FGTs via FMG

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: false
    default: root

  mode:
    description:
      - Sets one of three modes for managing the object.
      - Allows use of soft-adds instead of overwriting existing values
    choices: ['add', 'set', 'delete', 'update']
    required: false
    default: add

  name:
    description:
      - WAF Profile name.
    required: false

  external:
    description:
      - Disable/Enable external HTTP Inspection.
      - choice | disable | Disable external inspection.
      - choice | enable | Enable external inspection.
    required: false
    choices: ["disable", "enable"]

  extended_log:
    description:
      - Enable/disable extended logging.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  comment:
    description:
      - Comment.
    required: false

  address_list:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  address_list_blocked_address:
    description:
      - Blocked address.
    required: false

  address_list_blocked_log:
    description:
      - Enable/disable logging on blocked addresses.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  address_list_severity:
    description:
      - Severity.
      - choice | low | Low severity.
      - choice | medium | Medium severity.
      - choice | high | High severity.
    required: false
    choices: ["low", "medium", "high"]

  address_list_status:
    description:
      - Status.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  address_list_trusted_address:
    description:
      - Trusted address.
    required: false

  constraint:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  constraint_content_length_action:
    description:
      - Action.
      - choice | allow | Allow.
      - choice | block | Block.
    required: false
    choices: ["allow", "block"]

  constraint_content_length_length:
    description:
      - Length of HTTP content in bytes (0 to 2147483647).
    required: false

  constraint_content_length_log:
    description:
      - Enable/disable logging.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_content_length_severity:
    description:
      - Severity.
      - choice | low | Low severity.
      - choice | medium | Medium severity.
      - choice | high | High severity.
    required: false
    choices: ["low", "medium", "high"]

  constraint_content_length_status:
    description:
      - Enable/disable the constraint.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_exception_address:
    description:
      - Host address.
    required: false

  constraint_exception_content_length:
    description:
      - HTTP content length in request.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_exception_header_length:
    description:
      - HTTP header length in request.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_exception_hostname:
    description:
      - Enable/disable hostname check.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_exception_line_length:
    description:
      - HTTP line length in request.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_exception_malformed:
    description:
      - Enable/disable malformed HTTP request check.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_exception_max_cookie:
    description:
      - Maximum number of cookies in HTTP request.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_exception_max_header_line:
    description:
      - Maximum number of HTTP header line.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_exception_max_range_segment:
    description:
      - Maximum number of range segments in HTTP range line.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_exception_max_url_param:
    description:
      - Maximum number of parameters in URL.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_exception_method:
    description:
      - Enable/disable HTTP method check.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_exception_param_length:
    description:
      - Maximum length of parameter in URL, HTTP POST request or HTTP body.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_exception_pattern:
    description:
      - URL pattern.
    required: false

  constraint_exception_regex:
    description:
      - Enable/disable regular expression based pattern match.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_exception_url_param_length:
    description:
      - Maximum length of parameter in URL.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_exception_version:
    description:
      - Enable/disable HTTP version check.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_header_length_action:
    description:
      - Action.
      - choice | allow | Allow.
      - choice | block | Block.
    required: false
    choices: ["allow", "block"]

  constraint_header_length_length:
    description:
      - Length of HTTP header in bytes (0 to 2147483647).
    required: false

  constraint_header_length_log:
    description:
      - Enable/disable logging.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_header_length_severity:
    description:
      - Severity.
      - choice | low | Low severity.
      - choice | medium | Medium severity.
      - choice | high | High severity.
    required: false
    choices: ["low", "medium", "high"]

  constraint_header_length_status:
    description:
      - Enable/disable the constraint.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_hostname_action:
    description:
      - Action for a hostname constraint.
      - choice | allow | Allow.
      - choice | block | Block.
    required: false
    choices: ["allow", "block"]

  constraint_hostname_log:
    description:
      - Enable/disable logging.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_hostname_severity:
    description:
      - Severity.
      - choice | low | Low severity.
      - choice | medium | Medium severity.
      - choice | high | High severity.
    required: false
    choices: ["low", "medium", "high"]

  constraint_hostname_status:
    description:
      - Enable/disable the constraint.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_line_length_action:
    description:
      - Action.
      - choice | allow | Allow.
      - choice | block | Block.
    required: false
    choices: ["allow", "block"]

  constraint_line_length_length:
    description:
      - Length of HTTP line in bytes (0 to 2147483647).
    required: false

  constraint_line_length_log:
    description:
      - Enable/disable logging.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_line_length_severity:
    description:
      - Severity.
      - choice | low | Low severity.
      - choice | medium | Medium severity.
      - choice | high | High severity.
    required: false
    choices: ["low", "medium", "high"]

  constraint_line_length_status:
    description:
      - Enable/disable the constraint.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_malformed_action:
    description:
      - Action.
      - choice | allow | Allow.
      - choice | block | Block.
    required: false
    choices: ["allow", "block"]

  constraint_malformed_log:
    description:
      - Enable/disable logging.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_malformed_severity:
    description:
      - Severity.
      - choice | low | Low severity.
      - choice | medium | Medium severity.
      - choice | high | High severity.
    required: false
    choices: ["low", "medium", "high"]

  constraint_malformed_status:
    description:
      - Enable/disable the constraint.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_max_cookie_action:
    description:
      - Action.
      - choice | allow | Allow.
      - choice | block | Block.
    required: false
    choices: ["allow", "block"]

  constraint_max_cookie_log:
    description:
      - Enable/disable logging.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_max_cookie_max_cookie:
    description:
      - Maximum number of cookies in HTTP request (0 to 2147483647).
    required: false

  constraint_max_cookie_severity:
    description:
      - Severity.
      - choice | low | Low severity.
      - choice | medium | Medium severity.
      - choice | high | High severity.
    required: false
    choices: ["low", "medium", "high"]

  constraint_max_cookie_status:
    description:
      - Enable/disable the constraint.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_max_header_line_action:
    description:
      - Action.
      - choice | allow | Allow.
      - choice | block | Block.
    required: false
    choices: ["allow", "block"]

  constraint_max_header_line_log:
    description:
      - Enable/disable logging.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_max_header_line_max_header_line:
    description:
      - Maximum number HTTP header lines (0 to 2147483647).
    required: false

  constraint_max_header_line_severity:
    description:
      - Severity.
      - choice | low | Low severity.
      - choice | medium | Medium severity.
      - choice | high | High severity.
    required: false
    choices: ["low", "medium", "high"]

  constraint_max_header_line_status:
    description:
      - Enable/disable the constraint.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_max_range_segment_action:
    description:
      - Action.
      - choice | allow | Allow.
      - choice | block | Block.
    required: false
    choices: ["allow", "block"]

  constraint_max_range_segment_log:
    description:
      - Enable/disable logging.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_max_range_segment_max_range_segment:
    description:
      - Maximum number of range segments in HTTP range line (0 to 2147483647).
    required: false

  constraint_max_range_segment_severity:
    description:
      - Severity.
      - choice | low | Low severity.
      - choice | medium | Medium severity.
      - choice | high | High severity.
    required: false
    choices: ["low", "medium", "high"]

  constraint_max_range_segment_status:
    description:
      - Enable/disable the constraint.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_max_url_param_action:
    description:
      - Action.
      - choice | allow | Allow.
      - choice | block | Block.
    required: false
    choices: ["allow", "block"]

  constraint_max_url_param_log:
    description:
      - Enable/disable logging.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_max_url_param_max_url_param:
    description:
      - Maximum number of parameters in URL (0 to 2147483647).
    required: false

  constraint_max_url_param_severity:
    description:
      - Severity.
      - choice | low | Low severity.
      - choice | medium | Medium severity.
      - choice | high | High severity.
    required: false
    choices: ["low", "medium", "high"]

  constraint_max_url_param_status:
    description:
      - Enable/disable the constraint.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_method_action:
    description:
      - Action.
      - choice | allow | Allow.
      - choice | block | Block.
    required: false
    choices: ["allow", "block"]

  constraint_method_log:
    description:
      - Enable/disable logging.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_method_severity:
    description:
      - Severity.
      - choice | low | Low severity.
      - choice | medium | Medium severity.
      - choice | high | High severity.
    required: false
    choices: ["low", "medium", "high"]

  constraint_method_status:
    description:
      - Enable/disable the constraint.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_param_length_action:
    description:
      - Action.
      - choice | allow | Allow.
      - choice | block | Block.
    required: false
    choices: ["allow", "block"]

  constraint_param_length_length:
    description:
      - Maximum length of parameter in URL, HTTP POST request or HTTP body in bytes (0 to 2147483647).
    required: false

  constraint_param_length_log:
    description:
      - Enable/disable logging.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_param_length_severity:
    description:
      - Severity.
      - choice | low | Low severity.
      - choice | medium | Medium severity.
      - choice | high | High severity.
    required: false
    choices: ["low", "medium", "high"]

  constraint_param_length_status:
    description:
      - Enable/disable the constraint.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_url_param_length_action:
    description:
      - Action.
      - choice | allow | Allow.
      - choice | block | Block.
    required: false
    choices: ["allow", "block"]

  constraint_url_param_length_length:
    description:
      - Maximum length of URL parameter in bytes (0 to 2147483647).
    required: false

  constraint_url_param_length_log:
    description:
      - Enable/disable logging.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_url_param_length_severity:
    description:
      - Severity.
      - choice | low | Low severity.
      - choice | medium | Medium severity.
      - choice | high | High severity.
    required: false
    choices: ["low", "medium", "high"]

  constraint_url_param_length_status:
    description:
      - Enable/disable the constraint.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_version_action:
    description:
      - Action.
      - choice | allow | Allow.
      - choice | block | Block.
    required: false
    choices: ["allow", "block"]

  constraint_version_log:
    description:
      - Enable/disable logging.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  constraint_version_severity:
    description:
      - Severity.
      - choice | low | Low severity.
      - choice | medium | Medium severity.
      - choice | high | High severity.
    required: false
    choices: ["low", "medium", "high"]

  constraint_version_status:
    description:
      - Enable/disable the constraint.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  method:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  method_default_allowed_methods:
    description:
      - Methods.
      - FLAG Based Options. Specify multiple in list form.
      - flag | delete | HTTP DELETE method.
      - flag | get | HTTP GET method.
      - flag | head | HTTP HEAD method.
      - flag | options | HTTP OPTIONS method.
      - flag | post | HTTP POST method.
      - flag | put | HTTP PUT method.
      - flag | trace | HTTP TRACE method.
      - flag | others | Other HTTP methods.
      - flag | connect | HTTP CONNECT method.
    required: false
    choices: ["delete", "get", "head", "options", "post", "put", "trace", "others", "connect"]

  method_log:
    description:
      - Enable/disable logging.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  method_severity:
    description:
      - Severity.
      - choice | low | low severity
      - choice | medium | medium severity
      - choice | high | High severity
    required: false
    choices: ["low", "medium", "high"]

  method_status:
    description:
      - Status.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  method_method_policy_address:
    description:
      - Host address.
    required: false

  method_method_policy_allowed_methods:
    description:
      - Allowed Methods.
      - FLAG Based Options. Specify multiple in list form.
      - flag | delete | HTTP DELETE method.
      - flag | get | HTTP GET method.
      - flag | head | HTTP HEAD method.
      - flag | options | HTTP OPTIONS method.
      - flag | post | HTTP POST method.
      - flag | put | HTTP PUT method.
      - flag | trace | HTTP TRACE method.
      - flag | others | Other HTTP methods.
      - flag | connect | HTTP CONNECT method.
    required: false
    choices: ["delete", "get", "head", "options", "post", "put", "trace", "others", "connect"]

  method_method_policy_pattern:
    description:
      - URL pattern.
    required: false

  method_method_policy_regex:
    description:
      - Enable/disable regular expression based pattern match.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  signature:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  signature_credit_card_detection_threshold:
    description:
      - The minimum number of Credit cards to detect violation.
    required: false

  signature_disabled_signature:
    description:
      - Disabled signatures
    required: false

  signature_disabled_sub_class:
    description:
      - Disabled signature subclasses.
    required: false

  signature_custom_signature_action:
    description:
      - Action.
      - choice | allow | Allow.
      - choice | block | Block.
      - choice | erase | Erase credit card numbers.
    required: false
    choices: ["allow", "block", "erase"]

  signature_custom_signature_case_sensitivity:
    description:
      - Case sensitivity in pattern.
      - choice | disable | Case insensitive in pattern.
      - choice | enable | Case sensitive in pattern.
    required: false
    choices: ["disable", "enable"]

  signature_custom_signature_direction:
    description:
      - Traffic direction.
      - choice | request | Match HTTP request.
      - choice | response | Match HTTP response.
    required: false
    choices: ["request", "response"]

  signature_custom_signature_log:
    description:
      - Enable/disable logging.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  signature_custom_signature_name:
    description:
      - Signature name.
    required: false

  signature_custom_signature_pattern:
    description:
      - Match pattern.
    required: false

  signature_custom_signature_severity:
    description:
      - Severity.
      - choice | low | Low severity.
      - choice | medium | Medium severity.
      - choice | high | High severity.
    required: false
    choices: ["low", "medium", "high"]

  signature_custom_signature_status:
    description:
      - Status.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  signature_custom_signature_target:
    description:
      - Match HTTP target.
      - FLAG Based Options. Specify multiple in list form.
      - flag | arg | HTTP arguments.
      - flag | arg-name | Names of HTTP arguments.
      - flag | req-body | HTTP request body.
      - flag | req-cookie | HTTP request cookies.
      - flag | req-cookie-name | HTTP request cookie names.
      - flag | req-filename | HTTP request file name.
      - flag | req-header | HTTP request headers.
      - flag | req-header-name | HTTP request header names.
      - flag | req-raw-uri | Raw URI of HTTP request.
      - flag | req-uri | URI of HTTP request.
      - flag | resp-body | HTTP response body.
      - flag | resp-hdr | HTTP response headers.
      - flag | resp-status | HTTP response status.
    required: false
    choices: ["arg","arg-name","req-body","req-cookie","req-cookie-name","req-filename","req-header","req-header-name",
      "req-raw-uri","req-uri","resp-body","resp-hdr","resp-status"]

  signature_main_class_action:
    description:
      - Action.
      - choice | allow | Allow.
      - choice | block | Block.
      - choice | erase | Erase credit card numbers.
    required: false
    choices: ["allow", "block", "erase"]

  signature_main_class_log:
    description:
      - Enable/disable logging.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  signature_main_class_severity:
    description:
      - Severity.
      - choice | low | Low severity.
      - choice | medium | Medium severity.
      - choice | high | High severity.
    required: false
    choices: ["low", "medium", "high"]

  signature_main_class_status:
    description:
      - Status.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  url_access:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  url_access_action:
    description:
      - Action.
      - choice | bypass | Allow the HTTP request, also bypass further WAF scanning.
      - choice | permit | Allow the HTTP request, and continue further WAF scanning.
      - choice | block | Block HTTP request.
    required: false
    choices: ["bypass", "permit", "block"]

  url_access_address:
    description:
      - Host address.
    required: false

  url_access_log:
    description:
      - Enable/disable logging.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  url_access_severity:
    description:
      - Severity.
      - choice | low | Low severity.
      - choice | medium | Medium severity.
      - choice | high | High severity.
    required: false
    choices: ["low", "medium", "high"]

  url_access_access_pattern_negate:
    description:
      - Enable/disable match negation.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  url_access_access_pattern_pattern:
    description:
      - URL pattern.
    required: false

  url_access_access_pattern_regex:
    description:
      - Enable/disable regular expression based pattern match.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  url_access_access_pattern_srcaddr:
    description:
      - Source address.
    required: false

'''

EXAMPLES = '''
  - name: DELETE Profile
    fmgr_secprof_waf:
      name: "Ansible_WAF_Profile"
      comment: "Created by Ansible Module TEST"
      mode: "delete"

  - name: CREATE Profile
    fmgr_secprof_waf:
      name: "Ansible_WAF_Profile"
      comment: "Created by Ansible Module TEST"
      mode: "set"
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import FMGRMethods
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
from ansible.module_utils.network.fortimanager.common import prepare_dict
from ansible.module_utils.network.fortimanager.common import scrub_dict


###############
# START METHODS
###############


def fmgr_waf_profile_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """
    mode = paramgram["mode"]
    adom = paramgram["adom"]
    # INIT A BASIC OBJECTS
    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/waf/profile'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/waf/profile/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])

    return response


#############
# END METHODS
#############


def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        name=dict(required=False, type="str"),
        external=dict(required=False, type="str", choices=["disable", "enable"]),
        extended_log=dict(required=False, type="str", choices=["disable", "enable"]),
        comment=dict(required=False, type="str"),
        address_list=dict(required=False, type="list"),
        address_list_blocked_address=dict(required=False, type="str"),
        address_list_blocked_log=dict(required=False, type="str", choices=["disable", "enable"]),
        address_list_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        address_list_status=dict(required=False, type="str", choices=["disable", "enable"]),
        address_list_trusted_address=dict(required=False, type="str"),
        constraint=dict(required=False, type="list"),

        constraint_content_length_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_content_length_length=dict(required=False, type="int"),
        constraint_content_length_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_content_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_content_length_status=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_exception_address=dict(required=False, type="str"),
        constraint_exception_content_length=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_header_length=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_hostname=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_line_length=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_malformed=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_max_cookie=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_max_header_line=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_max_range_segment=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_max_url_param=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_method=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_param_length=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_pattern=dict(required=False, type="str"),
        constraint_exception_regex=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_url_param_length=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_exception_version=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_header_length_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_header_length_length=dict(required=False, type="int"),
        constraint_header_length_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_header_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_header_length_status=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_hostname_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_hostname_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_hostname_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_hostname_status=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_line_length_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_line_length_length=dict(required=False, type="int"),
        constraint_line_length_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_line_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_line_length_status=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_malformed_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_malformed_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_malformed_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_malformed_status=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_max_cookie_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_max_cookie_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_max_cookie_max_cookie=dict(required=False, type="int"),
        constraint_max_cookie_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_max_cookie_status=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_max_header_line_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_max_header_line_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_max_header_line_max_header_line=dict(required=False, type="int"),
        constraint_max_header_line_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_max_header_line_status=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_max_range_segment_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_max_range_segment_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_max_range_segment_max_range_segment=dict(required=False, type="int"),
        constraint_max_range_segment_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_max_range_segment_status=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_max_url_param_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_max_url_param_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_max_url_param_max_url_param=dict(required=False, type="int"),
        constraint_max_url_param_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_max_url_param_status=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_method_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_method_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_method_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_method_status=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_param_length_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_param_length_length=dict(required=False, type="int"),
        constraint_param_length_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_param_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_param_length_status=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_url_param_length_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_url_param_length_length=dict(required=False, type="int"),
        constraint_url_param_length_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_url_param_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_url_param_length_status=dict(required=False, type="str", choices=["disable", "enable"]),

        constraint_version_action=dict(required=False, type="str", choices=["allow", "block"]),
        constraint_version_log=dict(required=False, type="str", choices=["disable", "enable"]),
        constraint_version_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        constraint_version_status=dict(required=False, type="str", choices=["disable", "enable"]),
        method=dict(required=False, type="list"),
        method_default_allowed_methods=dict(required=False, type="str", choices=["delete",
                                                                                 "get",
                                                                                 "head",
                                                                                 "options",
                                                                                 "post",
                                                                                 "put",
                                                                                 "trace",
                                                                                 "others",
                                                                                 "connect"]),
        method_log=dict(required=False, type="str", choices=["disable", "enable"]),
        method_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        method_status=dict(required=False, type="str", choices=["disable", "enable"]),

        method_method_policy_address=dict(required=False, type="str"),
        method_method_policy_allowed_methods=dict(required=False, type="str", choices=["delete",
                                                                                       "get",
                                                                                       "head",
                                                                                       "options",
                                                                                       "post",
                                                                                       "put",
                                                                                       "trace",
                                                                                       "others",
                                                                                       "connect"]),
        method_method_policy_pattern=dict(required=False, type="str"),
        method_method_policy_regex=dict(required=False, type="str", choices=["disable", "enable"]),
        signature=dict(required=False, type="list"),
        signature_credit_card_detection_threshold=dict(required=False, type="int"),
        signature_disabled_signature=dict(required=False, type="str"),
        signature_disabled_sub_class=dict(required=False, type="str"),

        signature_custom_signature_action=dict(required=False, type="str", choices=["allow", "block", "erase"]),
        signature_custom_signature_case_sensitivity=dict(required=False, type="str", choices=["disable", "enable"]),
        signature_custom_signature_direction=dict(required=False, type="str", choices=["request", "response"]),
        signature_custom_signature_log=dict(required=False, type="str", choices=["disable", "enable"]),
        signature_custom_signature_name=dict(required=False, type="str"),
        signature_custom_signature_pattern=dict(required=False, type="str"),
        signature_custom_signature_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        signature_custom_signature_status=dict(required=False, type="str", choices=["disable", "enable"]),
        signature_custom_signature_target=dict(required=False, type="str", choices=["arg",
                                                                                    "arg-name",
                                                                                    "req-body",
                                                                                    "req-cookie",
                                                                                    "req-cookie-name",
                                                                                    "req-filename",
                                                                                    "req-header",
                                                                                    "req-header-name",
                                                                                    "req-raw-uri",
                                                                                    "req-uri",
                                                                                    "resp-body",
                                                                                    "resp-hdr",
                                                                                    "resp-status"]),

        signature_main_class_action=dict(required=False, type="str", choices=["allow", "block", "erase"]),
        signature_main_class_log=dict(required=False, type="str", choices=["disable", "enable"]),
        signature_main_class_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
        signature_main_class_status=dict(required=False, type="str", choices=["disable", "enable"]),
        url_access=dict(required=False, type="list"),
        url_access_action=dict(required=False, type="str", choices=["bypass", "permit", "block"]),
        url_access_address=dict(required=False, type="str"),
        url_access_log=dict(required=False, type="str", choices=["disable", "enable"]),
        url_access_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),

        url_access_access_pattern_negate=dict(required=False, type="str", choices=["disable", "enable"]),
        url_access_access_pattern_pattern=dict(required=False, type="str"),
        url_access_access_pattern_regex=dict(required=False, type="str", choices=["disable", "enable"]),
        url_access_access_pattern_srcaddr=dict(required=False, type="str"),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "name": module.params["name"],
        "external": module.params["external"],
        "extended-log": module.params["extended_log"],
        "comment": module.params["comment"],
        "address-list": {
            "blocked-address": module.params["address_list_blocked_address"],
            "blocked-log": module.params["address_list_blocked_log"],
            "severity": module.params["address_list_severity"],
            "status": module.params["address_list_status"],
            "trusted-address": module.params["address_list_trusted_address"],
        },
        "constraint": {
            "content-length": {
                "action": module.params["constraint_content_length_action"],
                "length": module.params["constraint_content_length_length"],
                "log": module.params["constraint_content_length_log"],
                "severity": module.params["constraint_content_length_severity"],
                "status": module.params["constraint_content_length_status"],
            },
            "exception": {
                "address": module.params["constraint_exception_address"],
                "content-length": module.params["constraint_exception_content_length"],
                "header-length": module.params["constraint_exception_header_length"],
                "hostname": module.params["constraint_exception_hostname"],
                "line-length": module.params["constraint_exception_line_length"],
                "malformed": module.params["constraint_exception_malformed"],
                "max-cookie": module.params["constraint_exception_max_cookie"],
                "max-header-line": module.params["constraint_exception_max_header_line"],
                "max-range-segment": module.params["constraint_exception_max_range_segment"],
                "max-url-param": module.params["constraint_exception_max_url_param"],
                "method": module.params["constraint_exception_method"],
                "param-length": module.params["constraint_exception_param_length"],
                "pattern": module.params["constraint_exception_pattern"],
                "regex": module.params["constraint_exception_regex"],
                "url-param-length": module.params["constraint_exception_url_param_length"],
                "version": module.params["constraint_exception_version"],
            },
            "header-length": {
                "action": module.params["constraint_header_length_action"],
                "length": module.params["constraint_header_length_length"],
                "log": module.params["constraint_header_length_log"],
                "severity": module.params["constraint_header_length_severity"],
                "status": module.params["constraint_header_length_status"],
            },
            "hostname": {
                "action": module.params["constraint_hostname_action"],
                "log": module.params["constraint_hostname_log"],
                "severity": module.params["constraint_hostname_severity"],
                "status": module.params["constraint_hostname_status"],
            },
            "line-length": {
                "action": module.params["constraint_line_length_action"],
                "length": module.params["constraint_line_length_length"],
                "log": module.params["constraint_line_length_log"],
                "severity": module.params["constraint_line_length_severity"],
                "status": module.params["constraint_line_length_status"],
            },
            "malformed": {
                "action": module.params["constraint_malformed_action"],
                "log": module.params["constraint_malformed_log"],
                "severity": module.params["constraint_malformed_severity"],
                "status": module.params["constraint_malformed_status"],
            },
            "max-cookie": {
                "action": module.params["constraint_max_cookie_action"],
                "log": module.params["constraint_max_cookie_log"],
                "max-cookie": module.params["constraint_max_cookie_max_cookie"],
                "severity": module.params["constraint_max_cookie_severity"],
                "status": module.params["constraint_max_cookie_status"],
            },
            "max-header-line": {
                "action": module.params["constraint_max_header_line_action"],
                "log": module.params["constraint_max_header_line_log"],
                "max-header-line": module.params["constraint_max_header_line_max_header_line"],
                "severity": module.params["constraint_max_header_line_severity"],
                "status": module.params["constraint_max_header_line_status"],
            },
            "max-range-segment": {
                "action": module.params["constraint_max_range_segment_action"],
                "log": module.params["constraint_max_range_segment_log"],
                "max-range-segment": module.params["constraint_max_range_segment_max_range_segment"],
                "severity": module.params["constraint_max_range_segment_severity"],
                "status": module.params["constraint_max_range_segment_status"],
            },
            "max-url-param": {
                "action": module.params["constraint_max_url_param_action"],
                "log": module.params["constraint_max_url_param_log"],
                "max-url-param": module.params["constraint_max_url_param_max_url_param"],
                "severity": module.params["constraint_max_url_param_severity"],
                "status": module.params["constraint_max_url_param_status"],
            },
            "method": {
                "action": module.params["constraint_method_action"],
                "log": module.params["constraint_method_log"],
                "severity": module.params["constraint_method_severity"],
                "status": module.params["constraint_method_status"],
            },
            "param-length": {
                "action": module.params["constraint_param_length_action"],
                "length": module.params["constraint_param_length_length"],
                "log": module.params["constraint_param_length_log"],
                "severity": module.params["constraint_param_length_severity"],
                "status": module.params["constraint_param_length_status"],
            },
            "url-param-length": {
                "action": module.params["constraint_url_param_length_action"],
                "length": module.params["constraint_url_param_length_length"],
                "log": module.params["constraint_url_param_length_log"],
                "severity": module.params["constraint_url_param_length_severity"],
                "status": module.params["constraint_url_param_length_status"],
            },
            "version": {
                "action": module.params["constraint_version_action"],
                "log": module.params["constraint_version_log"],
                "severity": module.params["constraint_version_severity"],
                "status": module.params["constraint_version_status"],
            },
        },
        "method": {
            "default-allowed-methods": module.params["method_default_allowed_methods"],
            "log": module.params["method_log"],
            "severity": module.params["method_severity"],
            "status": module.params["method_status"],
            "method-policy": {
                "address": module.params["method_method_policy_address"],
                "allowed-methods": module.params["method_method_policy_allowed_methods"],
                "pattern": module.params["method_method_policy_pattern"],
                "regex": module.params["method_method_policy_regex"],
            },
        },
        "signature": {
            "credit-card-detection-threshold": module.params["signature_credit_card_detection_threshold"],
            "disabled-signature": module.params["signature_disabled_signature"],
            "disabled-sub-class": module.params["signature_disabled_sub_class"],
            "custom-signature": {
                "action": module.params["signature_custom_signature_action"],
                "case-sensitivity": module.params["signature_custom_signature_case_sensitivity"],
                "direction": module.params["signature_custom_signature_direction"],
                "log": module.params["signature_custom_signature_log"],
                "name": module.params["signature_custom_signature_name"],
                "pattern": module.params["signature_custom_signature_pattern"],
                "severity": module.params["signature_custom_signature_severity"],
                "status": module.params["signature_custom_signature_status"],
                "target": module.params["signature_custom_signature_target"],
            },
            "main-class": {
                "action": module.params["signature_main_class_action"],
                "log": module.params["signature_main_class_log"],
                "severity": module.params["signature_main_class_severity"],
                "status": module.params["signature_main_class_status"],
            },
        },
        "url-access": {
            "action": module.params["url_access_action"],
            "address": module.params["url_access_address"],
            "log": module.params["url_access_log"],
            "severity": module.params["url_access_severity"],
            "access-pattern": {
                "negate": module.params["url_access_access_pattern_negate"],
                "pattern": module.params["url_access_access_pattern_pattern"],
                "regex": module.params["url_access_access_pattern_regex"],
                "srcaddr": module.params["url_access_access_pattern_srcaddr"],
            }
        }
    }

    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['address-list', 'constraint', 'method', 'signature', 'url-access']
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)

    results = DEFAULT_RESULT_OBJ

    try:
        results = fmgr_waf_profile_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_secprof_wanopt

Metadata

Name: fmgr_secprof_wanopt

Description: Manage WanOpt security profiles in FortiManager via API

Author(s):

  • Luke Weighall (github: @lweighall)
  • Andrew Welsh (github: @Ghilli3)
  • Jim Huber (github: @p4r4n0y1ng)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Andrew Welsh

Module Github Link

Parameters
adom
  • Description: The ADOM the configuration should belong to.
  • Required: False
  • default: root
auth_group
  • Description: Optionally add an authentication group to restrict access to the WAN Optimization tunnel to peers in the authentication group.
  • Required: False
cifs
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

cifs_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.
  • Required: False
  • choices: [‘disable’, ‘enable’]
cifs_log_traffic
  • Description: Enable/disable logging.
  • Required: False
  • choices: [‘disable’, ‘enable’]
cifs_port
  • 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.
  • Required: False
cifs_prefer_chunking
  • Description: Select dynamic or fixed-size data chunking for HTTP WAN Optimization.
  • Required: False
  • choices: [‘dynamic’, ‘fix’]
cifs_secure_tunnel
  • Description: Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the same TCP port (7810).
  • Required: False
  • choices: [‘disable’, ‘enable’]
cifs_status
  • Description: Enable/disable HTTP WAN Optimization.
  • Required: False
  • choices: [‘disable’, ‘enable’]
cifs_tunnel_sharing
  • Description: Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols.
  • Required: False
  • choices: [‘private’, ‘shared’, ‘express-shared’]
comments
  • Description: Comment.
  • Required: False
ftp
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

ftp_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.
  • Required: False
  • choices: [‘disable’, ‘enable’]
ftp_log_traffic
  • Description: Enable/disable logging.
  • Required: False
  • choices: [‘disable’, ‘enable’]
ftp_port
  • 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.
  • Required: False
ftp_prefer_chunking
  • Description: Select dynamic or fixed-size data chunking for HTTP WAN Optimization.
  • Required: False
  • choices: [‘dynamic’, ‘fix’]
ftp_secure_tunnel
  • Description: Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the same TCP port (7810).
  • Required: False
  • choices: [‘disable’, ‘enable’]
ftp_status
  • Description: Enable/disable HTTP WAN Optimization.
  • Required: False
  • choices: [‘disable’, ‘enable’]
ftp_tunnel_sharing
  • Description: Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols.
  • Required: False
  • choices: [‘private’, ‘shared’, ‘express-shared’]
http
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

http_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.
  • Required: False
  • choices: [‘disable’, ‘enable’]
http_log_traffic
  • Description: Enable/disable logging.
  • Required: False
  • choices: [‘disable’, ‘enable’]
http_port
  • 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.
  • Required: False
http_prefer_chunking
  • Description: Select dynamic or fixed-size data chunking for HTTP WAN Optimization.
  • Required: False
  • choices: [‘dynamic’, ‘fix’]
http_secure_tunnel
  • Description: Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the same TCP port (7810).
  • Required: False
  • choices: [‘disable’, ‘enable’]
http_ssl
  • Description: Enable/disable SSL/TLS offloading (hardware acceleration) for HTTPS traffic in this tunnel.
  • Required: False
  • choices: [‘disable’, ‘enable’]
http_ssl_port
  • Description: Port on which to expect HTTPS traffic for SSL/TLS offloading.
  • Required: False
http_status
  • Description: Enable/disable HTTP WAN Optimization.
  • Required: False
  • choices: [‘disable’, ‘enable’]
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.
  • Required: False
  • choices: [‘disable’, ‘enable’]
http_tunnel_sharing
  • Description: Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols.
  • Required: False
  • choices: [‘private’, ‘shared’, ‘express-shared’]
http_unknown_http_version
  • Description: How to handle HTTP sessions that do not comply with HTTP 0.9, 1.0, or 1.1.
  • Required: False
  • choices: [‘best-effort’, ‘reject’, ‘tunnel’]
mapi
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

mapi_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.
  • Required: False
  • choices: [‘disable’, ‘enable’]
mapi_log_traffic
  • Description: Enable/disable logging.
  • Required: False
  • choices: [‘disable’, ‘enable’]
mapi_port
  • 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.
  • Required: False
mapi_secure_tunnel
  • Description: Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the same TCP port (7810).
  • Required: False
  • choices: [‘disable’, ‘enable’]
mapi_status
  • Description: Enable/disable HTTP WAN Optimization.
  • Required: False
  • choices: [‘disable’, ‘enable’]
mapi_tunnel_sharing
  • Description: Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols.
  • Required: False
  • choices: [‘private’, ‘shared’, ‘express-shared’]
mode
  • Description: Sets one of three modes for managing the object.

    Allows use of soft-adds instead of overwriting existing values

  • Required: False

  • default: add

  • choices: [‘add’, ‘set’, ‘delete’, ‘update’]

name
  • Description: Profile name.
  • Required: False
tcp
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

tcp_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.
  • Required: False
  • choices: [‘disable’, ‘enable’]
tcp_byte_caching_opt
  • Description: Select whether TCP byte-caching uses system memory only or both memory and disk space.
  • Required: False
  • choices: [‘mem-only’, ‘mem-disk’]
tcp_log_traffic
  • Description: Enable/disable logging.
  • Required: False
  • choices: [‘disable’, ‘enable’]
tcp_port
  • 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.
  • Required: False
tcp_secure_tunnel
  • Description: Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the same TCP port (7810).
  • Required: False
  • choices: [‘disable’, ‘enable’]
tcp_ssl
  • Description: Enable/disable SSL/TLS offloading.
  • Required: False
  • choices: [‘disable’, ‘enable’]
tcp_ssl_port
  • Description: Port on which to expect HTTPS traffic for SSL/TLS offloading.
  • Required: False
tcp_status
  • Description: Enable/disable HTTP WAN Optimization.
  • Required: False
  • choices: [‘disable’, ‘enable’]
tcp_tunnel_sharing
  • Description: Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols.
  • Required: False
  • choices: [‘private’, ‘shared’, ‘express-shared’]
transparent
  • Description: Enable/disable transparent mode.
  • Required: False
  • choices: [‘disable’, ‘enable’]
Functions
  • fmgr_wanopt_profile_modify
def fmgr_wanopt_profile_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/wanopt/profile'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/wanopt/profile/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])

    return response


#############
# END METHODS
#############
  • main
def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        transparent=dict(required=False, type="str", choices=["disable", "enable"]),
        name=dict(required=False, type="str"),
        comments=dict(required=False, type="str"),
        auth_group=dict(required=False, type="str"),
        cifs=dict(required=False, type="dict"),
        cifs_byte_caching=dict(required=False, type="str", choices=["disable", "enable"]),
        cifs_log_traffic=dict(required=False, type="str", choices=["disable", "enable"]),
        cifs_port=dict(required=False, type="str"),
        cifs_prefer_chunking=dict(required=False, type="str", choices=["dynamic", "fix"]),
        cifs_secure_tunnel=dict(required=False, type="str", choices=["disable", "enable"]),
        cifs_status=dict(required=False, type="str", choices=["disable", "enable"]),
        cifs_tunnel_sharing=dict(required=False, type="str", choices=["private", "shared", "express-shared"]),
        ftp=dict(required=False, type="dict"),
        ftp_byte_caching=dict(required=False, type="str", choices=["disable", "enable"]),
        ftp_log_traffic=dict(required=False, type="str", choices=["disable", "enable"]),
        ftp_port=dict(required=False, type="str"),
        ftp_prefer_chunking=dict(required=False, type="str", choices=["dynamic", "fix"]),
        ftp_secure_tunnel=dict(required=False, type="str", choices=["disable", "enable"]),
        ftp_status=dict(required=False, type="str", choices=["disable", "enable"]),
        ftp_tunnel_sharing=dict(required=False, type="str", choices=["private", "shared", "express-shared"]),
        http=dict(required=False, type="dict"),
        http_byte_caching=dict(required=False, type="str", choices=["disable", "enable"]),
        http_log_traffic=dict(required=False, type="str", choices=["disable", "enable"]),
        http_port=dict(required=False, type="str"),
        http_prefer_chunking=dict(required=False, type="str", choices=["dynamic", "fix"]),
        http_secure_tunnel=dict(required=False, type="str", choices=["disable", "enable"]),
        http_ssl=dict(required=False, type="str", choices=["disable", "enable"]),
        http_ssl_port=dict(required=False, type="str"),
        http_status=dict(required=False, type="str", choices=["disable", "enable"]),
        http_tunnel_non_http=dict(required=False, type="str", choices=["disable", "enable"]),
        http_tunnel_sharing=dict(required=False, type="str", choices=["private", "shared", "express-shared"]),
        http_unknown_http_version=dict(required=False, type="str", choices=["best-effort", "reject", "tunnel"]),
        mapi=dict(required=False, type="dict"),
        mapi_byte_caching=dict(required=False, type="str", choices=["disable", "enable"]),
        mapi_log_traffic=dict(required=False, type="str", choices=["disable", "enable"]),
        mapi_port=dict(required=False, type="str"),
        mapi_secure_tunnel=dict(required=False, type="str", choices=["disable", "enable"]),
        mapi_status=dict(required=False, type="str", choices=["disable", "enable"]),
        mapi_tunnel_sharing=dict(required=False, type="str", choices=["private", "shared", "express-shared"]),
        tcp=dict(required=False, type="dict"),
        tcp_byte_caching=dict(required=False, type="str", choices=["disable", "enable"]),
        tcp_byte_caching_opt=dict(required=False, type="str", choices=["mem-only", "mem-disk"]),
        tcp_log_traffic=dict(required=False, type="str", choices=["disable", "enable"]),
        tcp_port=dict(required=False, type="str"),
        tcp_secure_tunnel=dict(required=False, type="str", choices=["disable", "enable"]),
        tcp_ssl=dict(required=False, type="str", choices=["disable", "enable"]),
        tcp_ssl_port=dict(required=False, type="str"),
        tcp_status=dict(required=False, type="str", choices=["disable", "enable"]),
        tcp_tunnel_sharing=dict(required=False, type="str", choices=["private", "shared", "express-shared"]),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "transparent": module.params["transparent"],
        "name": module.params["name"],
        "comments": module.params["comments"],
        "auth-group": module.params["auth_group"],
        "cifs": {
            "byte-caching": module.params["cifs_byte_caching"],
            "log-traffic": module.params["cifs_log_traffic"],
            "port": module.params["cifs_port"],
            "prefer-chunking": module.params["cifs_prefer_chunking"],
            "secure-tunnel": module.params["cifs_secure_tunnel"],
            "status": module.params["cifs_status"],
            "tunnel-sharing": module.params["cifs_tunnel_sharing"],
        },
        "ftp": {
            "byte-caching": module.params["ftp_byte_caching"],
            "log-traffic": module.params["ftp_log_traffic"],
            "port": module.params["ftp_port"],
            "prefer-chunking": module.params["ftp_prefer_chunking"],
            "secure-tunnel": module.params["ftp_secure_tunnel"],
            "status": module.params["ftp_status"],
            "tunnel-sharing": module.params["ftp_tunnel_sharing"],
        },
        "http": {
            "byte-caching": module.params["http_byte_caching"],
            "log-traffic": module.params["http_log_traffic"],
            "port": module.params["http_port"],
            "prefer-chunking": module.params["http_prefer_chunking"],
            "secure-tunnel": module.params["http_secure_tunnel"],
            "ssl": module.params["http_ssl"],
            "ssl-port": module.params["http_ssl_port"],
            "status": module.params["http_status"],
            "tunnel-non-http": module.params["http_tunnel_non_http"],
            "tunnel-sharing": module.params["http_tunnel_sharing"],
            "unknown-http-version": module.params["http_unknown_http_version"],
        },
        "mapi": {
            "byte-caching": module.params["mapi_byte_caching"],
            "log-traffic": module.params["mapi_log_traffic"],
            "port": module.params["mapi_port"],
            "secure-tunnel": module.params["mapi_secure_tunnel"],
            "status": module.params["mapi_status"],
            "tunnel-sharing": module.params["mapi_tunnel_sharing"],
        },
        "tcp": {
            "byte-caching": module.params["tcp_byte_caching"],
            "byte-caching-opt": module.params["tcp_byte_caching_opt"],
            "log-traffic": module.params["tcp_log_traffic"],
            "port": module.params["tcp_port"],
            "secure-tunnel": module.params["tcp_secure_tunnel"],
            "ssl": module.params["tcp_ssl"],
            "ssl-port": module.params["tcp_ssl_port"],
            "status": module.params["tcp_status"],
            "tunnel-sharing": module.params["tcp_tunnel_sharing"],
        }
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['cifs', 'ftp', 'http', 'mapi', 'tcp']
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)

    results = DEFAULT_RESULT_OBJ

    try:
        results = fmgr_wanopt_profile_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {'status': ['preview'],
                    'supported_by': 'community',
                    'metadata_version': '1.1'}

DOCUMENTATION = '''
---
module: fmgr_secprof_wanopt
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author:
    - Luke Weighall (@lweighall)
    - Andrew Welsh (@Ghilli3)
    - Jim Huber (@p4r4n0y1ng)
short_description: WAN optimization
description:
  -  Manage WanOpt security profiles in FortiManager via API

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: false
    default: root

  mode:
    description:
      - Sets one of three modes for managing the object.
      - Allows use of soft-adds instead of overwriting existing values
    choices: ['add', 'set', 'delete', 'update']
    required: false
    default: add

  transparent:
    description:
      - Enable/disable transparent mode.
    required: false
    choices:
      - disable
      - enable

  name:
    description:
      - Profile name.
    required: false

  comments:
    description:
      - Comment.
    required: false

  auth_group:
    description:
      - Optionally add an authentication group to restrict access to the WAN Optimization tunnel to
        peers in the authentication group.
    required: false

  cifs:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  cifs_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.
    required: false
    choices:
      - disable
      - enable

  cifs_log_traffic:
    description:
      - Enable/disable logging.
    required: false
    choices:
      - disable
      - enable

  cifs_port:
    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.
    required: false

  cifs_prefer_chunking:
    description:
      - Select dynamic or fixed-size data chunking for HTTP WAN Optimization.
    required: false
    choices:
      - dynamic
      - fix

  cifs_secure_tunnel:
    description:
      - Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the
        same TCP port (7810).
    required: false
    choices:
      - disable
      - enable

  cifs_status:
    description:
      - Enable/disable HTTP WAN Optimization.
    required: false
    choices:
      - disable
      - enable

  cifs_tunnel_sharing:
    description:
      - Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols.
    required: false
    choices:
      - private
      - shared
      - express-shared

  ftp:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  ftp_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.
    required: false
    choices:
      - disable
      - enable

  ftp_log_traffic:
    description:
      - Enable/disable logging.
    required: false
    choices:
      - disable
      - enable

  ftp_port:
    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.
    required: false

  ftp_prefer_chunking:
    description:
      - Select dynamic or fixed-size data chunking for HTTP WAN Optimization.
    required: false
    choices:
      - dynamic
      - fix

  ftp_secure_tunnel:
    description:
      - Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the
        same TCP port (7810).
    required: false
    choices:
      - disable
      - enable

  ftp_status:
    description:
      - Enable/disable HTTP WAN Optimization.
    required: false
    choices:
      - disable
      - enable

  ftp_tunnel_sharing:
    description:
      - Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols.
    required: false
    choices:
      - private
      - shared
      - express-shared

  http:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  http_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.
    required: false
    choices:
      - disable
      - enable

  http_log_traffic:
    description:
      - Enable/disable logging.
    required: false
    choices:
      - disable
      - enable

  http_port:
    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.
    required: false

  http_prefer_chunking:
    description:
      - Select dynamic or fixed-size data chunking for HTTP WAN Optimization.
    required: false
    choices:
      - dynamic
      - fix

  http_secure_tunnel:
    description:
      - Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the
        same TCP port (7810).
    required: false
    choices:
      - disable
      - enable

  http_ssl:
    description:
      - Enable/disable SSL/TLS offloading (hardware acceleration) for HTTPS traffic in this tunnel.
    required: false
    choices:
      - disable
      - enable

  http_ssl_port:
    description:
      - Port on which to expect HTTPS traffic for SSL/TLS offloading.
    required: false

  http_status:
    description:
      - Enable/disable HTTP WAN Optimization.
    required: false
    choices:
      - disable
      - enable

  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.
    required: false
    choices:
      - disable
      - enable

  http_tunnel_sharing:
    description:
      - Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols.
    required: false
    choices:
      - private
      - shared
      - express-shared

  http_unknown_http_version:
    description:
      - How to handle HTTP sessions that do not comply with HTTP 0.9, 1.0, or 1.1.
    required: false
    choices:
      - best-effort
      - reject
      - tunnel

  mapi:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  mapi_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.
    required: false
    choices:
      - disable
      - enable

  mapi_log_traffic:
    description:
      - Enable/disable logging.
    required: false
    choices:
      - disable
      - enable

  mapi_port:
    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.
    required: false

  mapi_secure_tunnel:
    description:
      - Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the
        same TCP port (7810).
    required: false
    choices:
      - disable
      - enable

  mapi_status:
    description:
      - Enable/disable HTTP WAN Optimization.
    required: false
    choices:
      - disable
      - enable

  mapi_tunnel_sharing:
    description:
      - Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols.
    required: false
    choices:
      - private
      - shared
      - express-shared

  tcp:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  tcp_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.
    required: false
    choices:
      - disable
      - enable

  tcp_byte_caching_opt:
    description:
      - Select whether TCP byte-caching uses system memory only or both memory and disk space.
    required: false
    choices:
      - mem-only
      - mem-disk

  tcp_log_traffic:
    description:
      - Enable/disable logging.
    required: false
    choices:
      - disable
      - enable

  tcp_port:
    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.
    required: false

  tcp_secure_tunnel:
    description:
      - Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the
        same TCP port (7810).
    required: false
    choices:
      - disable
      - enable

  tcp_ssl:
    description:
      - Enable/disable SSL/TLS offloading.
    required: false
    choices:
      - disable
      - enable

  tcp_ssl_port:
    description:
      - Port on which to expect HTTPS traffic for SSL/TLS offloading.
    required: false

  tcp_status:
    description:
      - Enable/disable HTTP WAN Optimization.
    required: false
    choices:
      - disable
      - enable

  tcp_tunnel_sharing:
    description:
      - Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols.
    required: false
    choices:
      - private
      - shared
      - express-shared

'''

EXAMPLES = '''
  - name: DELETE Profile
    fmgr_secprof_wanopt:
      name: "Ansible_WanOpt_Profile"
      mode: "delete"

  - name: Create FMGR_WANOPT_PROFILE
    fmgr_secprof_wanopt:
      mode: "set"
      adom: "root"
      transparent: "enable"
      name: "Ansible_WanOpt_Profile"
      comments: "Created by Ansible"
      cifs: {byte-caching: "enable",
              log-traffic: "enable",
              port: 80,
              prefer-chunking: "dynamic",
              status: "enable",
              tunnel-sharing: "private"}
      ftp: {byte-caching: "enable",
              log-traffic: "enable",
              port: 80,
              prefer-chunking: "dynamic",
              secure-tunnel: "disable",
              status: "enable",
              tunnel-sharing: "private"}
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
from ansible.module_utils.network.fortimanager.common import prepare_dict
from ansible.module_utils.network.fortimanager.common import scrub_dict


###############
# START METHODS
###############


def fmgr_wanopt_profile_modify(fmgr, paramgram):
    """
    :param fmgr: The fmgr object instance from fortimanager.py
    :type fmgr: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiManager
    :rtype: dict
    """

    mode = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/wanopt/profile'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/wanopt/profile/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])

    return response


#############
# END METHODS
#############


def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        transparent=dict(required=False, type="str", choices=["disable", "enable"]),
        name=dict(required=False, type="str"),
        comments=dict(required=False, type="str"),
        auth_group=dict(required=False, type="str"),
        cifs=dict(required=False, type="dict"),
        cifs_byte_caching=dict(required=False, type="str", choices=["disable", "enable"]),
        cifs_log_traffic=dict(required=False, type="str", choices=["disable", "enable"]),
        cifs_port=dict(required=False, type="str"),
        cifs_prefer_chunking=dict(required=False, type="str", choices=["dynamic", "fix"]),
        cifs_secure_tunnel=dict(required=False, type="str", choices=["disable", "enable"]),
        cifs_status=dict(required=False, type="str", choices=["disable", "enable"]),
        cifs_tunnel_sharing=dict(required=False, type="str", choices=["private", "shared", "express-shared"]),
        ftp=dict(required=False, type="dict"),
        ftp_byte_caching=dict(required=False, type="str", choices=["disable", "enable"]),
        ftp_log_traffic=dict(required=False, type="str", choices=["disable", "enable"]),
        ftp_port=dict(required=False, type="str"),
        ftp_prefer_chunking=dict(required=False, type="str", choices=["dynamic", "fix"]),
        ftp_secure_tunnel=dict(required=False, type="str", choices=["disable", "enable"]),
        ftp_status=dict(required=False, type="str", choices=["disable", "enable"]),
        ftp_tunnel_sharing=dict(required=False, type="str", choices=["private", "shared", "express-shared"]),
        http=dict(required=False, type="dict"),
        http_byte_caching=dict(required=False, type="str", choices=["disable", "enable"]),
        http_log_traffic=dict(required=False, type="str", choices=["disable", "enable"]),
        http_port=dict(required=False, type="str"),
        http_prefer_chunking=dict(required=False, type="str", choices=["dynamic", "fix"]),
        http_secure_tunnel=dict(required=False, type="str", choices=["disable", "enable"]),
        http_ssl=dict(required=False, type="str", choices=["disable", "enable"]),
        http_ssl_port=dict(required=False, type="str"),
        http_status=dict(required=False, type="str", choices=["disable", "enable"]),
        http_tunnel_non_http=dict(required=False, type="str", choices=["disable", "enable"]),
        http_tunnel_sharing=dict(required=False, type="str", choices=["private", "shared", "express-shared"]),
        http_unknown_http_version=dict(required=False, type="str", choices=["best-effort", "reject", "tunnel"]),
        mapi=dict(required=False, type="dict"),
        mapi_byte_caching=dict(required=False, type="str", choices=["disable", "enable"]),
        mapi_log_traffic=dict(required=False, type="str", choices=["disable", "enable"]),
        mapi_port=dict(required=False, type="str"),
        mapi_secure_tunnel=dict(required=False, type="str", choices=["disable", "enable"]),
        mapi_status=dict(required=False, type="str", choices=["disable", "enable"]),
        mapi_tunnel_sharing=dict(required=False, type="str", choices=["private", "shared", "express-shared"]),
        tcp=dict(required=False, type="dict"),
        tcp_byte_caching=dict(required=False, type="str", choices=["disable", "enable"]),
        tcp_byte_caching_opt=dict(required=False, type="str", choices=["mem-only", "mem-disk"]),
        tcp_log_traffic=dict(required=False, type="str", choices=["disable", "enable"]),
        tcp_port=dict(required=False, type="str"),
        tcp_secure_tunnel=dict(required=False, type="str", choices=["disable", "enable"]),
        tcp_ssl=dict(required=False, type="str", choices=["disable", "enable"]),
        tcp_ssl_port=dict(required=False, type="str"),
        tcp_status=dict(required=False, type="str", choices=["disable", "enable"]),
        tcp_tunnel_sharing=dict(required=False, type="str", choices=["private", "shared", "express-shared"]),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "transparent": module.params["transparent"],
        "name": module.params["name"],
        "comments": module.params["comments"],
        "auth-group": module.params["auth_group"],
        "cifs": {
            "byte-caching": module.params["cifs_byte_caching"],
            "log-traffic": module.params["cifs_log_traffic"],
            "port": module.params["cifs_port"],
            "prefer-chunking": module.params["cifs_prefer_chunking"],
            "secure-tunnel": module.params["cifs_secure_tunnel"],
            "status": module.params["cifs_status"],
            "tunnel-sharing": module.params["cifs_tunnel_sharing"],
        },
        "ftp": {
            "byte-caching": module.params["ftp_byte_caching"],
            "log-traffic": module.params["ftp_log_traffic"],
            "port": module.params["ftp_port"],
            "prefer-chunking": module.params["ftp_prefer_chunking"],
            "secure-tunnel": module.params["ftp_secure_tunnel"],
            "status": module.params["ftp_status"],
            "tunnel-sharing": module.params["ftp_tunnel_sharing"],
        },
        "http": {
            "byte-caching": module.params["http_byte_caching"],
            "log-traffic": module.params["http_log_traffic"],
            "port": module.params["http_port"],
            "prefer-chunking": module.params["http_prefer_chunking"],
            "secure-tunnel": module.params["http_secure_tunnel"],
            "ssl": module.params["http_ssl"],
            "ssl-port": module.params["http_ssl_port"],
            "status": module.params["http_status"],
            "tunnel-non-http": module.params["http_tunnel_non_http"],
            "tunnel-sharing": module.params["http_tunnel_sharing"],
            "unknown-http-version": module.params["http_unknown_http_version"],
        },
        "mapi": {
            "byte-caching": module.params["mapi_byte_caching"],
            "log-traffic": module.params["mapi_log_traffic"],
            "port": module.params["mapi_port"],
            "secure-tunnel": module.params["mapi_secure_tunnel"],
            "status": module.params["mapi_status"],
            "tunnel-sharing": module.params["mapi_tunnel_sharing"],
        },
        "tcp": {
            "byte-caching": module.params["tcp_byte_caching"],
            "byte-caching-opt": module.params["tcp_byte_caching_opt"],
            "log-traffic": module.params["tcp_log_traffic"],
            "port": module.params["tcp_port"],
            "secure-tunnel": module.params["tcp_secure_tunnel"],
            "ssl": module.params["tcp_ssl"],
            "ssl-port": module.params["tcp_ssl_port"],
            "status": module.params["tcp_status"],
            "tunnel-sharing": module.params["tcp_tunnel_sharing"],
        }
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['cifs', 'ftp', 'http', 'mapi', 'tcp']
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)

    results = DEFAULT_RESULT_OBJ

    try:
        results = fmgr_wanopt_profile_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_secprof_web

Metadata

Name: fmgr_secprof_web

Description: Manage web filter security profiles in FortiManager through playbooks using the FMG API

Author(s):

  • Luke Weighall (github: @lweighall)
  • Andrew Welsh (github: @Ghilli3)
  • Jim Huber (github: @p4r4n0y1ng)

Ansible Version Added/Required: 2.8

Dev Status: COMPLETED/MERGED

Owning Developer: Andrew Welsh

Module Github Link

Parameters
adom
  • Description: The ADOM the configuration should belong to.
  • Required: False
  • default: root
comment
  • Description: Optional comments.
  • Required: False
extended_log
  • Description: Enable/disable extended logging for web filtering.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

ftgd_wf
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

ftgd_wf_exempt_quota
  • Description: Do not stop quota for these categories.
  • Required: False
ftgd_wf_filters_action
  • Description: Action to take for matches.

    choice | block | Block access.

    choice | monitor | Allow access while logging the action.

    choice | warning | Allow access after warning the user.

    choice | authenticate | Authenticate user before allowing access.

  • Required: False

  • choices: [‘block’, ‘monitor’, ‘warning’, ‘authenticate’]

ftgd_wf_filters_auth_usr_grp
  • Description: Groups with permission to authenticate.
  • Required: False
ftgd_wf_filters_category
  • Description: Categories and groups the filter examines.
  • Required: False
ftgd_wf_filters_log
  • Description: Enable/disable logging.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

ftgd_wf_filters_override_replacemsg
  • Description: Override replacement message.
  • Required: False
ftgd_wf_filters_warn_duration
  • Description: Duration of warnings.
  • Required: False
ftgd_wf_filters_warning_duration_type
  • Description: Re-display warning after closing browser or after a timeout.

    choice | session | After session ends.

    choice | timeout | After timeout occurs.

  • Required: False

  • choices: [‘session’, ‘timeout’]

ftgd_wf_filters_warning_prompt
  • Description: Warning prompts in each category or each domain.

    choice | per-domain | Per-domain warnings.

    choice | per-category | Per-category warnings.

  • Required: False

  • choices: [‘per-domain’, ‘per-category’]

ftgd_wf_max_quota_timeout
  • Description: Maximum FortiGuard quota used by single page view in seconds (excludes streams).
  • Required: False
ftgd_wf_options
  • Description: Options for FortiGuard Web Filter.

    FLAG Based Options. Specify multiple in list form.

    flag | error-allow | Allow web pages with a rating error to pass through.

    flag | rate-server-ip | Rate the server IP in addition to the domain name.

    flag | connect-request-bypass | Bypass connection which has CONNECT request.

    flag | ftgd-disable | Disable FortiGuard scanning.

  • Required: False

  • choices: [‘error-allow’, ‘rate-server-ip’, ‘connect-request-bypass’, ‘ftgd-disable’]

ftgd_wf_ovrd
  • Description: Allow web filter profile overrides.
  • Required: False
ftgd_wf_quota_category
  • Description: FortiGuard categories to apply quota to (category action must be set to monitor).
  • Required: False
ftgd_wf_quota_duration
  • Description: Duration of quota.
  • Required: False
ftgd_wf_quota_override_replacemsg
  • Description: Override replacement message.
  • Required: False
ftgd_wf_quota_type
  • Description: Quota type.

    choice | time | Use a time-based quota.

    choice | traffic | Use a traffic-based quota.

  • Required: False

  • choices: [‘time’, ‘traffic’]

ftgd_wf_quota_unit
  • Description: Traffic quota unit of measurement.

    choice | B | Quota in bytes.

    choice | KB | Quota in kilobytes.

    choice | MB | Quota in megabytes.

    choice | GB | Quota in gigabytes.

  • Required: False

  • choices: [‘B’, ‘KB’, ‘MB’, ‘GB’]

ftgd_wf_quota_value
  • Description: Traffic quota value.
  • Required: False
ftgd_wf_rate_crl_urls
  • Description: Enable/disable rating CRL by URL.

    choice | disable | Disable rating CRL by URL.

    choice | enable | Enable rating CRL by URL.

  • Required: False

  • choices: [‘disable’, ‘enable’]

ftgd_wf_rate_css_urls
  • Description: Enable/disable rating CSS by URL.

    choice | disable | Disable rating CSS by URL.

    choice | enable | Enable rating CSS by URL.

  • Required: False

  • choices: [‘disable’, ‘enable’]

ftgd_wf_rate_image_urls
  • Description: Enable/disable rating images by URL.

    choice | disable | Disable rating images by URL (blocked images are replaced with blanks).

    choice | enable | Enable rating images by URL (blocked images are replaced with blanks).

  • Required: False

  • choices: [‘disable’, ‘enable’]

ftgd_wf_rate_javascript_urls
  • Description: Enable/disable rating JavaScript by URL.

    choice | disable | Disable rating JavaScript by URL.

    choice | enable | Enable rating JavaScript by URL.

  • Required: False

  • choices: [‘disable’, ‘enable’]

https_replacemsg
  • Description: Enable replacement messages for HTTPS.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

inspection_mode
  • Description: Web filtering inspection mode.

    choice | proxy | Proxy.

    choice | flow-based | Flow based.

  • Required: False

  • choices: [‘proxy’, ‘flow-based’]

log_all_url
  • Description: Enable/disable logging all URLs visited.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

mode
  • Description: Sets one of three modes for managing the object.

    Allows use of soft-adds instead of overwriting existing values

  • Required: False

  • default: add

  • choices: [‘add’, ‘set’, ‘delete’, ‘update’]

name
  • Description: Profile name.
  • Required: False
options
  • Description: FLAG Based Options. Specify multiple in list form.

    flag | block-invalid-url | Block sessions contained an invalid domain name.

    flag | jscript | Javascript block.

    flag | js | JS block.

    flag | vbs | VB script block.

    flag | unknown | Unknown script block.

    flag | wf-referer | Referring block.

    flag | intrinsic | Intrinsic script block.

    flag | wf-cookie | Cookie block.

    flag | per-user-bwl | Per-user black/white list filter

    flag | activexfilter | ActiveX filter.

    flag | cookiefilter | Cookie filter.

    flag | javafilter | Java applet filter.

  • Required: False

  • choices: [‘block-invalid-url’, ‘jscript’, ‘js’, ‘vbs’, ‘unknown’, ‘wf-referer’, ‘intrinsic’, ‘wf-cookie’, ‘per-user-bwl’, ‘activexfilter’, ‘cookiefilter’, ‘javafilter’]

override
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

override_ovrd_dur
  • Description: Override duration.
  • Required: False
override_ovrd_dur_mode
  • Description: Override duration mode.

    choice | constant | Constant mode.

    choice | ask | Prompt for duration when initiating an override.

  • Required: False

  • choices: [‘constant’, ‘ask’]

override_ovrd_scope
  • Description: Override scope.

    choice | user | Override for the user.

    choice | user-group | Override for the user’s group.

    choice | ip | Override for the initiating IP.

    choice | ask | Prompt for scope when initiating an override.

    choice | browser | Create browser-based (cookie) override.

  • Required: False

  • choices: [‘user’, ‘user-group’, ‘ip’, ‘ask’, ‘browser’]

override_ovrd_user_group
  • Description: User groups with permission to use the override.
  • Required: False
override_profile
  • Description: Web filter profile with permission to create overrides.
  • Required: False
override_profile_attribute
  • Description: Profile attribute to retrieve from the RADIUS server.

    choice | User-Name | Use this attribute.

    choice | NAS-IP-Address | Use this attribute.

    choice | Framed-IP-Address | Use this attribute.

    choice | Framed-IP-Netmask | Use this attribute.

    choice | Filter-Id | Use this attribute.

    choice | Login-IP-Host | Use this attribute.

    choice | Reply-Message | Use this attribute.

    choice | Callback-Number | Use this attribute.

    choice | Callback-Id | Use this attribute.

    choice | Framed-Route | Use this attribute.

    choice | Framed-IPX-Network | Use this attribute.

    choice | Class | Use this attribute.

    choice | Called-Station-Id | Use this attribute.

    choice | Calling-Station-Id | Use this attribute.

    choice | NAS-Identifier | Use this attribute.

    choice | Proxy-State | Use this attribute.

    choice | Login-LAT-Service | Use this attribute.

    choice | Login-LAT-Node | Use this attribute.

    choice | Login-LAT-Group | Use this attribute.

    choice | Framed-AppleTalk-Zone | Use this attribute.

    choice | Acct-Session-Id | Use this attribute.

    choice | Acct-Multi-Session-Id | Use this attribute.

  • Required: False

  • choices: [‘User-Name’, ‘NAS-IP-Address’, ‘Framed-IP-Address’, ‘Framed-IP-Netmask’, ‘Filter-Id’, ‘Login-IP-Host’, ‘Reply-Message’, ‘Callback-Number’, ‘Callback-Id’, ‘Framed-Route’, ‘Framed-IPX-Network’, ‘Class’, ‘Called-Station-Id’, ‘Calling-Station-Id’, ‘NAS-Identifier’, ‘Proxy-State’, ‘Login-LAT-Service’, ‘Login-LAT-Node’, ‘Login-LAT-Group’, ‘Framed-AppleTalk-Zone’, ‘Acct-Session-Id’, ‘Acct-Multi-Session-Id’]

override_profile_type
  • Description: Override profile type.

    choice | list | Profile chosen from list.

    choice | radius | Profile determined by RADIUS server.

  • Required: False

  • choices: [‘list’, ‘radius’]

ovrd_perm
  • Description: FLAG Based Options. Specify multiple in list form.

    flag | bannedword-override | Banned word override.

    flag | urlfilter-override | URL filter override.

    flag | fortiguard-wf-override | FortiGuard Web Filter override.

    flag | contenttype-check-override | Content-type header override.

  • Required: False

  • choices: [‘bannedword-override’, ‘urlfilter-override’, ‘fortiguard-wf-override’, ‘contenttype-check-override’]

post_action
  • Description: Action taken for HTTP POST traffic.

    choice | normal | Normal, POST requests are allowed.

    choice | block | POST requests are blocked.

  • Required: False

  • choices: [‘normal’, ‘block’]

replacemsg_group
  • Description: Replacement message group.
  • Required: False
url_extraction
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

url_extraction_redirect_header
  • Description: HTTP header name to use for client redirect on blocked requests
  • Required: False
url_extraction_redirect_no_content
  • Description: Enable / Disable empty message-body entity in HTTP response

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

url_extraction_redirect_url
  • Description: HTTP header value to use for client redirect on blocked requests
  • Required: False
url_extraction_server_fqdn
  • Description: URL extraction server FQDN (fully qualified domain name)
  • Required: False
url_extraction_status
  • Description: Enable URL Extraction

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

web
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

web_blacklist
  • Description: Enable/disable automatic addition of URLs detected by FortiSandbox to blacklist.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

web_bword_table
  • Description: Banned word table ID.
  • Required: False
web_bword_threshold
  • Description: Banned word score threshold.
  • Required: False
web_content_header_list
  • Description: Content header list.
  • Required: False
web_content_log
  • Description: Enable/disable logging logging blocked web content.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

web_extended_all_action_log
  • Description: Enable/disable extended any filter action logging for web filtering.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

web_filter_activex_log
  • Description: Enable/disable logging ActiveX.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

web_filter_applet_log
  • Description: Enable/disable logging Java applets.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

web_filter_command_block_log
  • Description: Enable/disable logging blocked commands.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

web_filter_js_log
  • Description: Enable/disable logging Java scripts.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

web_filter_jscript_log
  • Description: Enable/disable logging JScripts.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

web_filter_referer_log
  • Description: Enable/disable logging referrers.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

web_filter_unknown_log
  • Description: Enable/disable logging unknown scripts.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

web_filter_vbs_log
  • Description: Enable/disable logging VBS scripts.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

web_ftgd_err_log
  • Description: Enable/disable logging rating errors.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

web_ftgd_quota_usage
  • Description: Enable/disable logging daily quota usage.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

web_invalid_domain_log
  • Description: Enable/disable logging invalid domain names.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

web_keyword_match
  • Description: Search keywords to log when match is found.
  • Required: False
web_url_log
  • Description: Enable/disable logging URL filtering.

    choice | disable | Disable setting.

    choice | enable | Enable setting.

  • Required: False

  • choices: [‘disable’, ‘enable’]

web_urlfilter_table
  • Description: URL filter table ID.
  • Required: False
web_whitelist
  • Description: FortiGuard whitelist settings.

    FLAG Based Options. Specify multiple in list form.

    flag | exempt-av | Exempt antivirus.

    flag | exempt-webcontent | Exempt web content.

    flag | exempt-activex-java-cookie | Exempt ActiveX-JAVA-Cookie.

    flag | exempt-dlp | Exempt DLP.

    flag | exempt-rangeblock | Exempt RangeBlock.

    flag | extended-log-others | Support extended log.

  • Required: False

  • choices: [‘exempt-av’, ‘exempt-webcontent’, ‘exempt-activex-java-cookie’, ‘exempt-dlp’, ‘exempt-rangeblock’, ‘extended-log-others’]

web_youtube_restrict
  • Description: YouTube EDU filter level.

    choice | strict | Strict access for YouTube.

    choice | none | Full access for YouTube.

    choice | moderate | Moderate access for YouTube.

  • Required: False

  • choices: [‘strict’, ‘none’, ‘moderate’]

wisp
  • Description: Enable/disable web proxy WISP.

    choice | disable | Disable web proxy WISP.

    choice | enable | Enable web proxy WISP.

  • Required: False

  • choices: [‘disable’, ‘enable’]

wisp_algorithm
  • Description: WISP server selection algorithm.

    choice | auto-learning | Select the lightest loading healthy server.

    choice | primary-secondary | Select the first healthy server in order.

    choice | round-robin | Select the next healthy server.

  • Required: False

  • choices: [‘auto-learning’, ‘primary-secondary’, ‘round-robin’]

wisp_servers
  • Description: WISP servers.
  • Required: False
youtube_channel_filter
  • Description: EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!

    List of multiple child objects to be added. Expects a list of dictionaries.

    Dictionaries must use FortiManager API parameters, not the ansible ones listed below.

    If submitted, all other prefixed sub-parameters ARE IGNORED.

    This object is MUTUALLY EXCLUSIVE with its options.

    We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.

    WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS

  • Required: False

youtube_channel_filter_channel_id
  • Description: YouTube channel ID to be filtered.
  • Required: False
youtube_channel_filter_comment
  • Description: Comment.
  • Required: False
youtube_channel_status
  • Description: YouTube channel filter status.

    choice | disable | Disable YouTube channel filter.

    choice | blacklist | Block matches.

    choice | whitelist | Allow matches.

  • Required: False

  • choices: [‘disable’, ‘blacklist’, ‘whitelist’]

Functions
  • fmgr_webfilter_profile_modify
def fmgr_webfilter_profile_modify(fmgr, paramgram):

    mode = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/webfilter/profile'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/webfilter/profile/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])

    return response


#############
# END METHODS
#############
  • main
def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        youtube_channel_status=dict(required=False, type="str", choices=["disable", "blacklist", "whitelist"]),
        wisp_servers=dict(required=False, type="str"),
        wisp_algorithm=dict(required=False, type="str", choices=["auto-learning", "primary-secondary", "round-robin"]),
        wisp=dict(required=False, type="str", choices=["disable", "enable"]),
        web_url_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_invalid_domain_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_ftgd_quota_usage=dict(required=False, type="str", choices=["disable", "enable"]),
        web_ftgd_err_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_filter_vbs_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_filter_unknown_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_filter_referer_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_filter_jscript_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_filter_js_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_filter_cookie_removal_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_filter_cookie_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_filter_command_block_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_filter_applet_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_filter_activex_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_extended_all_action_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_content_log=dict(required=False, type="str", choices=["disable", "enable"]),
        replacemsg_group=dict(required=False, type="str"),
        post_action=dict(required=False, type="str", choices=["normal", "block"]),
        ovrd_perm=dict(required=False, type="list", choices=["bannedword-override",
                                                             "urlfilter-override",
                                                             "fortiguard-wf-override",
                                                             "contenttype-check-override"]),
        options=dict(required=False, type="list", choices=["block-invalid-url",
                                                           "jscript",
                                                           "js",
                                                           "vbs",
                                                           "unknown",
                                                           "wf-referer",
                                                           "intrinsic",
                                                           "wf-cookie",
                                                           "per-user-bwl",
                                                           "activexfilter",
                                                           "cookiefilter",
                                                           "javafilter"]),
        name=dict(required=False, type="str"),
        log_all_url=dict(required=False, type="str", choices=["disable", "enable"]),
        inspection_mode=dict(required=False, type="str", choices=["proxy", "flow-based"]),
        https_replacemsg=dict(required=False, type="str", choices=["disable", "enable"]),
        extended_log=dict(required=False, type="str", choices=["disable", "enable"]),
        comment=dict(required=False, type="str"),
        ftgd_wf=dict(required=False, type="list"),
        ftgd_wf_exempt_quota=dict(required=False, type="str"),
        ftgd_wf_max_quota_timeout=dict(required=False, type="int"),
        ftgd_wf_options=dict(required=False, type="str", choices=["error-allow", "rate-server-ip",
                                                                  "connect-request-bypass", "ftgd-disable"]),
        ftgd_wf_ovrd=dict(required=False, type="str"),
        ftgd_wf_rate_crl_urls=dict(required=False, type="str", choices=["disable", "enable"]),
        ftgd_wf_rate_css_urls=dict(required=False, type="str", choices=["disable", "enable"]),
        ftgd_wf_rate_image_urls=dict(required=False, type="str", choices=["disable", "enable"]),
        ftgd_wf_rate_javascript_urls=dict(required=False, type="str", choices=["disable", "enable"]),

        ftgd_wf_filters_action=dict(required=False, type="str", choices=["block", "monitor",
                                                                         "warning", "authenticate"]),
        ftgd_wf_filters_auth_usr_grp=dict(required=False, type="str"),
        ftgd_wf_filters_category=dict(required=False, type="str"),
        ftgd_wf_filters_log=dict(required=False, type="str", choices=["disable", "enable"]),
        ftgd_wf_filters_override_replacemsg=dict(required=False, type="str"),
        ftgd_wf_filters_warn_duration=dict(required=False, type="str"),
        ftgd_wf_filters_warning_duration_type=dict(required=False, type="str", choices=["session", "timeout"]),
        ftgd_wf_filters_warning_prompt=dict(required=False, type="str", choices=["per-domain", "per-category"]),

        ftgd_wf_quota_category=dict(required=False, type="str"),
        ftgd_wf_quota_duration=dict(required=False, type="str"),
        ftgd_wf_quota_override_replacemsg=dict(required=False, type="str"),
        ftgd_wf_quota_type=dict(required=False, type="str", choices=["time", "traffic"]),
        ftgd_wf_quota_unit=dict(required=False, type="str", choices=["B", "KB", "MB", "GB"]),
        ftgd_wf_quota_value=dict(required=False, type="int"),
        override=dict(required=False, type="list"),
        override_ovrd_cookie=dict(required=False, type="str", choices=["deny", "allow"]),
        override_ovrd_dur=dict(required=False, type="str"),
        override_ovrd_dur_mode=dict(required=False, type="str", choices=["constant", "ask"]),
        override_ovrd_scope=dict(required=False, type="str", choices=["user", "user-group", "ip", "ask", "browser"]),
        override_ovrd_user_group=dict(required=False, type="str"),
        override_profile=dict(required=False, type="str"),
        override_profile_attribute=dict(required=False, type="list", choices=["User-Name",
                                                                              "NAS-IP-Address",
                                                                              "Framed-IP-Address",
                                                                              "Framed-IP-Netmask",
                                                                              "Filter-Id",
                                                                              "Login-IP-Host",
                                                                              "Reply-Message",
                                                                              "Callback-Number",
                                                                              "Callback-Id",
                                                                              "Framed-Route",
                                                                              "Framed-IPX-Network",
                                                                              "Class",
                                                                              "Called-Station-Id",
                                                                              "Calling-Station-Id",
                                                                              "NAS-Identifier",
                                                                              "Proxy-State",
                                                                              "Login-LAT-Service",
                                                                              "Login-LAT-Node",
                                                                              "Login-LAT-Group",
                                                                              "Framed-AppleTalk-Zone",
                                                                              "Acct-Session-Id",
                                                                              "Acct-Multi-Session-Id"]),
        override_profile_type=dict(required=False, type="str", choices=["list", "radius"]),
        url_extraction=dict(required=False, type="list"),
        url_extraction_redirect_header=dict(required=False, type="str"),
        url_extraction_redirect_no_content=dict(required=False, type="str", choices=["disable", "enable"]),
        url_extraction_redirect_url=dict(required=False, type="str"),
        url_extraction_server_fqdn=dict(required=False, type="str"),
        url_extraction_status=dict(required=False, type="str", choices=["disable", "enable"]),
        web=dict(required=False, type="list"),
        web_blacklist=dict(required=False, type="str", choices=["disable", "enable"]),
        web_bword_table=dict(required=False, type="str"),
        web_bword_threshold=dict(required=False, type="int"),
        web_content_header_list=dict(required=False, type="str"),
        web_keyword_match=dict(required=False, type="str"),
        web_log_search=dict(required=False, type="str", choices=["disable", "enable"]),
        web_safe_search=dict(required=False, type="str", choices=["url", "header"]),
        web_urlfilter_table=dict(required=False, type="str"),
        web_whitelist=dict(required=False, type="list", choices=["exempt-av",
                                                                 "exempt-webcontent",
                                                                 "exempt-activex-java-cookie",
                                                                 "exempt-dlp",
                                                                 "exempt-rangeblock",
                                                                 "extended-log-others"]),
        web_youtube_restrict=dict(required=False, type="str", choices=["strict", "none", "moderate"]),
        youtube_channel_filter=dict(required=False, type="list"),
        youtube_channel_filter_channel_id=dict(required=False, type="str"),
        youtube_channel_filter_comment=dict(required=False, type="str"),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "youtube-channel-status": module.params["youtube_channel_status"],
        "wisp-servers": module.params["wisp_servers"],
        "wisp-algorithm": module.params["wisp_algorithm"],
        "wisp": module.params["wisp"],
        "web-url-log": module.params["web_url_log"],
        "web-invalid-domain-log": module.params["web_invalid_domain_log"],
        "web-ftgd-quota-usage": module.params["web_ftgd_quota_usage"],
        "web-ftgd-err-log": module.params["web_ftgd_err_log"],
        "web-filter-vbs-log": module.params["web_filter_vbs_log"],
        "web-filter-unknown-log": module.params["web_filter_unknown_log"],
        "web-filter-referer-log": module.params["web_filter_referer_log"],
        "web-filter-jscript-log": module.params["web_filter_jscript_log"],
        "web-filter-js-log": module.params["web_filter_js_log"],
        "web-filter-cookie-removal-log": module.params["web_filter_cookie_removal_log"],
        "web-filter-cookie-log": module.params["web_filter_cookie_log"],
        "web-filter-command-block-log": module.params["web_filter_command_block_log"],
        "web-filter-applet-log": module.params["web_filter_applet_log"],
        "web-filter-activex-log": module.params["web_filter_activex_log"],
        "web-extended-all-action-log": module.params["web_extended_all_action_log"],
        "web-content-log": module.params["web_content_log"],
        "replacemsg-group": module.params["replacemsg_group"],
        "post-action": module.params["post_action"],
        "ovrd-perm": module.params["ovrd_perm"],
        "options": module.params["options"],
        "name": module.params["name"],
        "log-all-url": module.params["log_all_url"],
        "inspection-mode": module.params["inspection_mode"],
        "https-replacemsg": module.params["https_replacemsg"],
        "extended-log": module.params["extended_log"],
        "comment": module.params["comment"],
        "ftgd-wf": {
            "exempt-quota": module.params["ftgd_wf_exempt_quota"],
            "max-quota-timeout": module.params["ftgd_wf_max_quota_timeout"],
            "options": module.params["ftgd_wf_options"],
            "ovrd": module.params["ftgd_wf_ovrd"],
            "rate-crl-urls": module.params["ftgd_wf_rate_crl_urls"],
            "rate-css-urls": module.params["ftgd_wf_rate_css_urls"],
            "rate-image-urls": module.params["ftgd_wf_rate_image_urls"],
            "rate-javascript-urls": module.params["ftgd_wf_rate_javascript_urls"],
            "filters": {
                "action": module.params["ftgd_wf_filters_action"],
                "auth-usr-grp": module.params["ftgd_wf_filters_auth_usr_grp"],
                "category": module.params["ftgd_wf_filters_category"],
                "log": module.params["ftgd_wf_filters_log"],
                "override-replacemsg": module.params["ftgd_wf_filters_override_replacemsg"],
                "warn-duration": module.params["ftgd_wf_filters_warn_duration"],
                "warning-duration-type": module.params["ftgd_wf_filters_warning_duration_type"],
                "warning-prompt": module.params["ftgd_wf_filters_warning_prompt"],
            },
            "quota": {
                "category": module.params["ftgd_wf_quota_category"],
                "duration": module.params["ftgd_wf_quota_duration"],
                "override-replacemsg": module.params["ftgd_wf_quota_override_replacemsg"],
                "type": module.params["ftgd_wf_quota_type"],
                "unit": module.params["ftgd_wf_quota_unit"],
                "value": module.params["ftgd_wf_quota_value"],
            },
        },
        "override": {
            "ovrd-cookie": module.params["override_ovrd_cookie"],
            "ovrd-dur": module.params["override_ovrd_dur"],
            "ovrd-dur-mode": module.params["override_ovrd_dur_mode"],
            "ovrd-scope": module.params["override_ovrd_scope"],
            "ovrd-user-group": module.params["override_ovrd_user_group"],
            "profile": module.params["override_profile"],
            "profile-attribute": module.params["override_profile_attribute"],
            "profile-type": module.params["override_profile_type"],
        },
        "url-extraction": {
            "redirect-header": module.params["url_extraction_redirect_header"],
            "redirect-no-content": module.params["url_extraction_redirect_no_content"],
            "redirect-url": module.params["url_extraction_redirect_url"],
            "server-fqdn": module.params["url_extraction_server_fqdn"],
            "status": module.params["url_extraction_status"],
        },
        "web": {
            "blacklist": module.params["web_blacklist"],
            "bword-table": module.params["web_bword_table"],
            "bword-threshold": module.params["web_bword_threshold"],
            "content-header-list": module.params["web_content_header_list"],
            "keyword-match": module.params["web_keyword_match"],
            "log-search": module.params["web_log_search"],
            "safe-search": module.params["web_safe_search"],
            "urlfilter-table": module.params["web_urlfilter_table"],
            "whitelist": module.params["web_whitelist"],
            "youtube-restrict": module.params["web_youtube_restrict"],
        },
        "youtube-channel-filter": {
            "channel-id": module.params["youtube_channel_filter_channel_id"],
            "comment": module.params["youtube_channel_filter_comment"],
        }
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['ftgd-wf', 'override', 'url-extraction', 'web', 'youtube-channel-filter']
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)

    results = DEFAULT_RESULT_OBJ

    try:

        results = fmgr_webfilter_profile_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {'status': ['preview'],
                    'supported_by': 'community',
                    'metadata_version': '1.1'}

DOCUMENTATION = '''
---
module: fmgr_secprof_web
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author:
    - Luke Weighall (@lweighall)
    - Andrew Welsh (@Ghilli3)
    - Jim Huber (@p4r4n0y1ng)
short_description: Manage web filter security profiles in FortiManager
description:
  -  Manage web filter security profiles in FortiManager through playbooks using the FMG API

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: false
    default: root

  mode:
    description:
      - Sets one of three modes for managing the object.
      - Allows use of soft-adds instead of overwriting existing values
    choices: ['add', 'set', 'delete', 'update']
    required: false
    default: add

  youtube_channel_status:
    description:
      - YouTube channel filter status.
      - choice | disable | Disable YouTube channel filter.
      - choice | blacklist | Block matches.
      - choice | whitelist | Allow matches.
    required: false
    choices: ["disable", "blacklist", "whitelist"]

  wisp_servers:
    description:
      - WISP servers.
    required: false

  wisp_algorithm:
    description:
      - WISP server selection algorithm.
      - choice | auto-learning | Select the lightest loading healthy server.
      - choice | primary-secondary | Select the first healthy server in order.
      - choice | round-robin | Select the next healthy server.
    required: false
    choices: ["auto-learning", "primary-secondary", "round-robin"]

  wisp:
    description:
      - Enable/disable web proxy WISP.
      - choice | disable | Disable web proxy WISP.
      - choice | enable | Enable web proxy WISP.
    required: false
    choices: ["disable", "enable"]

  web_url_log:
    description:
      - Enable/disable logging URL filtering.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  web_invalid_domain_log:
    description:
      - Enable/disable logging invalid domain names.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  web_ftgd_quota_usage:
    description:
      - Enable/disable logging daily quota usage.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  web_ftgd_err_log:
    description:
      - Enable/disable logging rating errors.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  web_filter_vbs_log:
    description:
      - Enable/disable logging VBS scripts.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  web_filter_unknown_log:
    description:
      - Enable/disable logging unknown scripts.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  web_filter_referer_log:
    description:
      - Enable/disable logging referrers.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  web_filter_jscript_log:
    description:
      - Enable/disable logging JScripts.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  web_filter_js_log:
    description:
      - Enable/disable logging Java scripts.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  web_filter_cookie_removal_log:
    description:
      - Enable/disable logging blocked cookies.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  web_filter_cookie_log:
    description:
      - Enable/disable logging cookie filtering.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  web_filter_command_block_log:
    description:
      - Enable/disable logging blocked commands.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  web_filter_applet_log:
    description:
      - Enable/disable logging Java applets.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  web_filter_activex_log:
    description:
      - Enable/disable logging ActiveX.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  web_extended_all_action_log:
    description:
      - Enable/disable extended any filter action logging for web filtering.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  web_content_log:
    description:
      - Enable/disable logging logging blocked web content.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  replacemsg_group:
    description:
      - Replacement message group.
    required: false

  post_action:
    description:
      - Action taken for HTTP POST traffic.
      - choice | normal | Normal, POST requests are allowed.
      - choice | block | POST requests are blocked.
    required: false
    choices: ["normal", "block"]

  ovrd_perm:
    description:
      - FLAG Based Options. Specify multiple in list form.
      - flag | bannedword-override | Banned word override.
      - flag | urlfilter-override | URL filter override.
      - flag | fortiguard-wf-override | FortiGuard Web Filter override.
      - flag | contenttype-check-override | Content-type header override.
    required: false
    choices:
      - bannedword-override
      - urlfilter-override
      - fortiguard-wf-override
      - contenttype-check-override

  options:
    description:
      - FLAG Based Options. Specify multiple in list form.
      - flag | block-invalid-url | Block sessions contained an invalid domain name.
      - flag | jscript | Javascript block.
      - flag | js | JS block.
      - flag | vbs | VB script block.
      - flag | unknown | Unknown script block.
      - flag | wf-referer | Referring block.
      - flag | intrinsic | Intrinsic script block.
      - flag | wf-cookie | Cookie block.
      - flag | per-user-bwl | Per-user black/white list filter
      - flag | activexfilter | ActiveX filter.
      - flag | cookiefilter | Cookie filter.
      - flag | javafilter | Java applet filter.
    required: false
    choices:
      - block-invalid-url
      - jscript
      - js
      - vbs
      - unknown
      - wf-referer
      - intrinsic
      - wf-cookie
      - per-user-bwl
      - activexfilter
      - cookiefilter
      - javafilter

  name:
    description:
      - Profile name.
    required: false

  log_all_url:
    description:
      - Enable/disable logging all URLs visited.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  inspection_mode:
    description:
      - Web filtering inspection mode.
      - choice | proxy | Proxy.
      - choice | flow-based | Flow based.
    required: false
    choices: ["proxy", "flow-based"]

  https_replacemsg:
    description:
      - Enable replacement messages for HTTPS.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  extended_log:
    description:
      - Enable/disable extended logging for web filtering.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  comment:
    description:
      - Optional comments.
    required: false

  ftgd_wf:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  ftgd_wf_exempt_quota:
    description:
      - Do not stop quota for these categories.
    required: false

  ftgd_wf_max_quota_timeout:
    description:
      - Maximum FortiGuard quota used by single page view in seconds (excludes streams).
    required: false

  ftgd_wf_options:
    description:
      - Options for FortiGuard Web Filter.
      - FLAG Based Options. Specify multiple in list form.
      - flag | error-allow | Allow web pages with a rating error to pass through.
      - flag | rate-server-ip | Rate the server IP in addition to the domain name.
      - flag | connect-request-bypass | Bypass connection which has CONNECT request.
      - flag | ftgd-disable | Disable FortiGuard scanning.
    required: false
    choices: ["error-allow", "rate-server-ip", "connect-request-bypass", "ftgd-disable"]

  ftgd_wf_ovrd:
    description:
      - Allow web filter profile overrides.
    required: false

  ftgd_wf_rate_crl_urls:
    description:
      - Enable/disable rating CRL by URL.
      - choice | disable | Disable rating CRL by URL.
      - choice | enable | Enable rating CRL by URL.
    required: false
    choices: ["disable", "enable"]

  ftgd_wf_rate_css_urls:
    description:
      - Enable/disable rating CSS by URL.
      - choice | disable | Disable rating CSS by URL.
      - choice | enable | Enable rating CSS by URL.
    required: false
    choices: ["disable", "enable"]

  ftgd_wf_rate_image_urls:
    description:
      - Enable/disable rating images by URL.
      - choice | disable | Disable rating images by URL (blocked images are replaced with blanks).
      - choice | enable | Enable rating images by URL (blocked images are replaced with blanks).
    required: false
    choices: ["disable", "enable"]

  ftgd_wf_rate_javascript_urls:
    description:
      - Enable/disable rating JavaScript by URL.
      - choice | disable | Disable rating JavaScript by URL.
      - choice | enable | Enable rating JavaScript by URL.
    required: false
    choices: ["disable", "enable"]

  ftgd_wf_filters_action:
    description:
      - Action to take for matches.
      - choice | block | Block access.
      - choice | monitor | Allow access while logging the action.
      - choice | warning | Allow access after warning the user.
      - choice | authenticate | Authenticate user before allowing access.
    required: false
    choices: ["block", "monitor", "warning", "authenticate"]

  ftgd_wf_filters_auth_usr_grp:
    description:
      - Groups with permission to authenticate.
    required: false

  ftgd_wf_filters_category:
    description:
      - Categories and groups the filter examines.
    required: false

  ftgd_wf_filters_log:
    description:
      - Enable/disable logging.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  ftgd_wf_filters_override_replacemsg:
    description:
      - Override replacement message.
    required: false

  ftgd_wf_filters_warn_duration:
    description:
      - Duration of warnings.
    required: false

  ftgd_wf_filters_warning_duration_type:
    description:
      - Re-display warning after closing browser or after a timeout.
      - choice | session | After session ends.
      - choice | timeout | After timeout occurs.
    required: false
    choices: ["session", "timeout"]

  ftgd_wf_filters_warning_prompt:
    description:
      - Warning prompts in each category or each domain.
      - choice | per-domain | Per-domain warnings.
      - choice | per-category | Per-category warnings.
    required: false
    choices: ["per-domain", "per-category"]

  ftgd_wf_quota_category:
    description:
      - FortiGuard categories to apply quota to (category action must be set to monitor).
    required: false

  ftgd_wf_quota_duration:
    description:
      - Duration of quota.
    required: false

  ftgd_wf_quota_override_replacemsg:
    description:
      - Override replacement message.
    required: false

  ftgd_wf_quota_type:
    description:
      - Quota type.
      - choice | time | Use a time-based quota.
      - choice | traffic | Use a traffic-based quota.
    required: false
    choices: ["time", "traffic"]

  ftgd_wf_quota_unit:
    description:
      - Traffic quota unit of measurement.
      - choice | B | Quota in bytes.
      - choice | KB | Quota in kilobytes.
      - choice | MB | Quota in megabytes.
      - choice | GB | Quota in gigabytes.
    required: false
    choices: ["B", "KB", "MB", "GB"]

  ftgd_wf_quota_value:
    description:
      - Traffic quota value.
    required: false

  override:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  override_ovrd_cookie:
    description:
      - Allow/deny browser-based (cookie) overrides.
      - choice | deny | Deny browser-based (cookie) override.
      - choice | allow | Allow browser-based (cookie) override.
    required: false
    choices: ["deny", "allow"]

  override_ovrd_dur:
    description:
      - Override duration.
    required: false

  override_ovrd_dur_mode:
    description:
      - Override duration mode.
      - choice | constant | Constant mode.
      - choice | ask | Prompt for duration when initiating an override.
    required: false
    choices: ["constant", "ask"]

  override_ovrd_scope:
    description:
      - Override scope.
      - choice | user | Override for the user.
      - choice | user-group | Override for the user's group.
      - choice | ip | Override for the initiating IP.
      - choice | ask | Prompt for scope when initiating an override.
      - choice | browser | Create browser-based (cookie) override.
    required: false
    choices: ["user", "user-group", "ip", "ask", "browser"]

  override_ovrd_user_group:
    description:
      - User groups with permission to use the override.
    required: false

  override_profile:
    description:
      - Web filter profile with permission to create overrides.
    required: false

  override_profile_attribute:
    description:
      - Profile attribute to retrieve from the RADIUS server.
      - choice | User-Name | Use this attribute.
      - choice | NAS-IP-Address | Use this attribute.
      - choice | Framed-IP-Address | Use this attribute.
      - choice | Framed-IP-Netmask | Use this attribute.
      - choice | Filter-Id | Use this attribute.
      - choice | Login-IP-Host | Use this attribute.
      - choice | Reply-Message | Use this attribute.
      - choice | Callback-Number | Use this attribute.
      - choice | Callback-Id | Use this attribute.
      - choice | Framed-Route | Use this attribute.
      - choice | Framed-IPX-Network | Use this attribute.
      - choice | Class | Use this attribute.
      - choice | Called-Station-Id | Use this attribute.
      - choice | Calling-Station-Id | Use this attribute.
      - choice | NAS-Identifier | Use this attribute.
      - choice | Proxy-State | Use this attribute.
      - choice | Login-LAT-Service | Use this attribute.
      - choice | Login-LAT-Node | Use this attribute.
      - choice | Login-LAT-Group | Use this attribute.
      - choice | Framed-AppleTalk-Zone | Use this attribute.
      - choice | Acct-Session-Id | Use this attribute.
      - choice | Acct-Multi-Session-Id | Use this attribute.
    required: false
    choices:
      - User-Name
      - NAS-IP-Address
      - Framed-IP-Address
      - Framed-IP-Netmask
      - Filter-Id
      - Login-IP-Host
      - Reply-Message
      - Callback-Number
      - Callback-Id
      - Framed-Route
      - Framed-IPX-Network
      - Class
      - Called-Station-Id
      - Calling-Station-Id
      - NAS-Identifier
      - Proxy-State
      - Login-LAT-Service
      - Login-LAT-Node
      - Login-LAT-Group
      - Framed-AppleTalk-Zone
      - Acct-Session-Id
      - Acct-Multi-Session-Id

  override_profile_type:
    description:
      - Override profile type.
      - choice | list | Profile chosen from list.
      - choice | radius | Profile determined by RADIUS server.
    required: false
    choices: ["list", "radius"]

  url_extraction:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  url_extraction_redirect_header:
    description:
      - HTTP header name to use for client redirect on blocked requests
    required: false

  url_extraction_redirect_no_content:
    description:
      - Enable / Disable empty message-body entity in HTTP response
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  url_extraction_redirect_url:
    description:
      - HTTP header value to use for client redirect on blocked requests
    required: false

  url_extraction_server_fqdn:
    description:
      - URL extraction server FQDN (fully qualified domain name)
    required: false

  url_extraction_status:
    description:
      - Enable URL Extraction
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  web:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  web_blacklist:
    description:
      - Enable/disable automatic addition of URLs detected by FortiSandbox to blacklist.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  web_bword_table:
    description:
      - Banned word table ID.
    required: false

  web_bword_threshold:
    description:
      - Banned word score threshold.
    required: false

  web_content_header_list:
    description:
      - Content header list.
    required: false

  web_keyword_match:
    description:
      - Search keywords to log when match is found.
    required: false

  web_log_search:
    description:
      - Enable/disable logging all search phrases.
      - choice | disable | Disable setting.
      - choice | enable | Enable setting.
    required: false
    choices: ["disable", "enable"]

  web_safe_search:
    description:
      - Safe search type.
      - FLAG Based Options. Specify multiple in list form.
      - flag | url | Insert safe search string into URL.
      - flag | header | Insert safe search header.
    required: false
    choices: ["url", "header"]

  web_urlfilter_table:
    description:
      - URL filter table ID.
    required: false

  web_whitelist:
    description:
      - FortiGuard whitelist settings.
      - FLAG Based Options. Specify multiple in list form.
      - flag | exempt-av | Exempt antivirus.
      - flag | exempt-webcontent | Exempt web content.
      - flag | exempt-activex-java-cookie | Exempt ActiveX-JAVA-Cookie.
      - flag | exempt-dlp | Exempt DLP.
      - flag | exempt-rangeblock | Exempt RangeBlock.
      - flag | extended-log-others | Support extended log.
    required: false
    choices:
      - exempt-av
      - exempt-webcontent
      - exempt-activex-java-cookie
      - exempt-dlp
      - exempt-rangeblock
      - extended-log-others

  web_youtube_restrict:
    description:
      - YouTube EDU filter level.
      - choice | strict | Strict access for YouTube.
      - choice | none | Full access for YouTube.
      - choice | moderate | Moderate access for YouTube.
    required: false
    choices: ["strict", "none", "moderate"]

  youtube_channel_filter:
    description:
      - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
      - List of multiple child objects to be added. Expects a list of dictionaries.
      - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
      - If submitted, all other prefixed sub-parameters ARE IGNORED.
      - This object is MUTUALLY EXCLUSIVE with its options.
      - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
      - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
    required: false

  youtube_channel_filter_channel_id:
    description:
      - YouTube channel ID to be filtered.
    required: false

  youtube_channel_filter_comment:
    description:
      - Comment.
    required: false


'''

EXAMPLES = '''
  - name: DELETE Profile
    fmgr_secprof_web:
      name: "Ansible_Web_Filter_Profile"
      mode: "delete"

  - name: CREATE Profile
    fmgr_secprof_web:
      name: "Ansible_Web_Filter_Profile"
      comment: "Created by Ansible Module TEST"
      mode: "set"
      extended_log: "enable"
      inspection_mode: "proxy"
      log_all_url: "enable"
      options: "js"
      ovrd_perm: "bannedword-override"
      post_action: "block"
      web_content_log: "enable"
      web_extended_all_action_log: "enable"
      web_filter_activex_log: "enable"
      web_filter_applet_log: "enable"
      web_filter_command_block_log: "enable"
      web_filter_cookie_log: "enable"
      web_filter_cookie_removal_log: "enable"
      web_filter_js_log: "enable"
      web_filter_jscript_log: "enable"
      web_filter_referer_log: "enable"
      web_filter_unknown_log: "enable"
      web_filter_vbs_log: "enable"
      web_ftgd_err_log: "enable"
      web_ftgd_quota_usage: "enable"
      web_invalid_domain_log: "enable"
      web_url_log: "enable"
      wisp: "enable"
      wisp_algorithm: "auto-learning"
      youtube_channel_status: "blacklist"
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
from ansible.module_utils.network.fortimanager.common import FMGRCommon
from ansible.module_utils.network.fortimanager.common import FMGRMethods
from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
from ansible.module_utils.network.fortimanager.common import prepare_dict
from ansible.module_utils.network.fortimanager.common import scrub_dict


def fmgr_webfilter_profile_modify(fmgr, paramgram):

    mode = paramgram["mode"]
    adom = paramgram["adom"]

    response = DEFAULT_RESULT_OBJ
    url = ""
    datagram = {}

    # EVAL THE MODE PARAMETER FOR SET OR ADD
    if mode in ['set', 'add', 'update']:
        url = '/pm/config/adom/{adom}/obj/webfilter/profile'.format(adom=adom)
        datagram = scrub_dict(prepare_dict(paramgram))

    # EVAL THE MODE PARAMETER FOR DELETE
    elif mode == "delete":
        # SET THE CORRECT URL FOR DELETE
        url = '/pm/config/adom/{adom}/obj/webfilter/profile/{name}'.format(adom=adom, name=paramgram["name"])
        datagram = {}

    response = fmgr.process_request(url, datagram, paramgram["mode"])

    return response


#############
# END METHODS
#############


def main():
    argument_spec = dict(
        adom=dict(type="str", default="root"),
        mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),

        youtube_channel_status=dict(required=False, type="str", choices=["disable", "blacklist", "whitelist"]),
        wisp_servers=dict(required=False, type="str"),
        wisp_algorithm=dict(required=False, type="str", choices=["auto-learning", "primary-secondary", "round-robin"]),
        wisp=dict(required=False, type="str", choices=["disable", "enable"]),
        web_url_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_invalid_domain_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_ftgd_quota_usage=dict(required=False, type="str", choices=["disable", "enable"]),
        web_ftgd_err_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_filter_vbs_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_filter_unknown_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_filter_referer_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_filter_jscript_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_filter_js_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_filter_cookie_removal_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_filter_cookie_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_filter_command_block_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_filter_applet_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_filter_activex_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_extended_all_action_log=dict(required=False, type="str", choices=["disable", "enable"]),
        web_content_log=dict(required=False, type="str", choices=["disable", "enable"]),
        replacemsg_group=dict(required=False, type="str"),
        post_action=dict(required=False, type="str", choices=["normal", "block"]),
        ovrd_perm=dict(required=False, type="list", choices=["bannedword-override",
                                                             "urlfilter-override",
                                                             "fortiguard-wf-override",
                                                             "contenttype-check-override"]),
        options=dict(required=False, type="list", choices=["block-invalid-url",
                                                           "jscript",
                                                           "js",
                                                           "vbs",
                                                           "unknown",
                                                           "wf-referer",
                                                           "intrinsic",
                                                           "wf-cookie",
                                                           "per-user-bwl",
                                                           "activexfilter",
                                                           "cookiefilter",
                                                           "javafilter"]),
        name=dict(required=False, type="str"),
        log_all_url=dict(required=False, type="str", choices=["disable", "enable"]),
        inspection_mode=dict(required=False, type="str", choices=["proxy", "flow-based"]),
        https_replacemsg=dict(required=False, type="str", choices=["disable", "enable"]),
        extended_log=dict(required=False, type="str", choices=["disable", "enable"]),
        comment=dict(required=False, type="str"),
        ftgd_wf=dict(required=False, type="list"),
        ftgd_wf_exempt_quota=dict(required=False, type="str"),
        ftgd_wf_max_quota_timeout=dict(required=False, type="int"),
        ftgd_wf_options=dict(required=False, type="str", choices=["error-allow", "rate-server-ip",
                                                                  "connect-request-bypass", "ftgd-disable"]),
        ftgd_wf_ovrd=dict(required=False, type="str"),
        ftgd_wf_rate_crl_urls=dict(required=False, type="str", choices=["disable", "enable"]),
        ftgd_wf_rate_css_urls=dict(required=False, type="str", choices=["disable", "enable"]),
        ftgd_wf_rate_image_urls=dict(required=False, type="str", choices=["disable", "enable"]),
        ftgd_wf_rate_javascript_urls=dict(required=False, type="str", choices=["disable", "enable"]),

        ftgd_wf_filters_action=dict(required=False, type="str", choices=["block", "monitor",
                                                                         "warning", "authenticate"]),
        ftgd_wf_filters_auth_usr_grp=dict(required=False, type="str"),
        ftgd_wf_filters_category=dict(required=False, type="str"),
        ftgd_wf_filters_log=dict(required=False, type="str", choices=["disable", "enable"]),
        ftgd_wf_filters_override_replacemsg=dict(required=False, type="str"),
        ftgd_wf_filters_warn_duration=dict(required=False, type="str"),
        ftgd_wf_filters_warning_duration_type=dict(required=False, type="str", choices=["session", "timeout"]),
        ftgd_wf_filters_warning_prompt=dict(required=False, type="str", choices=["per-domain", "per-category"]),

        ftgd_wf_quota_category=dict(required=False, type="str"),
        ftgd_wf_quota_duration=dict(required=False, type="str"),
        ftgd_wf_quota_override_replacemsg=dict(required=False, type="str"),
        ftgd_wf_quota_type=dict(required=False, type="str", choices=["time", "traffic"]),
        ftgd_wf_quota_unit=dict(required=False, type="str", choices=["B", "KB", "MB", "GB"]),
        ftgd_wf_quota_value=dict(required=False, type="int"),
        override=dict(required=False, type="list"),
        override_ovrd_cookie=dict(required=False, type="str", choices=["deny", "allow"]),
        override_ovrd_dur=dict(required=False, type="str"),
        override_ovrd_dur_mode=dict(required=False, type="str", choices=["constant", "ask"]),
        override_ovrd_scope=dict(required=False, type="str", choices=["user", "user-group", "ip", "ask", "browser"]),
        override_ovrd_user_group=dict(required=False, type="str"),
        override_profile=dict(required=False, type="str"),
        override_profile_attribute=dict(required=False, type="list", choices=["User-Name",
                                                                              "NAS-IP-Address",
                                                                              "Framed-IP-Address",
                                                                              "Framed-IP-Netmask",
                                                                              "Filter-Id",
                                                                              "Login-IP-Host",
                                                                              "Reply-Message",
                                                                              "Callback-Number",
                                                                              "Callback-Id",
                                                                              "Framed-Route",
                                                                              "Framed-IPX-Network",
                                                                              "Class",
                                                                              "Called-Station-Id",
                                                                              "Calling-Station-Id",
                                                                              "NAS-Identifier",
                                                                              "Proxy-State",
                                                                              "Login-LAT-Service",
                                                                              "Login-LAT-Node",
                                                                              "Login-LAT-Group",
                                                                              "Framed-AppleTalk-Zone",
                                                                              "Acct-Session-Id",
                                                                              "Acct-Multi-Session-Id"]),
        override_profile_type=dict(required=False, type="str", choices=["list", "radius"]),
        url_extraction=dict(required=False, type="list"),
        url_extraction_redirect_header=dict(required=False, type="str"),
        url_extraction_redirect_no_content=dict(required=False, type="str", choices=["disable", "enable"]),
        url_extraction_redirect_url=dict(required=False, type="str"),
        url_extraction_server_fqdn=dict(required=False, type="str"),
        url_extraction_status=dict(required=False, type="str", choices=["disable", "enable"]),
        web=dict(required=False, type="list"),
        web_blacklist=dict(required=False, type="str", choices=["disable", "enable"]),
        web_bword_table=dict(required=False, type="str"),
        web_bword_threshold=dict(required=False, type="int"),
        web_content_header_list=dict(required=False, type="str"),
        web_keyword_match=dict(required=False, type="str"),
        web_log_search=dict(required=False, type="str", choices=["disable", "enable"]),
        web_safe_search=dict(required=False, type="str", choices=["url", "header"]),
        web_urlfilter_table=dict(required=False, type="str"),
        web_whitelist=dict(required=False, type="list", choices=["exempt-av",
                                                                 "exempt-webcontent",
                                                                 "exempt-activex-java-cookie",
                                                                 "exempt-dlp",
                                                                 "exempt-rangeblock",
                                                                 "extended-log-others"]),
        web_youtube_restrict=dict(required=False, type="str", choices=["strict", "none", "moderate"]),
        youtube_channel_filter=dict(required=False, type="list"),
        youtube_channel_filter_channel_id=dict(required=False, type="str"),
        youtube_channel_filter_comment=dict(required=False, type="str"),

    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    # MODULE PARAMGRAM
    paramgram = {
        "mode": module.params["mode"],
        "adom": module.params["adom"],
        "youtube-channel-status": module.params["youtube_channel_status"],
        "wisp-servers": module.params["wisp_servers"],
        "wisp-algorithm": module.params["wisp_algorithm"],
        "wisp": module.params["wisp"],
        "web-url-log": module.params["web_url_log"],
        "web-invalid-domain-log": module.params["web_invalid_domain_log"],
        "web-ftgd-quota-usage": module.params["web_ftgd_quota_usage"],
        "web-ftgd-err-log": module.params["web_ftgd_err_log"],
        "web-filter-vbs-log": module.params["web_filter_vbs_log"],
        "web-filter-unknown-log": module.params["web_filter_unknown_log"],
        "web-filter-referer-log": module.params["web_filter_referer_log"],
        "web-filter-jscript-log": module.params["web_filter_jscript_log"],
        "web-filter-js-log": module.params["web_filter_js_log"],
        "web-filter-cookie-removal-log": module.params["web_filter_cookie_removal_log"],
        "web-filter-cookie-log": module.params["web_filter_cookie_log"],
        "web-filter-command-block-log": module.params["web_filter_command_block_log"],
        "web-filter-applet-log": module.params["web_filter_applet_log"],
        "web-filter-activex-log": module.params["web_filter_activex_log"],
        "web-extended-all-action-log": module.params["web_extended_all_action_log"],
        "web-content-log": module.params["web_content_log"],
        "replacemsg-group": module.params["replacemsg_group"],
        "post-action": module.params["post_action"],
        "ovrd-perm": module.params["ovrd_perm"],
        "options": module.params["options"],
        "name": module.params["name"],
        "log-all-url": module.params["log_all_url"],
        "inspection-mode": module.params["inspection_mode"],
        "https-replacemsg": module.params["https_replacemsg"],
        "extended-log": module.params["extended_log"],
        "comment": module.params["comment"],
        "ftgd-wf": {
            "exempt-quota": module.params["ftgd_wf_exempt_quota"],
            "max-quota-timeout": module.params["ftgd_wf_max_quota_timeout"],
            "options": module.params["ftgd_wf_options"],
            "ovrd": module.params["ftgd_wf_ovrd"],
            "rate-crl-urls": module.params["ftgd_wf_rate_crl_urls"],
            "rate-css-urls": module.params["ftgd_wf_rate_css_urls"],
            "rate-image-urls": module.params["ftgd_wf_rate_image_urls"],
            "rate-javascript-urls": module.params["ftgd_wf_rate_javascript_urls"],
            "filters": {
                "action": module.params["ftgd_wf_filters_action"],
                "auth-usr-grp": module.params["ftgd_wf_filters_auth_usr_grp"],
                "category": module.params["ftgd_wf_filters_category"],
                "log": module.params["ftgd_wf_filters_log"],
                "override-replacemsg": module.params["ftgd_wf_filters_override_replacemsg"],
                "warn-duration": module.params["ftgd_wf_filters_warn_duration"],
                "warning-duration-type": module.params["ftgd_wf_filters_warning_duration_type"],
                "warning-prompt": module.params["ftgd_wf_filters_warning_prompt"],
            },
            "quota": {
                "category": module.params["ftgd_wf_quota_category"],
                "duration": module.params["ftgd_wf_quota_duration"],
                "override-replacemsg": module.params["ftgd_wf_quota_override_replacemsg"],
                "type": module.params["ftgd_wf_quota_type"],
                "unit": module.params["ftgd_wf_quota_unit"],
                "value": module.params["ftgd_wf_quota_value"],
            },
        },
        "override": {
            "ovrd-cookie": module.params["override_ovrd_cookie"],
            "ovrd-dur": module.params["override_ovrd_dur"],
            "ovrd-dur-mode": module.params["override_ovrd_dur_mode"],
            "ovrd-scope": module.params["override_ovrd_scope"],
            "ovrd-user-group": module.params["override_ovrd_user_group"],
            "profile": module.params["override_profile"],
            "profile-attribute": module.params["override_profile_attribute"],
            "profile-type": module.params["override_profile_type"],
        },
        "url-extraction": {
            "redirect-header": module.params["url_extraction_redirect_header"],
            "redirect-no-content": module.params["url_extraction_redirect_no_content"],
            "redirect-url": module.params["url_extraction_redirect_url"],
            "server-fqdn": module.params["url_extraction_server_fqdn"],
            "status": module.params["url_extraction_status"],
        },
        "web": {
            "blacklist": module.params["web_blacklist"],
            "bword-table": module.params["web_bword_table"],
            "bword-threshold": module.params["web_bword_threshold"],
            "content-header-list": module.params["web_content_header_list"],
            "keyword-match": module.params["web_keyword_match"],
            "log-search": module.params["web_log_search"],
            "safe-search": module.params["web_safe_search"],
            "urlfilter-table": module.params["web_urlfilter_table"],
            "whitelist": module.params["web_whitelist"],
            "youtube-restrict": module.params["web_youtube_restrict"],
        },
        "youtube-channel-filter": {
            "channel-id": module.params["youtube_channel_filter_channel_id"],
            "comment": module.params["youtube_channel_filter_comment"],
        }
    }
    module.paramgram = paramgram
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    list_overrides = ['ftgd-wf', 'override', 'url-extraction', 'web', 'youtube-channel-filter']
    paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
                                                         paramgram=paramgram, module=module)

    results = DEFAULT_RESULT_OBJ

    try:

        results = fmgr_webfilter_profile_modify(fmgr, paramgram)
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

fmgr_sys_proxy

Metadata

Name: fmgr_sys_proxy

Description: The FMG proxies FOS API calls via the FMG. Review FortiGate API documentation to ensure you are passing correct parameters for both the FortiManager and FortiGate

Author(s): Andrew Welsh

Ansible Version Added/Required: 2.8

Dev Status: CODE UPDATE IN PROGRESS

Owning Developer: Andrew Welsh

Pull Request Started:

Days in PR:

Module Github Link

Parameters
action
  • Description: Specify HTTP action for the request. Either ‘get’ or ‘post’
  • Required: True
adom
  • Description: The administrative domain (admon) the configuration belongs to
  • Required: True
payload
  • Description: JSON payload of the request. The payload will be URL-encoded and becomes the “json” field in the query string for both GET and POST request.
  • Required: False
resource
  • Description: URL on the remote device to be accessed, string
  • Required: True
target
  • Description: FOS datasource, either device or group object
  • Required: True
Functions
  • fos_request
def fos_request(fmgr, action, resource, target, payload, adom='root'):

    datagram = {
        "data": {
            # get or post
            "action": action,
            # dictionary of data
            "payload": payload,
            # FOS API URL including vdom params
            "resource": resource,
            # FMG device to make API calls to
            "target": target
        },

    }
    url = "/sys/proxy/json"

    status, response = fmgr.process_request(url, datagram, action)
    return status, response
  • main
def main():

    argument_spec = dict(
        adom=dict(required=False, type="str"),
        host=dict(required=True, type="str"),
        password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True),
        username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"]), no_log=True),

        action=dict(required=False, type="str"),
        resource=dict(required=False, type="str"),
        target=dict(required=False, type="str"),
        payload=dict(required=False, type="str"),
    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module.check_mode)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    action = module.params["action"]
    resource = module.params["resource"]
    target = module.params["target"]
    payload = module.params["payload"]
    if module.params["adom"] is None:
        module.params["adom"] = 'root'

    # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION
    results = DEFAULT_RESULT_OBJ
    try:
        status, result = fos_request(fmgr, action, resource, target, payload, module.params["adom"])
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, payload))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(changed=True, **result)
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function

__metaclass__ = type

ANSIBLE_METADATA = {'status': ['preview'],
                    'supported_by': 'community',
                    'metadata_version': '1.1'}

DOCUMENTATION = '''
---
module: fmgr_sys_proxy
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author: Andrew Welsh
short_description: Make FortiGate API calls via the FortiMananger
description:
  - The FMG proxies FOS API calls via the FMG.  Review FortiGate API documentation to ensure you are passing correct
    parameters for both the FortiManager and FortiGate

options:
  adom:
    description:
      - The administrative domain (admon) the configuration belongs to
    required: true
  action:
    description:
      - Specify HTTP action for the request. Either 'get' or 'post'
    required: True
  payload:
    description:
      - JSON payload of the request. The payload will be URL-encoded and becomes the "json" field in the query string for both GET and POST request.
    required: False
  resource:
    description:
      - URL on the remote device to be accessed, string
    required: True
  target:
    description:
      - FOS datasource, either device or group object
    required: True

'''

EXAMPLES = '''
- name: Proxy FOS requests via FMG
  hosts: FortiManager
  connection: local
  gather_facts: False

  tasks:

    - name: Get upgrade path for FGT1
      fmgr_provision:
        adom: "root"
        action: "get"
        resource: "/api/v2/monitor/system/firmware/upgrade-paths?vdom=root"
        target: ["/adom/root/device/FGT1"]
    - name: Upgrade firmware of FGT1
      fmgr_provision:
        adom: "root"
        action: "post"
        payload: {source: upload, file_content: b64_encoded_string, file_name: file_name}
        resource: "/api/v2/monitor/system/firmware/upgrade?vdom=vdom"
        target: ["/adom/root/device/FGT1"]

'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: string
"""


from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
from ansible.module_utils.network.fortimanager.common import FMGBaseException
#from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
from ansible.module_utils.network.fortimanager.common import prepare_dict
from ansible.module_utils.network.fortimanager.common import scrub_dict


def fos_request(fmgr, action, resource, target, payload, adom='root'):

    datagram = {
        "data": {
            # get or post
            "action": action,
            # dictionary of data
            "payload": payload,
            # FOS API URL including vdom params
            "resource": resource,
            # FMG device to make API calls to
            "target": target
        },

    }
    url = "/sys/proxy/json"

    status, response = fmgr.process_request(url, datagram, action)
    return status, response


def main():

    argument_spec = dict(
        adom=dict(required=False, type="str"),
        host=dict(required=True, type="str"),
        password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True),
        username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"]), no_log=True),

        action=dict(required=False, type="str"),
        resource=dict(required=False, type="str"),
        target=dict(required=False, type="str"),
        payload=dict(required=False, type="str"),
    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    fmgr = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        fmgr = FortiManagerHandler(connection, module.check_mode)
        fmgr.tools = FMGRCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    action = module.params["action"]
    resource = module.params["resource"]
    target = module.params["target"]
    payload = module.params["payload"]
    if module.params["adom"] is None:
        module.params["adom"] = 'root'

    # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION
    results = DEFAULT_RESULT_OBJ
    try:
        status, result = fos_request(fmgr, action, resource, target, payload, module.params["adom"])
        fmgr.govern_response(module=module, results=results,
                             ansible_facts=fmgr.construct_ansible_facts(results, module.params, payload))

    except Exception as err:
        raise FMGBaseException(err)

    return module.exit_json(changed=True, **result)


if __name__ == "__main__":
    main()

Playbook Examples

fmgr_device

Playbook Task Examples
- name: DISCOVER AND ADD DEVICE FGT1
  fmgr_device:
    adom: "root"
    device_username: "admin"
    device_password: "admin"
    device_ip: "10.10.24.201"
    device_unique_name: "FGT1"
    device_serial: "FGVM000000117994"
    mode: "add"
    blind_add: "enable"

- name: DISCOVER AND ADD DEVICE FGT2
  fmgr_device:
    adom: "root"
    device_username: "admin"
    device_password: "admin"
    device_ip: "10.10.24.202"
    device_unique_name: "FGT2"
    device_serial: "FGVM000000117992"
    mode: "delete"
Playbook File Examples
fmgr_devices_ansibleAdom.yml
- name: DISCOVER AND ADD DEVICES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: DISCOVER AND ADD DEVICE FGT1
      fmgr_device:
        #hard coded fortimanager example host and login -- see "fmg_group_add.yml for ansible host file version"
        #HARD CODED LOGIN FOR FORTIMANAGER SEE "fmg_group_add.yml" example for anisble host version
        #ADOM TO ADD THE DEVICE TO
        adom: "ansible"
        #DEVICE LOGIN
        device_username: "admin"
        device_password: "fortinet"
        #DEVICE IP ADDRESS
        device_ip: "10.7.220.151"
        #FRIENDLY NAME FOR DEVICE IN FORTIMANAGER
        device_unique_name: "FGT1"
    - name: DISCOVER AND ADD DEVICE FGT2
      fmgr_device:
        adom: "ansible"
        device_username: "admin"
        device_password: "fortinet"
        device_ip: "10.7.220.152"
        device_unique_name: "FGT2"
    - name: DISCOVER AND ADD DEVICE FGT3
      fmgr_device:
        adom: "ansible"
        device_username: "admin"
        device_password: "fortinet"
        device_ip: "10.7.220.153"
        device_unique_name: "FGT3"
fmgr_device_run_all.sh
        #!/bin/bash
ansible-playbook fmgr_devices_ansibleAdom.yml -vvvv
ansible-playbook fmgr_devices_plugin_edition_add.yml -vvvv
ansible-playbook fmgr_devices_ansibleAdom_all.yml -vvvv
ansible-playbook fmgr_devices_delete_ansibleAdom.yml -vvvv
ansible-playbook fmgr_devices_plugin_edition_del.yml -vvvv
ansible-playbook fmgr_devices.yml -vvvv
ansible-playbook fmgr_devices_ipv6_add.yml -vvvv
ansible-playbook fmgr_devices_ansibleAdom2.yml -vvvv
fmgr_devices_plugin_edition_add.yml
- name: DISCOVER AND ADD DEVICES via PLUGIN
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: DISCOVER AND ADD DEVICE FGT1
      fmgr_device:
        adom: "ansible"
        device_username: "admin"
        device_password: "fortinet"
        device_ip: "10.7.220.151"
        device_unique_name: "FGT1"
        mode: "add"
      ignore_errors: yes
      ignore_unreachable: yes

    - name: DISCOVER AND ADD DEVICE FGT2
      fmgr_device:
        adom: "ansible"
        device_username: "admin"
        device_password: "fortinet"
        device_ip: "10.7.220.152"
        device_unique_name: "FGT2"
        #blind_add: "enable"
      ignore_errors: yes
      ignore_unreachable: yes

    - name: DISCOVER AND ADD DEVICE FGT3
      fmgr_device:
        adom: "ansible"
        device_username: "admin"
        device_password: "fortinet"
        device_ip: "10.7.220.153"
        device_unique_name: "FGT3"
      ignore_errors: yes
      ignore_unreachable: yes
fmgr_devices_ansibleAdom_all.yml
- name: DISCOVER AND ADD DEVICES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: DISCOVER AND ADD DEVICE FGT4
      fmgr_device:
        adom: "ansible"
        #DEVICE LOGIN
        device_username: "admin"
        device_password: "fortinet"
        #DEVICE IP ADDRESS
        device_ip: "10.7.220.164"
        #FRIENDLY NAME FOR DEVICE IN FORTIMANAGER
        device_unique_name: "FGT4"
    - name: DISCOVER AND ADD DEVICE FGT5
      fmgr_device:
        adom: "ansible"
        device_username: "admin"
        device_password: "fortinet"
        device_ip: "10.7.220.165"
        device_unique_name: "FGT5"
    - name: DISCOVER AND ADD DEVICE FGT6
      fmgr_device:
        adom: "ansible"
        device_username: "admin"
        device_password: "fortinet"
        device_ip: "10.7.220.166"
        device_unique_name: "FGT6"
    - name: DISCOVER AND ADD DEVICE FGT1
      fmgr_device:
        adom: "ansible"
        #DEVICE LOGIN
        device_username: "admin"
        device_password: "fortinet"
        #DEVICE IP ADDRESS
        device_ip: "10.7.220.151"
        #FRIENDLY NAME FOR DEVICE IN FORTIMANAGER
        device_unique_name: "FGT1"
    - name: DISCOVER AND ADD DEVICE FGT2
      fmgr_device:
        adom: "ansible"
        device_username: "admin"
        device_password: "fortinet"
        device_ip: "10.7.220.152"
        device_unique_name: "FGT2"
    - name: DISCOVER AND ADD DEVICE FGT3
      fmgr_device:
        adom: "ansible"
        device_username: "admin"
        device_password: "fortinet"
        device_ip: "10.7.220.153"
        device_unique_name: "FGT3"
fmgr_devices_delete_ansibleAdom.yml
- name: DISCOVER AND ADD DEVICES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: DISCOVER AND ADD DEVICE FGT1
      fmgr_device:
        #hard coded fortimanager example host and login -- see "fmg_group_add.yml for ansible host file version"
        #HARD CODED LOGIN FOR FORTIMANAGER SEE "fmg_group_add.yml" example for anisble host version
        #ADOM TO ADD THE DEVICE TO
        adom: "ansible"
        #DEVICE LOGIN
        device_username: "admin"
        device_password: "fortinet"
        #DEVICE IP ADDRESS
        device_ip: "10.7.220.151"
        #FRIENDLY NAME FOR DEVICE IN FORTIMANAGER
        device_unique_name: "FGT1"
        #SERIAL NUMBER OF DEVICE
        state: "absent"
    - name: DISCOVER AND ADD DEVICE FGT2
      fmgr_device:
        adom: "ansible"
        device_username: "admin"
        device_password: "fortinet"
        device_ip: "10.7.220.152"
        device_unique_name: "FGT2"
        state: "absent"
    - name: DISCOVER AND ADD DEVICE FGT3
      fmgr_device:
        adom: "ansible"
        device_username: "admin"
        device_password: "fortinet"
        device_ip: "10.7.220.153"
        device_unique_name: "FGT3"
        state: "absent"
fmgr_devices_plugin_edition_del.yml
- name: DISCOVER AND ADD DEVICES via PLUGIN
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: DISCOVER AND ADD DEVICE FGT1
      fmgr_device:
        device_username: "admin"
        device_password: "fortinet"
        device_ip: "10.7.220.151"
        device_unique_name: "FGT1"
        mode: "delete"
#      ignore_errors: yes

    - name: DISCOVER AND ADD DEVICE FGT2
      fmgr_device:
        adom: "ansible"
        device_username: "admin"
        device_password: "fortinet"
        device_ip: "10.7.220.152"
        device_unique_name: "FGT2"
        mode: "delete"
#      ignore_errors: yes

    - name: DISCOVER AND ADD DEVICE FGT3
      fmgr_device:
        adom: "ansible"
        device_username: "admin"
        device_password: "fortinet"
        device_ip: "10.7.220.153"
        device_unique_name: "FGT3"
        mode: "delete"
#      ignore_errors: yes
fmgr_devices.yml
- name: DISCOVER AND ADD DEVICES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: DISCOVER AND ADD DEVICE FGT1
      fmgr_device:
        adom: "root"
        device_username: "admin"
        device_password: "fortinet"
        device_ip: "10.10.24.201"
        device_unique_name: "FGT1"
        device_serial: "FGVM000000117994"
    - name: DISCOVER AND ADD DEVICE FGT2
      fmgr_device:
        adom: "root"
        device_username: "admin"
        device_password: "fortinet"
        device_ip: "10.10.24.202"
        device_unique_name: "FGT2"
        device_serial: "FGVM000000117992"
fmgr_devices_ipv6_add.yml
- name: DISCOVER AND ADD DEVICES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: DISCOVER AND ADD DEVICE FGT1 IPv6
      fmgr_device:
        adom: "ansible"
        device_username: "admin"
        device_password: "fortinet"
        device_ip: "fdc3:7fb3:8b9f:468b::2001"
        device_unique_name: "FGT1"
fmgr_devices_ansibleAdom2.yml
- name: DISCOVER AND ADD DEVICES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: DISCOVER AND ADD DEVICE FGT4
      fmgr_device:
        #hard coded fortimanager example host and login -- see "fmg_group_add.yml for ansible host file version"
        #HARD CODED LOGIN FOR FORTIMANAGER SEE "fmg_group_add.yml" example for anisble host version
        #ADOM TO ADD THE DEVICE TO
        adom: "ansible"
        #DEVICE LOGIN
        device_username: "admin"
        device_password: "fortinet"
        #DEVICE IP ADDRESS
        device_ip: "10.7.220.164"
        #FRIENDLY NAME FOR DEVICE IN FORTIMANAGER
        device_unique_name: "FGT4"
    - name: DISCOVER AND ADD DEVICE FGT5
      fmgr_device:
        adom: "ansible"
        device_username: "admin"
        device_password: "fortinet"
        device_ip: "10.7.220.165"
        device_unique_name: "FGT5"
    - name: DISCOVER AND ADD DEVICE FGT6
      fmgr_device:
        adom: "ansible"
        device_username: "admin"
        device_password: "fortinet"
        device_ip: "10.7.220.166"
        device_unique_name: "FGT6"
fmgr_devices_pyfmg.yml
- name: DISCOVER AND ADD DEVICES
  hosts: FortiManager
  connection: local
  gather_facts: False

  tasks:
    - name: DISCOVER AND ADD DEVICE FGT1
      fmgr_device:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        adom: "ansible"
        device_username: "admin"
        device_password: "fortinet"
        device_ip: "10.7.220.151"
        device_unique_name: "FGT1"
#    - name: DISCOVER AND ADD DEVICE FGT2
#      fmgr_device:
#        host: "{{ inventory_hostname }}"
#        username: "{{ username }}"
#        password: "{{ password }}"
#        adom: "ansible"
#        device_username: "admin"
#        device_password: "fortinet"
#        device_ip: "10.7.220.152"
#        device_unique_name: "FGT2"
#    - name: DISCOVER AND ADD DEVICE FGT3
#      fmgr_device:
#        host: "{{ inventory_hostname }}"
#        username: "{{ username }}"
#        password: "{{ password }}"
#        adom: "ansible"
#        device_username: "admin"
#        device_password: "fortinet"
#        device_ip: "10.7.220.153"
#        device_unique_name: "FGT3"

fmgr_device_config

Playbook Task Examples
- name: CHANGE HOSTNAME
  fmgr_device_config:
    device_hostname: "ChangedbyAnsible"
    device_unique_name: "FGT1"

- name: EDIT INTERFACE INFORMATION
  fmgr_device_config:
    adom: "root"
    device_unique_name: "FGT2"
    interface: "port3"
    interface_ip: "10.1.1.1/24"
    interface_allow_access: "ping, telnet, https"

- name: INSTALL CONFIG
  fmgr_device_config:
    adom: "root"
    device_unique_name: "FGT1"
    install_config: "enable"
Playbook File Examples
fmgr_device_exec_config.yml
- name: DISCOVER AND ADD DEVICES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: INSTALL CONFIG FGT1
      fmgr_device_config:
        adom: "ansible"
        device_unique_name: "FGT1"
        install_config: "enable"

    - name: INSTALL CONFIG FGT2 and FGT3
      fmgr_device_config:
        adom: "ansible"
        device_unique_name: "FGT2, FGT3"
        install_config: "enable"
fmgr_device_config_run_all.sh
        #!/bin/bash
ansible-playbook fmgr_device_exec_config.yml -vvvv
ansible-playbook fgt01_config.yml -vvvv
ansible-playbook fgt03_config.yml -vvvv
ansible-playbook fmgr_device_config.yml -vvvv
ansible-playbook fgt02_config.yml -vvvv
fgt01_config.yml
- name: CONFIG FGT HOSTNAME AND INTERFACE
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: CHANGE HOSTNAME
    fmgr_device_config:
      device_hostname: "ansible-fgt01"
      device_unique_name: "FGT1"
      adom: "ansible"


  - name: EDIT INTERFACE INFORMATION
    fmgr_device_config:
      adom: "ansible"
      device_unique_name: "FGT1"
      interface: "port2"
      interface_ip: "10.1.1.1/24"
      interface_allow_access: "ping, telnet, https, http"
fgt03_config.yml
- name: CONFIG FGT HOSTNAME AND INTERFACE
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: CHANGE HOSTNAME
    fmgr_device_config:
      #the new hostname for the Fortigate
      device_hostname: "ansible-fgt03"
      #the "friendly name" of the device in FortiManager
      device_unique_name: "FGT3"
      #adom to put the device in
      adom: "ansible"


  - name: EDIT INTERFACE INFORMATION
    fmgr_device_config:
      adom: "ansible"
      device_unique_name: "FGT3"
      #interface to configure
      interface: "port2"
      #ip address to add to interface
      interface_ip: "10.1.3.1/24"
      #edit management access
      interface_allow_access: "ping, telnet, https, http"
fmgr_device_config.yml
- name: DISCOVER AND ADD DEVICES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: CHANGE HOSTNAME
      fmgr_device_config:
        device_hostname: "ChangedbyAnsible"
        device_unique_name: "FGT1"

    - name: EDIT INTERFACE INFORMATION
      fmgr_device_config:
        adom: "root"
        device_unique_name: "FGT2"
        interface: "port3"
        interface_ip: "10.255.1.1/24"
        interface_allow_access: "ping, telnet, https, http"
fgt02_config.yml
- name: CONFIG FGT HOSTNAME AND INTERFACE
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: CHANGE HOSTNAME
    fmgr_device_config:
      #hard coded fortimanager example host and login -- see "fmg_group_add.yml for ansible host file version"
      #the new hostname for the fortigate
      device_hostname: "ansible-fgt02"
      #the "friendly name" of the device in FortiManager
      device_unique_name: "FGT2"
      #adom for device
      adom: "ansible"


  - name: EDIT INTERFACE INFORMATION
    fmgr_device_config:
      adom: "ansible"
      device_unique_name: "FGT2"
      #interface to configure
      interface: "port2"
      #ip address to add to interface
      interface_ip: "10.1.2.1/24"
      #edit management access
      interface_allow_access: "ping, telnet, https, http"

fmgr_device_group

Playbook Task Examples
- name: CREATE DEVICE GROUP
  fmgr_device_group:
    grp_name: "TestGroup"
    grp_desc: "CreatedbyAnsible"
    adom: "ansible"
    mode: "add"

- name: CREATE DEVICE GROUP 2
  fmgr_device_group:
    grp_name: "AnsibleGroup"
    grp_desc: "CreatedbyAnsible"
    adom: "ansible"
    mode: "add"

- name: ADD DEVICES TO DEVICE GROUP
  fmgr_device_group:
    mode: "add"
    grp_name: "TestGroup"
    grp_members: "FGT1,FGT2"
    adom: "ansible"
    vdom: "root"

- name: REMOVE DEVICES TO DEVICE GROUP
  fmgr_device_group:
    mode: "delete"
    grp_name: "TestGroup"
    grp_members: "FGT1,FGT2"
    adom: "ansible"

- name: DELETE DEVICE GROUP
  fmgr_device_group:
    grp_name: "AnsibleGroup"
    grp_desc: "CreatedbyAnsible"
    mode: "delete"
    adom: "ansible"
Playbook File Examples
fmgr_group_delete.yml
- name: REMOVE FGT GRP
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: DELETE DEVICE GROUP
      fmgr_device_group:
        #GETTING FORTIMANAGER HOST IP OR NAME FROM ANSIBLE INVENTORY FOR HOSTS GROUP ABOVE
        #DYNAMIC MAPPING FOR THE FORTIMANAGER LOGIN AS SPECIFIED IN INVENTORY FILE
        #NAME OF GROUP YOU WANT TO ADD
        grp_name: "TestGroup"
        #DESCRIPTION TO ADD TO GROUP
        grp_desc: "CreatedbyAnsible"
        #STATE if "present" add the group, if "absent" delete the GROUP
        mode: "delete"
        #ADOM TO CREATE THE GROUP IN
        adom: "ansible"

    - name: DELETE DEVICE GROUP 2
      fmgr_device_group:
        grp_name: "testtest"
        grp_desc: "CreatedbyAnsible"
        mode: "delete"
        adom: "ansible"
fmgr_group_edit_remove.yml
- name: REMOVE DEVICES FROM FGT GRP
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: REMOVE DEVICES FROM DEVICE GROUP
      fmgr_device_group:
        #GETTING FORTIMANAGER HOST IP OR NAME FROM ANSIBLE INVENTORY FOR HOSTS GROUP ABOVE
        #DYNAMIC MAPPING FOR THE FORTIMANAGER LOGIN AS SPECIFIED IN INVENTORY FILE
        #STATE if "present" ADD THE GROUP MEMBERS, IF "absent" DELETE THE GROUP MEMBERS
        mode: "delete"
        #GROUP NAME TO REMOVE THE DEVICES FROM
        grp_name: "testtest"
        #FRIENDLY NAME OF DEVICES IN FORTIMANAGER YOU WISH TO DELETE FROM THE GROUP
        #MULTIPLE DEVICES CAN BE SPECIFIED BY COMMA SEPARATION (CSV)
        grp_members: "FGT3"
        #ADOM YOU WISH TO ADD
        adom: "ansible"

    - name: REMOVE DEVICES FROM DEVICE GROUP2
      fmgr_device_group:
        mode: "delete"
        grp_name: "TestGroup"
        grp_members: "FGT1"
        adom: "ansible"
fmgr_device_groups.yml
- name: CREATE DEVICE GROUP AND ADD MEMBERS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: CREATE DEVICE GROUP
      fmgr_device_group:
        grp_name: "TestGroup"
        grp_desc: "CreatedbyAnsible"
        adom: "ansible"

    - name: CREATE DEVICE GROUP
      fmgr_device_group:
        grp_name: "AnsibleGroup"
        grp_desc: "CreatedbyAnsible"
        adom: "ansible"

    - name: ADD DEVICES TO DEVICE GROUP
      fmgr_device_group:
        mode: "add"
        grp_name: "TestGroup"
        grp_members: "FGT1"
        adom: "ansible"

    - name: DELETE DEVICE GROUP
      fmgr_device_group:
        grp_name: "AnsibleGroup"
        grp_desc: "CreatedbyAnsible"
        mode: "delete"
        adom: "ansible"
fmgr_group_edit_add.yml
- name: CREATE FGT GRP
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: ADD DEVICES TO DEVICE GROUP
    fmgr_device_group:
      #GETTING FORTIMANAGER HOST IP OR NAME FROM ANSIBLE INVENTORY FOR HOSTS GROUP ABOVE
      #DYNAMIC MAPPING FOR THE FORTIMANAGER LOGIN AS SPECIFIED IN INVENTORY FILE
      #STATE if "present" ADD THE GROUP MEMBERS, IF "absent" DELETE THE GROUP MEMBERS
      mode: "add"
      #GROUP NAME TO ADD THE DEVICES TO
      grp_name: "TestGroup"
      #FRIENDLY NAME OF DEVICES IN FORTIMANAGER YOU WISH TO ADD TO THE GROUP
      #MULTIPLE DEVICES CAN BE SPECIFIED BY COMMA SEPARATION (CSV)
      grp_members: "FGT1"
      #ADOM TO CREATE THE GROUP IN
      adom: "ansible"
      vdom: "root"

  - name: ADD DEVICES TO DEVICE GROUP 2
    fmgr_device_group:
      mode: "add"
      grp_name: "testtest"
      grp_members: "FGT3"
      adom: "ansible"
      vdom: "root"
fmgr_group_add.yml
- name: CREATE FGT GRP
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: CREATE DEVICE GROUP
    fmgr_device_group:
      #GETTING FORTIMANAGER HOST IP OR NAME FROM ANSIBLE INVENTORY FOR HOSTS GROUP ABOVE
      #DYNAMIC MAPPING FOR THE FORTIMANAGER LOGIN AS SPECIFIED IN INVENTORY FILE
      #NAME OF GROUP YOU WANT TO ADD
      grp_name: "TestGroup"
      #DESCRIPTION TO ADD TO GROUP
      grp_desc: "CreatedbyAnsible"
      #ADOM TO CREATE THE GROUP IN
      adom: "ansible"
      #STATE if "present" add the group, if "absent" delete the GROUP
      mode: "add"

  - name: CREATE DEVICE GROUP2
    fmgr_device_group:
      grp_name: "testtest"
      grp_desc: "CreatedbyAnsible"
      adom: "ansible"
      mode: "add"
fmgr_device_group_run_all.sh
        #!/bin/bash
ansible-playbook fmgr_group_delete.yml -vvvv
ansible-playbook fmgr_group_edit_remove.yml -vvvv
ansible-playbook fmgr_device_groups.yml -vvvv
ansible-playbook fmgr_group_edit_add.yml -vvvv
ansible-playbook fmgr_group_add.yml -vvvv

fmgr_device_provision_template

Playbook Task Examples
- name: SET SNMP SYSTEM INFO
  fmgr_device_provision_template:
    provisioning_template: "default"
    snmp_status: "enable"
    mode: "set"

- name: SET SNMP SYSTEM INFO ANSIBLE ADOM
  fmgr_device_provision_template:
    provisioning_template: "default"
    snmp_status: "enable"
    mode: "set"
    adom: "ansible"

- name: SET SNMP SYSTEM INFO different template (SNMPv2)
  fmgr_device_provision_template:
    provisioning_template: "ansibleTest"
    snmp_status: "enable"
    mode: "set"
    adom: "ansible"
    snmp_v2c_query_port: "162"
    snmp_v2c_trap_port: "161"
    snmp_v2c_status: "enable"
    snmp_v2c_trap_status: "enable"
    snmp_v2c_query_status: "enable"
    snmp_v2c_name: "ansibleV2c"
    snmp_v2c_id: "1"
    snmp_v2c_trap_src_ipv4: "10.7.220.41"
    snmp_v2c_trap_hosts_ipv4: "10.7.220.59 255.255.255.255, 10.7.220.60 255.255.255.255"
    snmp_v2c_query_hosts_ipv4: "10.7.220.59 255.255.255.255, 10.7.220.0 255.255.255.0"

- name: SET SNMP SYSTEM INFO different template (SNMPv3)
  fmgr_device_provision_template:
    provisioning_template: "ansibleTest"
    snmp_status: "enable"
    mode: "set"
    adom: "ansible"
    snmpv3_auth_proto: "sha"
    snmpv3_auth_pwd: "fortinet"
    snmpv3_name: "ansibleSNMPv3"
    snmpv3_notify_hosts: "10.7.220.59,10.7.220.60"
    snmpv3_priv_proto: "aes256"
    snmpv3_priv_pwd: "fortinet"
    snmpv3_queries: "enable"
    snmpv3_query_port: "161"
    snmpv3_security_level: "auth_priv"
    snmpv3_source_ip: "0.0.0.0"
    snmpv3_status: "enable"
    snmpv3_trap_rport: "162"
    snmpv3_trap_status: "enable"

- name: SET SYSLOG INFO
  fmgr_device_provision_template:
    provisioning_template: "ansibleTest"
    mode: "set"
    adom: "ansible"
    syslog_server: "10.7.220.59"
    syslog_port: "514"
    syslog_mode: "disable"
    syslog_status: "enable"
    syslog_filter: "information"

- name: SET NTP TO FORTIGUARD
  fmgr_device_provision_template:
    provisioning_template: "ansibleTest"
    mode: "set"
    adom: "ansible"
    ntp_status: "enable"
    ntp_sync_interval: "60"
    type: "fortiguard"

- name: SET NTP TO CUSTOM SERVER
  fmgr_device_provision_template:
    provisioning_template: "ansibleTest"
    mode: "set"
    adom: "ansible"
    ntp_status: "enable"
    ntp_sync_interval: "60"
    ntp_type: "custom"
    ntp_server: "10.7.220.32,10.7.220.1"
    ntp_auth: "enable"
    ntp_auth_pwd: "fortinet"
    ntp_v3: "disable"

- name: SET ADMIN GLOBAL SETTINGS
  fmgr_device_provision_template:
    provisioning_template: "ansibleTest"
    mode: "set"
    adom: "ansible"
    admin_https_redirect: "enable"
    admin_https_port: "4433"
    admin_http_port: "8080"
    admin_timeout: "30"
    admin_language: "english"
    admin_switch_controller: "enable"
    admin_gui_theme: "blue"
    admin_enable_fortiguard: "direct"
    admin_fortiguard_target: "10.7.220.128"
    admin_fortianalyzer_target: "10.7.220.61"

- name: SET CUSTOM SMTP SERVER
  fmgr_device_provision_template:
    provisioning_template: "ansibleTest"
    mode: "set"
    adom: "ansible"
    smtp_username: "ansible"
    smtp_password: "fortinet"
    smtp_port: "25"
    smtp_replyto: "ansible@do-not-reply.com"
    smtp_conn_sec: "starttls"
    smtp_server: "10.7.220.32"
    smtp_source_ipv4: "0.0.0.0"
    smtp_validate_cert: "disable"

- name: SET DNS SERVERS
  fmgr_device_provision_template:
    provisioning_template: "ansibleTest"
    mode: "set"
    adom: "ansible"
    dns_suffix: "ansible.local"
    dns_primary_ipv4: "8.8.8.8"
    dns_secondary_ipv4: "4.4.4.4"

- name: SET PROVISIONING TEMPLATE DEVICE TARGETS IN FORTIMANAGER
  fmgr_device_provision_template:
    provisioning_template: "ansibleTest"
    mode: "set"
    adom: "ansible"
    provision_targets: "FGT1, FGT2"

- name: DELETE ENTIRE PROVISIONING TEMPLATE
  fmgr_device_provision_template:
    delete_provisioning_template: "ansibleTest"
    mode: "delete"
    adom: "ansible"
Playbook File Examples
fmgr_device_provision_template_remove_scope.yml
- name: DELETE DEVICE PROVISION TEMPLATES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: SET PROVISIONING TEMPLATE DEVICE TARGETS IN FORTIMANAGER
      fmgr_device_provision_template:
        provisioning_template: "ansibleTest"
        mode: "delete"
        adom: "ansible"
        provision_targets: "FGT1,FGT2"
fmgr_device_proftemplate_faz_assign.yml
- name: CREATE DEVICE PROVISION TEMPLATES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
#    - name: SET ADMIN GLOBAL SETTINGS
#      fmgr_device_provision_template:
#        provisioning_template: "testTemplate"
#        mode: "set"
#        adom: "ansible"
#        admin_https_redirect: "enable"
#        admin_timeout: "60"
#        admin_gui_theme: "blue"
#        admin_fortianalyzer_target: "10.7.220.38"
#
#    - name: SET PROVISIONING TEMPLATE DEVICE TARGETS IN FORTIMANAGER
#      fmgr_device_provision_template:
#        provisioning_template: "testTemplate"
#        mode: "set"
#        adom: "ansible"
#        provision_targets: "seattle-fgt-cluster"


    - name: INSTALL CONFIG
      fmgr_device_config:
        adom: "ansible"
        device_unique_name: "seattle-fgt-cluster"
        install_config: "enable"
fmgr_device_provision_template_delete.yml
- name: CREATE DEVICE PROVISION TEMPLATES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: DELETE ENTIRE PROVISIONING TEMPLATE
      fmgr_device_provision_template:
        delete_provisioning_template: "ansibleTest"
        mode: "delete"
        adom: "ansible"
fmgr_device_provision_template.yml
- name: CREATE DEVICE PROVISION TEMPLATES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: SET SNMP SYSTEM INFO ANSIBLE ADOM
      fmgr_device_provision_template:
        provisioning_template: "ansibleTest"
        snmp_status: "enable"
        mode: "set"
        adom: "ansible"

    - name: SET SYSLOG INFO
      fmgr_device_provision_template:
        provisioning_template: "ansibleTest"
        mode: "set"
        adom: "ansible"
        syslog_server: "10.7.220.59"
        syslog_port: "514"
        syslog_mode: "udp"
        syslog_status: "enable"
        syslog_filter: "critical"
        syslog_facility: "kernel"

    - name: SET SNMP SYSTEM INFO different template
      fmgr_device_provision_template:
        provisioning_template: "ansibleTest"
        snmp_status: "enable"
        mode: "set"
        adom: "ansible"
        snmp_v2c_query_port: "162"
        snmp_v2c_trap_port: "161"
        snmp_v2c_status: "enable"
        snmp_v2c_trap_status: "enable"
        snmp_v2c_query_status: "enable"
        snmp_v2c_name: "ansibleV2c"
        snmp_v2c_id: "1"
        snmp_v2c_trap_src_ipv4: "10.7.220.41"
        snmp_v2c_trap_hosts_ipv4: "10.7.220.59 255.255.255.255, 10.7.220.60 255.255.255.255"
        snmp_v2c_query_hosts_ipv4: "10.7.220.59 255.255.255.255, 10.7.220.0 255.255.255.0"


    - name: SET SNMP SYSTEM INFO different template (SNMPv3)
      fmgr_device_provision_template:
        provisioning_template: "ansibleTest"
        snmp_status: "enable"
        mode: "set"
        adom: "ansible"
        snmpv3_auth_proto: "sha"
        snmpv3_auth_pwd: "fortinet"
        snmpv3_name: "ansibleSNMPv3"
        snmpv3_notify_hosts: "10.7.220.59,10.7.220.60"
        snmpv3_priv_proto: "aes256"
        snmpv3_priv_pwd: "fortinet"
        snmpv3_queries: "enable"
        snmpv3_query_port: "161"
        snmpv3_security_level: "auth-priv"
        snmpv3_source_ip: "0.0.0.0"
        snmpv3_status: "enable"
        snmpv3_trap_rport: "162"
        snmpv3_trap_status: "enable"

    - name: SET NTP TO FORTIGUARD
      fmgr_device_provision_template:
        provisioning_template: "ansibleTest"
        mode: "set"
        adom: "ansible"
        ntp_status: "enable"
        ntp_sync_interval: "60"
        ntp_type: "fortiguard"

    - name: SET NTP TO CUSTOM SERVER
      fmgr_device_provision_template:
        provisioning_template: "ansibleTest"
        mode: "set"
        adom: "ansible"
        ntp_status: "enable"
        ntp_sync_interval: "60"
        ntp_type: "custom"
        ntp_server: "10.7.220.32,10.7.220.1"
        ntp_auth: "enable"
        ntp_auth_pwd: "fortinet"

    - name: SET ADMIN GLOBAL SETTINGS
      fmgr_device_provision_template:
        provisioning_template: "ansibleTest"
        mode: "set"
        adom: "ansible"
        admin_https_redirect: "enable"
        admin_https_port: "4433"
        admin_http_port: "8080"
        admin_timeout: "60"
        admin_language: "english"
        admin_switch_controller: "enable"
        admin_gui_theme: "blue"
        admin_enable_fortiguard: "this-fmg"
        #admin_fortiguard_target: "10.7.220.128"
        admin_fortianalyzer_target: "10.7.220.38"

    - name: SET CUSTOM SMTP SERVER
      fmgr_device_provision_template:
        provisioning_template: "ansibleTest"
        mode: "set"
        adom: "ansible"
        smtp_username: "ansible"
        smtp_password: "{{ password }}"
        smtp_port: "25"
        smtp_replyto: "ansible@do-not-reply.com"
        smtp_conn_sec: "starttls"
        smtp_server: "10.7.220.32"
        smtp_source_ipv4: "0.0.0.0"
        smtp_validate_cert: "disable"

    - name: SET DNS SERVERS
      fmgr_device_provision_template:
        provisioning_template: "ansibleTest"
        mode: "set"
        adom: "ansible"
        dns_suffix: "ansible.local"
        dns_primary_ipv4: "8.8.8.8"
        dns_secondary_ipv4: "4.4.4.4"

    - name: SET PROVISIONING TEMPLATE DEVICE TARGETS IN FORTIMANAGER
      fmgr_device_provision_template:
        provisioning_template: "ansibleTest"
        mode: "set"
        adom: "ansible"
        provision_targets: "FGT1,FGT2"
fmgr_device_provision_template_run_all.sh
        #!/bin/bash
ansible-playbook fmgr_device_provision_template_remove_scope.yml -vvvv
ansible-playbook fmgr_device_proftemplate_faz_assign.yml -vvvv
ansible-playbook fmgr_device_provision_template_delete.yml -vvvv
ansible-playbook fmgr_device_provision_template.yml -vvvv
ansible-playbook fmgr_device_provision_template_run_all.sh -vvvv
ansible-playbook fmgr_device_provision_template_absent.yml -vvvv
fmgr_device_provision_template_absent.yml
- name: DELETE DEVICE PROVISION TEMPLATES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: DELETE SNMP SYSTEM INFO
      fmgr_device_provision_template:
        provisioning_template: "ansibleTest"
        snmp_status: "enable"
        mode: "delete"
        adom: "ansible"

    - name: DELETE SNMP SYSTEM INFO ANSIBLE ADOM
      fmgr_device_provision_template:
        provisioning_template: "ansibleTest"
        snmp_status: "enable"
        mode: "delete"
        adom: "ansible"

    - name: DELETE SYSLOG INFO
      fmgr_device_provision_template:
        provisioning_template: "ansibleTest"
        mode: "delete"
        adom: "ansible"
        syslog_server: "10.7.220.59"
        syslog_port: "514"
        syslog_mode: "udp"
        syslog_status: "enable"
        syslog_filter: "critical"

    - name: DELETE SNMP SYSTEM INFO different template
      fmgr_device_provision_template:
        provisioning_template: "ansibleTest"
        snmp_status: "enable"
        mode: "delete"
        adom: "ansible"
        snmp_v2c_query_port: "162"
        snmp_v2c_trap_port: "161"
        snmp_v2c_status: "enable"
        snmp_v2c_trap_status: "enable"
        snmp_v2c_query_status: "enable"
        snmp_v2c_name: "ansibleV2c"
        snmp_v2c_id: "1"
        snmp_v2c_trap_src_ipv4: "10.7.220.41"
        snmp_v2c_trap_hosts_ipv4: "10.7.220.59 255.255.255.255, 10.7.220.60 255.255.255.255"
        snmp_v2c_query_hosts_ipv4: "10.7.220.59 255.255.255.255, 10.7.220.0 255.255.255.0"

    - name: DELETE SNMP SYSTEM INFO different template (SNMPv3)
      fmgr_device_provision_template:
        provisioning_template: "ansibleTest"
        snmp_status: "enable"
        mode: "delete"
        adom: "ansible"
        snmpv3_auth_proto: "sha"
        snmpv3_auth_pwd: "fortinet"
        snmpv3_name: "ansibleSNMPv3"
        snmpv3_notify_hosts: "10.7.220.59,10.7.220.60"
        snmpv3_priv_proto: "aes256"
        snmpv3_priv_pwd: "fortinet"
        snmpv3_queries: "enable"
        snmpv3_query_port: "161"
        snmpv3_security_level: "auth-priv"
        snmpv3_source_ip: "0.0.0.0"
        snmpv3_status: "enable"
        snmpv3_trap_rport: "162"
        snmpv3_trap_status: "enable"

    - name: DELETE NTP TO FORTIGUARD
      fmgr_device_provision_template:
        provisioning_template: "ansibleTest"
        mode: "delete"
        adom: "ansible"
        ntp_status: "enable"
        ntp_sync_interval: "60"
        ntp_type: "fortiguard"

    - name: DELETE NTP TO CUSTOM SERVER
      fmgr_device_provision_template:
        provisioning_template: "ansibleTest"
        mode: "delete"
        adom: "ansible"
        ntp_status: "enable"
        ntp_sync_interval: "60"
        ntp_type: "custom"
        ntp_server: "10.7.220.32,10.7.220.1"
        ntp_auth: "enable"
        ntp_auth_pwd: "fortinet"
        ntp_v3: "disable"

    - name: DELETE ADMIN GLOBAL DELETETINGS
      fmgr_device_provision_template:
        provisioning_template: "ansibleTest"
        mode: "delete"
        adom: "ansible"
        admin_https_redirect: "enable"
        admin_https_port: "4433"
        admin_http_port: "8080"
        admin_timeout: "30"
        admin_language: "english"
        admin_switch_controller: "enable"
        admin_gui_theme: "blue"
        admin_enable_fortiguard: "none"
        admin_fortianalyzer_target: "10.7.220.65"

    - name: DELETE CUSTOM SMTP SERVER
      fmgr_device_provision_template:
        provisioning_template: "ansibleTest"
        mode: "delete"
        adom: "ansible"
        smtp_username: "ansible"
        smtp_password: "{{ password }}"
        smtp_port: "25"
        smtp_replyto: "ansible@do-not-reply.com"
        smtp_conn_sec: "starttls"
        smtp_server: "10.7.220.32"
        smtp_source_ipv4: "0.0.0.0"
        smtp_validate_cert: "disable"

    - name: SET DNS SERVERS
      fmgr_device_provision_template:
        provisioning_template: "ansibleTest"
        mode: "delete"
        adom: "ansible"
        dns_suffix: "ansible.local"
        dns_primary_ipv4: "8.8.8.8"
        dns_secondary_ipv4: "4.4.4.4"

    - name: SET PROVISIONING TEMPLATE DEVICE TARGETS IN FORTIMANAGER
      fmgr_device_provision_template:
        provisioning_template: "ansibleTest"
        mode: "delete"
        adom: "ansible"
        provision_targets: "FGT1,FGT2"

fmgr_fortimeter

Playbook Task Examples
- name: SET LICENSING MODE ON FORTIMETER DEVICE to ALL
  fmgr_fortimeter:
    object: "device"
    adom: "ansible"
    device_unique_name: "FOSVM1FGPRJ411DD"
    fortimeter_utm_level: "all"

- name: SET LICENSING MODE ON FORTIMETER DEVICE to a COMBO
  fmgr_fortimeter:
    object: "device"
    adom: "ansible"
    device_unique_name: "FOSVM1FGPRJ411DD"
    fortimeter_utm_level: "fw, ips, av"
Playbook File Examples

%%PB_FILE_EXAMPLE_TOKEN%%

fmgr_fwobj_address

Playbook Task Examples
- name: ADD IPv4 IP ADDRESS OBJECT
  fmgr_fwobj_address:
    ipv4: "ipmask"
    ipv4addr: "10.7.220.30/32"
    name: "ansible_v4Obj"
    comment: "Created by Ansible"
    color: "6"

- name: ADD IPv4 IP ADDRESS OBJECT MORE OPTIONS
  fmgr_fwobj_address:
    ipv4: "ipmask"
    ipv4addr: "10.7.220.34/32"
    name: "ansible_v4Obj_MORE"
    comment: "Created by Ansible"
    color: "6"
    allow_routing: "enable"
    cache_ttl: "180"
    associated_interface: "port1"
    obj_id: "123"

- name: ADD IPv4 IP ADDRESS SUBNET OBJECT
  fmgr_fwobj_address:
    ipv4: "ipmask"
    ipv4addr: "10.7.220.0/255.255.255.128"
    name: "ansible_subnet"
    comment: "Created by Ansible"
    mode: "set"

- name: ADD IPv4 IP ADDRESS RANGE OBJECT
  fmgr_fwobj_address:
    ipv4: "iprange"
    start_ip: "10.7.220.1"
    end_ip: "10.7.220.125"
    name: "ansible_range"
    comment: "Created by Ansible"

- name: ADD IPv4 IP ADDRESS WILDCARD OBJECT
  fmgr_fwobj_address:
    ipv4: "wildcard"
    wildcard: "10.7.220.30/255.255.255.255"
    name: "ansible_wildcard"
    comment: "Created by Ansible"

- name: ADD IPv4 IP ADDRESS WILDCARD FQDN OBJECT
  fmgr_fwobj_address:
    ipv4: "wildcard-fqdn"
    wildcard_fqdn: "*.myds.com"
    name: "Synology myds DDNS service"
    comment: "Created by Ansible"

- name: ADD IPv4 IP ADDRESS FQDN OBJECT
  fmgr_fwobj_address:
    ipv4: "fqdn"
    fqdn: "ansible.com"
    name: "ansible_fqdn"
    comment: "Created by Ansible"

- name: ADD IPv4 IP ADDRESS GEO OBJECT
  fmgr_fwobj_address:
    ipv4: "geography"
    country: "usa"
    name: "ansible_geo"
    comment: "Created by Ansible"

- name: ADD IPv6 ADDRESS
  fmgr_fwobj_address:
    ipv6: "ip"
    ipv6addr: "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
    name: "ansible_v6Obj"
    comment: "Created by Ansible"

- name: ADD IPv6 ADDRESS RANGE
  fmgr_fwobj_address:
    ipv6: "iprange"
    start_ip: "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
    end_ip: "2001:0db8:85a3:0000:0000:8a2e:0370:7446"
    name: "ansible_v6range"
    comment: "Created by Ansible"

- name: ADD IPv4 IP ADDRESS GROUP
  fmgr_fwobj_address:
    ipv4: "group"
    group_name: "ansibleIPv4Group"
    group_members: "ansible_fqdn, ansible_wildcard, ansible_range"

- name: ADD IPv6 IP ADDRESS GROUP
  fmgr_fwobj_address:
    ipv6: "group"
    group_name: "ansibleIPv6Group"
    group_members: "ansible_v6Obj, ansible_v6range"

- name: ADD MULTICAST RANGE
  fmgr_fwobj_address:
    multicast: "multicastrange"
    start_ip: "224.0.0.251"
    end_ip: "224.0.0.251"
    name: "ansible_multicastrange"
    comment: "Created by Ansible"

- name: ADD BROADCAST SUBNET
  fmgr_fwobj_address:
    multicast: "broadcastmask"
    ipv4addr: "10.7.220.0/24"
    name: "ansible_broadcastSubnet"
    comment: "Created by Ansible"
Playbook File Examples
fmgr_fwobj_ipv6_add_iprange.yml
- name: CONFIG FMGR FIREWALL OBJECTS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: ADD IPv6 IP ADDRESS RANGE OBJECT
    fmgr_fwobj_address:
      mode: "add"
      adom: "ansible"
      ipv6: "iprange"
      start_ip: "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
      end_ip: "2001:0db8:85a3:0000:0000:8a2e:0370:7446"
      name: "ansible_v6Obj_Range"
      comment: "Dev Example for Ansible"
      color: "22"
      #tags: "ansible, ipv4, test123, test321"
fmgr_fwobj_ipv4_add_fqdn.yml
- name: CONFIG FMGR FIREWALL OBJECTS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: ADD IPv4 IP ADDRESS FQDN OBJECT
    fmgr_fwobj_address:
      ipv4: "fqdn"
      mode: "add"
      adom: "ansible"
      fqdn: "bluesnews.com"
      name: "Bluesnews"
      comment: "Dev Example for Ansible"
      color: "22"
      #tags: "ansible, ipv4, test123, test321"
fmgr_fwobj_ipv4_del_all.yml
- name: CONFIG FMGR FIREWALL OBJECTS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: DELETE IPv4 IP ADDRESS GROUP
    fmgr_fwobj_address:
      adom: "ansible"
      mode: "delete"
      ipv4: "group"
      group_name: "ansibleIPv4Group"

  - name: DELETE IPv4 IP ADDRESS RANGE OBJECT
    fmgr_fwobj_address:
      mode: "delete"
      adom: "ansible"
      ipv4: "iprange"
      name: "ansible_v4Obj_Range"

  - name: DELETE IPv4 IP ADDRESS RANGE OBJECT 3
    fmgr_fwobj_address:
      mode: "delete"
      adom: "ansible"
      ipv4: "iprange"
      name: "ansible_v4Obj_MORE"

  - name: DELETE IPv4 IP ADDRESS RANGE OBJECT 4
    fmgr_fwobj_address:
      mode: "delete"
      adom: "ansible"
      ipv4: "iprange"
      name: "ansible_v4Obj_ipMask2"

  - name: DELETE IPv4 IP ADDRESS RANGE OBJECT 2
    fmgr_fwobj_address:
      mode: "delete"
      adom: "ansible"
      ipv4: "iprange"
      name: "ansible_v4Obj_Range2"

  - name: DELETE IPv4 IP ADDRESS OBJECT
    fmgr_fwobj_address:
      mode: "delete"
      adom: "ansible"
      ipv4: "ipmask"
      name: "ansible_v4Obj_ipMask"

  - name: DELETE IPv4 IP ADDRESS OBJECT (NON CIDR TEST)
    fmgr_fwobj_address:
      mode: "delete"
      adom: "ansible"
      ipv4: "ipmask"
      name: "ansible_v4Obj_Subnet2"

  - name: DELETE IPv4 IP ADDRESS OBJECT (NON CIDR TEST) 2
    fmgr_fwobj_address:
      mode: "delete"
      adom: "ansible"
      ipv4: "ipmask"
      name: "ansible_v4Obj_Subnet1"

  - name: DELETE IPv4 IP ADDRESS WILDCARD OBJECT
    fmgr_fwobj_address:
      mode: "delete"
      adom: "ansible"
      ipv4: "wildcard"
      name: "ansible_v4Obj_wildCard"

  - name: DELETE IPv4 IP ADDRESS WILDCARD FQDN OBJECT
    fmgr_fwobj_address:
      ipv4: "wildcard-fqdn"
      mode: "delete"
      adom: "ansible"
      name: "Synology myds DDNS service"

  - name: DELETE IPv4 IP ADDRESS FQDN OBJECT
    fmgr_fwobj_address:
      ipv4: "fqdn"
      mode: "delete"
      adom: "ansible"
      name: "Bluesnews"

  - name: DELETE IPv4 IP ADDRESS GEO OBJECT
    fmgr_fwobj_address:
      ipv4: "geography"
      mode: "delete"
      adom: "ansible"
      name: "ansible_geo"

  - name: DELETE IPv6 IP ADDRESS GROUP
    fmgr_fwobj_address:
      adom: "ansible"
      mode: "delete"
      ipv6: "group"
      group_name: "ansibleIPv6Group"

  - name: DELETE IPv6 IP ADDRESS RANGE OBJECT
    fmgr_fwobj_address:
      mode: "delete"
      adom: "ansible"
      ipv6: "iprange"
      name: "ansible_v6Obj_Range"

  - name: DELETE IPv6 ADDRESS
    fmgr_fwobj_address:
      adom: "ansible"
      mode: "delete"
      ipv6: "ip"
      name: "ansible_v6Obj"

  - name: DELETE BROADCAST SUBNET
    fmgr_fwobj_address:
      adom: "ansible"
      multicast: "broadcastmask"
      mode: "delete"
      name: "ansible_broadcastSubnet"

  - name: DELETE MULTICAST RANGE
    fmgr_fwobj_address:
      adom: "ansible"
      mode: "delete"
      multicast: "multicastrange"
      name: "ansible_multicastrange"
fmgr_fwobj_ipv4_broadcast_subnet.yml
- name: CONFIG IPv4 IP ADDRESS OBJECT
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: ADD BROADCAST SUBNET
    fmgr_fwobj_address:
      adom: "ansible"
      mode: "add"
      multicast: "broadcastmask"
      ipv4addr: "10.7.220.0/24"
      name: "ansible_broadcastSubnet"
      comment: "Dev Example for Ansible"
      color: "22"
      #tags: "ansible, ipv4, test123, test321"
fmgr_fwobj_ipv6_add_ip.yml
- name: CONFIG FMGR FIREWALL OBJECTS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: ADD IPv6 ADDRESS
    fmgr_fwobj_address:
      adom: "ansible"
      mode: "add"
      ipv6: "ip"
      ipv6addr: "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
      name: "ansible_v6Obj"
      comment: "Dev Example for Ansible"
      color: "22"
      #tags: "ansible, ipv4, test123, test321"
fmgr_fwobj_ipv6_add_z_group.yml
- name: CONFIG FMGR FIREWALL OBJECTS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: ADD IPv6 IP ADDRESS GROUP
    fmgr_fwobj_address:
      adom: "ansible"
      mode: "add"
      ipv6: "group"
      group_name: "ansibleIPv6Group"
      group_members: "ansible_v6Obj_Range, ansible_v6Obj"
      color: "22"
      #tags: "ansible, ipv4, test123, test321"
      comment: "test123 comment"
fmgr_fwobj_address_run_all.sh
        #!/bin/bash
ansible-playbook fmgr_fwobj_ipv6_add_iprange.yml -vvvv
ansible-playbook fmgr_fwobj_ipv4_add_fqdn.yml -vvvv
ansible-playbook fmgr_fwobj_ipv4_del_all.yml -vvvv
ansible-playbook fmgr_fwobj_ipv4_broadcast_subnet.yml -vvvv
ansible-playbook fmgr_fwobj_ipv6_add_ip.yml -vvvv
ansible-playbook fmgr_fwobj_ipv6_add_z_group.yml -vvvv
ansible-playbook fmgr_fwobj_ipv4_add_geo.yml -vvvv
ansible-playbook fmgr_fwobj_ipv4_add_ipmask.yml -vvvv
ansible-playbook fmgr_fwobj_ipv4_add_z_group.yml -vvvv
ansible-playbook fmgr_fwobj_ipv4_add_ipsubnet.yml -vvvv
ansible-playbook fmgr_fwobj_ipv4_multicast_range.yml -vvvv
ansible-playbook fmgr_fwobj_ipv4_add_iprange.yml -vvvv
ansible-playbook fmgr_fwobj_ipv4_add_wildcard_fqdn.yml -vvvv
ansible-playbook fmgr_fwobj_ipv4_add_wildcard.yml -vvvv
fmgr_fwobj_ipv4_add_geo.yml
- name: CONFIG FMGR FIREWALL OBJECTS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: ADD IPv4 IP ADDRESS GEO OBJECT
    fmgr_fwobj_address:
      ipv4: "geography"
      country: "US"
      mode: "add"
      adom: "ansible"
      name: "ansible_geo"
      comment: "Dev Example for Ansible"
      color: "22"
      #tags: "ipv4, test123, test321"
fmgr_fwobj_ipv4_add_ipmask.yml
- name: CONFIG IPv4 IP ADDRESS OBJECT
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: ADD IPv4 IP ADDRESS OBJECT
    fmgr_fwobj_address:
      mode: "delete"
      adom: "ansible"
      ipv4: "ipmask"
      ipv4addr: "10.7.220.30/32"
      name: "ansible_v4Obj_ipMask2"
      comment: "Ansible is fun! Paramgram!"
      #tags: "ansible, ipv4, object"
      color: "26"

  - name: ADD IPv4 IP ADDRESS OBJECT MORE OPTIONS
    fmgr_fwobj_address:
      ipv4: "ipmask"
      ipv4addr: "10.7.220.41/32"
      name: "ansible_v4Obj_MORE"
      comment: "Ansible more options"
      #tags: "ansible, ipv4, object"
      color: "6"
      allow_routing: "enable"
      cache_ttl: "180"
      associated_interface: "port1"
      adom: "ansible"
      mode: "set"
fmgr_fwobj_ipv4_add_z_group.yml
- name: CONFIG FMGR FIREWALL OBJECTS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: ADD IPv4 IP ADDRESS GROUP
    fmgr_fwobj_address:
      adom: "ansible"
      mode: "add"
      ipv4: "group"
      group_name: "ansibleIPv4Group"
      group_members: "Bluesnews, ansible_v4Obj_Range"
      color: "22"
fmgr_fwobj_ipv4_add_ipsubnet.yml
- name: CONFIG FMGR FIREWALL OBJECTS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: ADD IPv4 IP ADDRESS OBJECT
    fmgr_fwobj_address:
      mode: "add"
      adom: "ansible"
      ipv4: "ipmask"
      ipv4addr: "10.7.220.0/25"
      name: "ansible_v4Obj_Subnet1"
      comment: "Dev Example for Ansible"
      color: "22"
      #tags: "ansible, ipv4, test123, test321"

  - name: ADD IPv4 IP ADDRESS OBJECT (NON CIDR TEST)
    fmgr_fwobj_address:
      mode: "add"
      adom: "ansible"
      ipv4: "ipmask"
      ipv4addr: "10.7.220.128/255.255.255.128"
      name: "ansible_v4Obj_Subnet2"
      comment: "Dev Example for Ansible"
      color: "22"
      #tags: "ansible, ipv4, test123, test321"
fmgr_fwobj_ipv4_multicast_range.yml
- name: CONFIG IPv4 IP ADDRESS OBJECT
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: ADD MULTICAST RANGE
    fmgr_fwobj_address:
      adom: "ansible"
      mode: "add"
      multicast: "multicastrange"
      start_ip: "224.0.0.251"
      end_ip: "224.0.0.251"
      name: "ansible_multicastrange"
      comment: "Dev by Ansible"
      color: "22"
      #tags: "blahBlahBlah"
fmgr_fwobj_ipv4_add_iprange.yml
- name: CONFIG FMGR FIREWALL OBJECTS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: ADD IPv4 IP ADDRESS RANGE OBJECT
    fmgr_fwobj_address:
      mode: "set"
      adom: "ansible"
      ipv4: "iprange"
      start_ip: "10.7.220.1"
      end_ip: "10.7.220.50"
      name: "ansible_v4Obj_Range"
      comment: "Dev Example for Ansible"
      color: "22"
      #tags: "ansible, ipv4, test123, test321"

  - name: ADD IPv4 IP ADDRESS RANGE OBJECT 2
    fmgr_fwobj_address:
      mode: "set"
      adom: "ansible"
      ipv4: "iprange"
      start_ip: "10.7.220.100"
      end_ip: "10.7.220.150"
      name: "ansible_v4Obj_Range2"
      comment: "Dev Example for Ansible"
      color: "22"
      #tags: "ansible, ipv4, test123, test321"
fmgr_fwobj_ipv4_add_wildcard_fqdn.yml
- name: CONFIG FMGR FIREWALL OBJECTS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: ADD IPv4 IP ADDRESS WILDCARD FQDN OBJECT
    fmgr_fwobj_address:
      ipv4: "wildcard-fqdn"
      mode: "add"
      adom: "ansible"
      wildcard_fqdn: "*.myds.com"
      name: "Synology myds DDNS service"
      comment: "Dev Example for Ansible"
      color: "22"
      #tags: "ansible, ipv4, test123, test321"
fmgr_fwobj_ipv4_add_wildcard.yml
- name: CONFIG FMGR FIREWALL OBJECTS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: ADD IPv4 IP ADDRESS WILDCARD OBJECT
    fmgr_fwobj_address:
      mode: "add"
      adom: "ansible"
      ipv4: "wildcard"
      wildcard: "10.7.220.0/24"
      name: "ansible_v4Obj_wildCard"
      comment: "Dev Example for Ansible"
      color: "22"
      #tags: "ansible, ipv4, test123, test321"

fmgr_fwobj_ippool

Playbook Task Examples
- name: ADD FMGR_FIREWALL_IPPOOL Overload
  fmgr_fwobj_ippool:
    mode: "add"
    adom: "ansible"
    name: "Ansible_pool4_overload"
    comments: "Created by ansible"
    type: "overload"

    # OPTIONS FOR ALL MODES
    startip: "10.10.10.10"
    endip: "10.10.10.100"
    arp_reply: "enable"

- name: ADD FMGR_FIREWALL_IPPOOL one-to-one
  fmgr_fwobj_ippool:
    mode: "add"
    adom: "ansible"
    name: "Ansible_pool4_121"
    comments: "Created by ansible"
    type: "one-to-one"

    # OPTIONS FOR ALL MODES
    startip: "10.10.20.10"
    endip: "10.10.20.100"
    arp_reply: "enable"

- name: ADD FMGR_FIREWALL_IPPOOL FIXED PORT RANGE
  fmgr_fwobj_ippool:
    mode: "add"
    adom: "ansible"
    name: "Ansible_pool4_fixed_port"
    comments: "Created by ansible"
    type: "fixed-port-range"

    # OPTIONS FOR ALL MODES
    startip: "10.10.40.10"
    endip: "10.10.40.100"
    arp_reply: "enable"
    # FIXED PORT RANGE OPTIONS
    source_startip: "192.168.20.1"
    source_endip: "192.168.20.20"

- name: ADD FMGR_FIREWALL_IPPOOL PORT BLOCK ALLOCATION
  fmgr_fwobj_ippool:
    mode: "add"
    adom: "ansible"
    name: "Ansible_pool4_port_block_allocation"
    comments: "Created by ansible"
    type: "port-block-allocation"

    # OPTIONS FOR ALL MODES
    startip: "10.10.30.10"
    endip: "10.10.30.100"
    arp_reply: "enable"
    # PORT BLOCK ALLOCATION OPTIONS
    block_size: "128"
    num_blocks_per_user: "1"
Playbook File Examples
fmgr_fwobj_ippool_del.yml
- name: CONFIG FMGR FIREWALL OBJECTS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: DELETE FMGR_FIREWALL_IPPOOL Overload
      fmgr_fwobj_ippool:
        mode: "delete"
        adom: "ansible"
        name: "Ansible_pool4_overload"
        comments: "Created by ansible"

    - name: DELETE FMGR_FIREWALL_IPPOOL Overload
      fmgr_fwobj_ippool:
        mode: "delete"
        adom: "ansible"
        name: "Ansible_pool4_121"
        comments: "Created by ansible"

    - name: DELETE FMGR_FIREWALL_IPPOOL Overload
      fmgr_fwobj_ippool:
        mode: "delete"
        adom: "ansible"
        name: "Ansible_pool4_fixed_port"
        comments: "Created by ansible"



    - name: DELETE FMGR_FIREWALL_IPPOOL Overload
      fmgr_fwobj_ippool:
        mode: "delete"
        adom: "ansible"
        name: "Ansible_pool4_port_block_allocation"
        comments: "Created by ansible"
fmgr_fwobj_ippool_add.yml
- name: CONFIG FMGR FIREWALL OBJECTS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: ADD FMGR_FIREWALL_IPPOOL Overload
      fmgr_fwobj_ippool:
        mode: "add"
        adom: "ansible"
        name: "Ansible_pool4_overload"
        comments: "Created by ansible"
        type: "overload"

        # OPTIONS FOR ALL MODES
        startip: "10.10.10.10"
        endip: "10.10.10.100"
        arp_reply: "enable"

      # FIXED PORT RANGE OPTIONS
#       source_startip:
#       source_endip:

      # PORT BLOCK ALLOCATION OPTIONS
#       block_size:
#       num_blocks_per_user:

      # ADVANCED OPTIONS
#       pba_timeout:
#       associated_interface:
#       permit_any_host:
#       arp_intf:

      # DYNAMIC "PER-DEVICE" MAPPING OPTIONS
#       dynamic_mapping_arp_intf:
#       dynamic_mapping_arp_reply:
#       dynamic_mapping_associated_interface:
#       dynamic_mapping_block_size:
#       dynamic_mapping_comments:
#       dynamic_mapping_endip:
#       dynamic_mapping_num_blocks_per_user:
#       dynamic_mapping_pba_timeout:
#       dynamic_mapping_permit_any_host:
#       dynamic_mapping_source_endip:
#       dynamic_mapping_source_startip:
#       dynamic_mapping_startip:
#       dynamic_mapping_type:


    - name: ADD FMGR_FIREWALL_IPPOOL one-to-one
      fmgr_fwobj_ippool:
        mode: "add"
        adom: "ansible"
        name: "Ansible_pool4_121"
        comments: "Created by ansible"
        type: "one-to-one"

        # OPTIONS FOR ALL MODES
        startip: "10.10.20.10"
        endip: "10.10.20.100"
        arp_reply: "enable"

    - name: ADD FMGR_FIREWALL_IPPOOL FIXED PORT RANGE
      fmgr_fwobj_ippool:
        mode: "add"
        adom: "ansible"
        name: "Ansible_pool4_fixed_port"
        comments: "Created by ansible"
        type: "fixed-port-range"

        # OPTIONS FOR ALL MODES
        startip: "10.10.40.10"
        endip: "10.10.40.100"
        arp_reply: "enable"
        # FIXED PORT RANGE OPTIONS
        source_startip: "192.168.20.1"
        source_endip: "192.168.20.20"

    - name: ADD FMGR_FIREWALL_IPPOOL PORT BLOCK ALLOCATION
      fmgr_fwobj_ippool:
        mode: "add"
        adom: "ansible"
        name: "Ansible_pool4_port_block_allocation"
        comments: "Created by ansible"
        type: "port-block-allocation"

        # OPTIONS FOR ALL MODES
        startip: "10.10.30.10"
        endip: "10.10.30.100"
        arp_reply: "enable"
        # PORT BLOCK ALLOCATION OPTIONS
        block_size: "128"
        num_blocks_per_user: "1"
fmgr_fwobj_ippool_run_all.sh
        #!/bin/bash
ansible-playbook fmgr_fwobj_ippool_del.yml -vvvv
ansible-playbook fmgr_fwobj_ippool_add.yml -vvvv

fmgr_fwobj_ippool6

Playbook Task Examples
- name: ADD FMGR_FIREWALL_IPPOOL6
  fmgr_firewall_ippool6:
    mode: "add"
    adom: "ansible"
    startip:
    name: "IPv6 IPPool"
    endip:
    comments: "Created by Ansible"

- name: DELETE FMGR_FIREWALL_IPPOOL6
  fmgr_firewall_ippool6:
    mode: "delete"
    adom: "ansible"
    name: "IPv6 IPPool"
Playbook File Examples
fmgr_fwobj_ippool6_del.yml
- name: CONFIG FMGR FIREWALL OBJECTS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: DELETE FMGR_FIREWALL_IPPOOL6
    fmgr_fwobj_ippool6:
      mode: "delete"
      adom: "ansible"
      name: "IPv6 IPPool"
fmgr_fwobj_ippool6_run_all.sh
        #!/bin/bash
ansible-playbook fmgr_fwobj_ippool6_del.yml -vvvv
ansible-playbook fmgr_fwobj_ippool6_add.yml -vvvv
fmgr_fwobj_ippool6_add.yml
- name: CONFIG FMGR FIREWALL OBJECTS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: ADD FMGR_FIREWALL_IPPOOL6
    fmgr_fwobj_ippool6:
      mode: "add"
      adom: "ansible"
      startip: "fd30:fc67:cb18:ae44::aaaa:aaaa"
      name: "IPv6 IPPool"
      endip: "fd30:fc67:cb18:ae44::ffff:ffff"
      comments: "Created by Ansible"

fmgr_fwobj_service

Playbook Task Examples
- name: ADD A CUSTOM SERVICE FOR TCP/UDP/SCP
  fmgr_fwobj_service:
    adom: "ansible"
    name: "ansible_custom_service"
    object_type: "custom"
    custom_type: "tcp_udp_sctp"
    tcp_portrange: "443"
    udp_portrange: "51"
    sctp_portrange: "100"

- name: ADD A CUSTOM SERVICE FOR TCP/UDP/SCP WITH SOURCE RANGES AND MULTIPLES
  fmgr_fwobj_service:
    adom: "ansible"
    name: "ansible_custom_serviceWithSource"
    object_type: "custom"
    custom_type: "tcp_udp_sctp"
    tcp_portrange: "443:2000-1000,80-82:10000-20000"
    udp_portrange: "51:100-200,162:200-400"
    sctp_portrange: "100:2000-2500"

- name: ADD A CUSTOM SERVICE FOR ICMP
  fmgr_fwobj_service:
    adom: "ansible"
    name: "ansible_custom_icmp"
    object_type: "custom"
    custom_type: "icmp"
    icmp_type: "8"
    icmp_code: "3"

- name: ADD A CUSTOM SERVICE FOR ICMP6
  fmgr_fwobj_service:
    adom: "ansible"
    name: "ansible_custom_icmp6"
    object_type: "custom"
    custom_type: "icmp6"
    icmp_type: "5"
    icmp_code: "1"

- name: ADD A CUSTOM SERVICE FOR IP - GRE
  fmgr_fwobj_service:
    adom: "ansible"
    name: "ansible_custom_icmp6"
    object_type: "custom"
    custom_type: "ip"
    protocol_number: "47"

- name: ADD A CUSTOM PROXY FOR ALL WITH SOURCE RANGES AND MULTIPLES
  fmgr_fwobj_service:
    adom: "ansible"
    name: "ansible_custom_proxy_all"
    object_type: "custom"
    custom_type: "all"
    explicit_proxy: "enable"
    tcp_portrange: "443:2000-1000,80-82:10000-20000"
    iprange: "www.ansible.com"
Playbook File Examples
fmgr_fwobj_service_run_all.sh
        #!/bin/bash
ansible-playbook fmgr_fwobj_service_delete_group.yml -vvvv
ansible-playbook fmgr_fwobj_service_add_group.yml -vvvv
ansible-playbook fmgr_fwobj_service_delete_custom.yml -vvvv
ansible-playbook fmgr_fwobj_service_delete_category.yml -vvvv
ansible-playbook fmgr_fwobj_service_add_custom.yml -vvvv
ansible-playbook fmgr_fwobj_service_add_category.yml -vvvv
fmgr_fwobj_service_delete_group.yml
- name: CONFIG CUSTOM SERVICES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: ADD A CUSTOM SERVICE GROUP
    fmgr_fwobj_service:
      adom: "ansible"
      object_type: "group"
      group_name: "ansibleTestGroup"
      mode: "delete"
fmgr_fwobj_service_add_group.yml
- name: CONFIG CUSTOM SERVICES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: ADD A CUSTOM SERVICE GROUP
    fmgr_fwobj_service:
      adom: "ansible"
      object_type: "group"
      comment: "created by ansible"
      group_name: "ansibleTestGroup"
      group_member: "ansible_custom_ip, ansible_custom_icmp, ansible_custom_service"
      color: "10"
fmgr_fwobj_service_delete_custom.yml
- name: CONFIG CUSTOM SERVICES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: REMOVE A CUSTOM SERVICE FOR TCP/UDP/SCP
    fmgr_fwobj_service:
      adom: "ansible"
      name: "ansible_custom_service"
      object_type: "custom"
      mode: "delete"

  - name: REMOVE A CUSTOM SERVICE FOR TCP/UDP/SCP
    fmgr_fwobj_service:
      adom: "ansible"
      name: "ansible_custom_icmp"
      object_type: "custom"
      mode: "delete"

  - name: REMOVE A CUSTOM SERVICE FOR TCP/UDP/SCP
    fmgr_fwobj_service:
      adom: "ansible"
      name: "ansible_custom_icmp6"
      object_type: "custom"
      mode: "delete"

  - name: REMOVE A CUSTOM SERVICE FOR TCP/UDP/SCP
    fmgr_fwobj_service:
      adom: "ansible"
      name: "ansible_custom_ip"
      object_type: "custom"
      mode: "delete"

  - name: REMOVE A CUSTOM SERVICE FOR TCP/UDP/SCP
    fmgr_fwobj_service:
      adom: "ansible"
      name: "ansible_custom_serviceWithSource"
      object_type: "custom"
      mode: "delete"

  - name: REMOVE A CUSTOM PROXY ALL
    fmgr_fwobj_service:
      adom: "ansible"
      name: "ansible_custom_proxy_all"
      object_type: "custom"
      mode: "delete"
fmgr_fwobj_service_delete_category.yml
- name: CONFIG CUSTOM SERVICES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: DELETE A CUSTOM SERVICE CATEGORY
    fmgr_fwobj_service:
      adom: "ansible"
      object_type: "category"
      category: "ansibleCategory5"
      mode: "delete"

  - name: DELETE A CUSTOM SERVICE CATEGORY 2
    fmgr_fwobj_service:
      adom: "ansible"
      object_type: "category"
      category: "ansibleCategory2"
      mode: "delete"

  - name: DELETE A CUSTOM SERVICE CATEGORY 3
    fmgr_fwobj_service:
      adom: "ansible"
      object_type: "category"
      category: "ansibleCategory"
      mode: "delete"
fmgr_fwobj_service_add_custom.yml
- name: CONFIG CUSTOM SERVICES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: ADD A CUSTOM SERVICE FOR TCP/UDP/SCP
    fmgr_fwobj_service:
      adom: "ansible"
      name: "ansible_custom_service"
      object_type: "custom"
      custom_type: "tcp_udp_sctp"
      tcp_portrange: "443"
      udp_portrange: "51"
      sctp_portrange: "100"
      category: "ansibleCategoryTest"

  - name: ADD A CUSTOM SERVICE FOR TCP/UDP/SCP WITH SOURCE RANGES AND MULTIPLES
    fmgr_fwobj_service:
      adom: "ansible"
      name: "ansible_custom_serviceWithSource"
      object_type: "custom"
      custom_type: "tcp_udp_sctp"
      tcp_portrange: "443:1000-2000,80-82:10000-20000"
      udp_portrange: "51:100-200,162:200-400"
      sctp_portrange: "100:2000-2500"

  - name: ADD A CUSTOM SERVICE FOR ICMP
    fmgr_fwobj_service:
      adom: "ansible"
      name: "ansible_custom_icmp"
      object_type: "custom"
      custom_type: "icmp"
      icmp_type: "8"
      icmp_code: "3"

  - name: ADD A CUSTOM SERVICE FOR ICMP6
    fmgr_fwobj_service:
      adom: "ansible"
      name: "ansible_custom_icmp6"
      object_type: "custom"
      custom_type: "icmp6"
      icmp_type: "5"
      icmp_code: "1"

  - name: ADD A CUSTOM SERVICE FOR IP - GRE
    fmgr_fwobj_service:
      adom: "ansible"
      name: "ansible_custom_ip"
      object_type: "custom"
      custom_type: "ip"
      protocol_number: "12"

  - name: ADD A CUSTOM PROXY FOR ALL WITH SOURCE RANGES AND MULTIPLES
    fmgr_fwobj_service:
      adom: "ansible"
      name: "ansible_custom_proxy_all"
      object_type: "custom"
      custom_type: "all"
      explicit_proxy: "enable"
      tcp_portrange: "443:1000-2000,80-82:10000-20000"
      iprange: "www.ansible.com"
fmgr_fwobj_service_add_category.yml
- name: CONFIG CUSTOM SERVICES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: ADD A CUSTOM SERVICE CATEGORY
    fmgr_fwobj_service:
      adom: "ansible"
      object_type: "category"
      comment: "created by ansible"
      category: "ansibleCategory5"
      mode: "set"

fmgr_fwobj_vip

Playbook Task Examples
# BASIC FULL STATIC NAT MAPPING
- name: EDIT FMGR_FIREWALL_VIP SNAT
  fmgr_fwobj_vip:
    name: "Basic StaticNAT Map"
    mode: "set"
    adom: "ansible"
    type: "static-nat"
    extip: "82.72.192.185"
    extintf: "any"
    mappedip: "10.7.220.25"
    comment: "Created by Ansible"
    color: "17"

# BASIC PORT PNAT MAPPING
- name: EDIT FMGR_FIREWALL_VIP PNAT
  fmgr_fwobj_vip:
    name: "Basic PNAT Map Port 10443"
    mode: "set"
    adom: "ansible"
    type: "static-nat"
    extip: "82.72.192.185"
    extport: "10443"
    extintf: "any"
    portforward: "enable"
    protocol: "tcp"
    mappedip: "10.7.220.25"
    mappedport: "443"
    comment: "Created by Ansible"
    color: "17"

# BASIC DNS TRANSLATION NAT
- name: EDIT FMGR_FIREWALL_DNST
  fmgr_fwobj_vip:
    name: "Basic DNS Translation"
    mode: "set"
    adom: "ansible"
    type: "dns-translation"
    extip: "192.168.0.1-192.168.0.100"
    extintf: "dmz"
    mappedip: "3.3.3.0/24, 4.0.0.0/24"
    comment: "Created by Ansible"
    color: "12"

# BASIC FQDN NAT
- name: EDIT FMGR_FIREWALL_FQDN
  fmgr_fwobj_vip:
    name: "Basic FQDN Translation"
    mode: "set"
    adom: "ansible"
    type: "fqdn"
    mapped_addr: "google-play"
    comment: "Created by Ansible"
    color: "5"

# DELETE AN ENTRY
- name: DELETE FMGR_FIREWALL_VIP PNAT
  fmgr_fwobj_vip:
    name: "Basic PNAT Map Port 10443"
    mode: "delete"
    adom: "ansible"
Playbook File Examples
fmgr_fwobj_vip_add_pnat.yml
- name: CONFIG CUSTOM SERVICES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  # BASIC FULL PNAT MAPPING
  - name: EDIT FMGR_FIREWALL_VIP PNAT
    fmgr_fwobj_vip:
      name: "Basic PNAT Map Port 10443"
      mode: "set"
      adom: "ansible"
      type: "static-nat"
      extip: "82.72.192.185"
      extport: "10443"
      extintf: "any"
      portforward: "enable"
      protocol: "tcp"
      mappedip: "10.7.220.25"
      mappedport: "443"
      comment: "Created by Ansible"
      color: "17"
fmgr_fwobj_vip_add_dnst.yml
- name: CONFIG CUSTOM SERVICES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: EDIT FMGR_FIREWALL_DNST
    fmgr_fwobj_vip:
      name: "Basic DNS Translation"
      mode: "set"
      adom: "ansible"
      type: "dns-translation"
      extip: "192.168.0.1-192.168.0.100"
      extintf: "dmz"
      mappedip: "3.3.3.0/24, 4.0.0.0/24"
      comment: "Created by Ansible"
      color: "12"
fmgr_fwobj_vip_add_fqdn.yml
- name: CONFIG CUSTOM SERVICES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: EDIT FMGR_FIREWALL_FQDN
    fmgr_fwobj_vip:
      name: "Basic FQDN Translation"
      mode: "set"
      adom: "ansible"
      type: "fqdn"
      mapped_addr: "google-play"
      comment: "Created by Ansible"
      color: "5"
fmgr_fwobj_vip_add_snat.yml
- name: CONFIG CUSTOM SERVICES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  # BASIC FULL STATIC NAT MAPPING
  - name: EDIT FMGR_FIREWALL_VIP SNAT
    fmgr_fwobj_vip:
      name: "Basic StaticNAT Map"
      mode: "set"
      adom: "ansible"
      type: "static-nat"
      extip: "82.72.192.185"
      extintf: "any"
      mappedip: "10.7.220.25"
      comment: "Created by Ansible"
      color: "17"
fmgr_fwobj_vip_TEMPLATE.yml
- name: CONFIG CUSTOM SERVICES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  # BASIC FULL PNAT MAPPING
  - name: EDIT FMGR_FIREWALL_VIP PNAT
    fmgr_fwobj_vip:
      name: "Basic PNAT Map Port 10443"
      mode: "set"
      adom: "ansible"
      type: "static-nat"
      extip: "82.72.192.185"
      extport: "10443"
      extintf: "any"
      portforward: "enable"
      protocol: "tcp"
      mappedip: "10.7.220.25"
      mappedport: "443"
      comment: "Created by Ansible"
      color: "17"
#      service:
#      server_type:
#      portmapping_type:
#      monitor:
#      max_embryonic_connections:
#      mapped_addr:
#      ldb_method:

# FILTERS!
#      srcintf_filter:
#      src_filter:


# ADVANCED OPTIONS!!
#      nat_source_vip:
#      persistence:
#      extaddr:
#      dns_mapping_ttl:
#      arp_reply:
#      outlook_web_access:
#      https_cookie_secure:
#      http_multiplex:
#      http_ip_header_name:
#      http_ip_header:
#      http_cookie_share:
#      http_cookie_path:
#      http_cookie_generation:
#      http_cookie_domain_from_host:
#      http_cookie_domain:
#      http_cookie_age:
#      gratuitous_arp_interval:
#      dynamic_mapping_arp_reply:
#      dynamic_mapping_color:
#      dynamic_mapping_comment:
#      dynamic_mapping_dns_mapping_ttl:
#      dynamic_mapping_extaddr:
#      dynamic_mapping_extintf:
#      dynamic_mapping_extip:
#      dynamic_mapping_extport:
#      dynamic_mapping_gratuitous_arp_interval:
#      dynamic_mapping_http_cookie_age:
#      dynamic_mapping_http_cookie_domain:
#      dynamic_mapping_http_cookie_domain_from_host:
#      dynamic_mapping_http_cookie_generation:
#      dynamic_mapping_http_cookie_path:
#      dynamic_mapping_http_cookie_share:
#      dynamic_mapping_http_ip_header:
#      dynamic_mapping_http_ip_header_name:
#      dynamic_mapping_http_multiplex:
#      dynamic_mapping_https_cookie_secure:
#      dynamic_mapping_ldb_method:
#      dynamic_mapping_mapped_addr:
#      dynamic_mapping_mappedip:
#      dynamic_mapping_mappedport:
#      dynamic_mapping_max_embryonic_connections:
#      dynamic_mapping_monitor:
#      dynamic_mapping_nat_source_vip:
#      dynamic_mapping_outlook_web_access:
#      dynamic_mapping_persistence:
#      dynamic_mapping_portforward:
#      dynamic_mapping_portmapping_type:
#      dynamic_mapping_protocol:
#      dynamic_mapping_server_type:
#      dynamic_mapping_service:
#      dynamic_mapping_src_filter:
#      dynamic_mapping_srcintf_filter:
#      dynamic_mapping_ssl_algorithm:
#      dynamic_mapping_ssl_certificate:
#      dynamic_mapping_ssl_client_fallback:
#      dynamic_mapping_ssl_client_renegotiation:
#      dynamic_mapping_ssl_client_session_state_max:
#      dynamic_mapping_ssl_client_session_state_timeout:
#      dynamic_mapping_ssl_client_session_state_type:
#      dynamic_mapping_ssl_dh_bits:
#      dynamic_mapping_ssl_hpkp:
#      dynamic_mapping_ssl_hpkp_age:
#      dynamic_mapping_ssl_hpkp_backup:
#      dynamic_mapping_ssl_hpkp_include_subdomains:
#      dynamic_mapping_ssl_hpkp_primary:
#      dynamic_mapping_ssl_hpkp_report_uri:
#      dynamic_mapping_ssl_hsts:
#      dynamic_mapping_ssl_hsts_age:
#      dynamic_mapping_ssl_hsts_include_subdomains:
#      dynamic_mapping_ssl_http_location_conversion:
#      dynamic_mapping_ssl_http_match_host:
#      dynamic_mapping_ssl_max_version:
#      dynamic_mapping_ssl_min_version:
#      dynamic_mapping_ssl_mode:
#      dynamic_mapping_ssl_pfs:
#      dynamic_mapping_ssl_send_empty_frags:
#      dynamic_mapping_ssl_server_algorithm:
#      dynamic_mapping_ssl_server_max_version:
#      dynamic_mapping_ssl_server_min_version:
#      dynamic_mapping_ssl_server_session_state_max:
#      dynamic_mapping_ssl_server_session_state_timeout:
#      dynamic_mapping_ssl_server_session_state_type:
#      dynamic_mapping_type:
#      dynamic_mapping_weblogic_server:
#      dynamic_mapping_websphere_server:
#      dynamic_mapping_realservers_client_ip:
#      dynamic_mapping_realservers_healthcheck:
#      dynamic_mapping_realservers_holddown_interval:
#      dynamic_mapping_realservers_http_host:
#      dynamic_mapping_realservers_ip:
#      dynamic_mapping_realservers_max_connections:
#      dynamic_mapping_realservers_monitor:
#      dynamic_mapping_realservers_port:
#      dynamic_mapping_realservers_seq:
#      dynamic_mapping_realservers_status:
#      dynamic_mapping_realservers_weight:
#      dynamic_mapping_ssl_cipher_suites_cipher:
#      dynamic_mapping_ssl_cipher_suites_versions:
#      realservers_client_ip:
#      realservers_healthcheck:
#      realservers_holddown_interval:
#      realservers_http_host:
#      realservers_ip:
#      realservers_max_connections:
#      realservers_monitor:
#      realservers_port:
#      realservers_seq:
#      realservers_status:
#      realservers_weight:
#      ssl_server_session_state_type:
#      ssl_server_session_state_timeout:
#      ssl_server_session_state_max:
#      ssl_server_min_version:
#      ssl_server_max_version:
#      ssl_server_algorithm:
#      ssl_send_empty_frags:
#      ssl_pfs:
#      ssl_mode:
#      ssl_min_version:
#      ssl_max_version:
#      ssl_http_match_host:
#      ssl_http_location_conversion:
#      ssl_hsts_include_subdomains:
#      ssl_hsts_age:
#      ssl_hsts:
#      ssl_hpkp_report_uri:
#      ssl_hpkp_primary:
#      ssl_hpkp_include_subdomains:
#      ssl_hpkp_backup:
#      ssl_hpkp_age:
#      ssl_hpkp:
#      ssl_dh_bits:
#      ssl_client_session_state_type:
#      ssl_client_session_state_timeout:
#      ssl_client_session_state_max:
#      ssl_client_renegotiation:
#      ssl_client_fallback:
#      ssl_certificate:
#      ssl_algorithm:
#      ssl_cipher_suites_cipher:
#      ssl_cipher_suites_versions:
#      ssl_server_cipher_suites_cipher:
#      ssl_server_cipher_suites_priority:
#      ssl_server_cipher_suites_versions:
#      websphere_server:
#      weblogic_server:
fmgr_fwobj_vip_del_all.yml
- name: CONFIG CUSTOM SERVICES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  # BASIC FULL PORT NAT MAPPING
  - name: DELETE FMGR_FIREWALL_VIP PNAT
    fmgr_fwobj_vip:
      name: "Basic PNAT Map Port 10443"
      mode: "delete"
      adom: "ansible"

  - name: DELETE FMGR_FIREWALL_VIP SNAT
    fmgr_fwobj_vip:
      name: "Basic StaticNAT Map"
      mode: "delete"
      adom: "ansible"

  - name: DELETE FMGR_FIREWALL_VIP DNS
    fmgr_fwobj_vip:
      name: "Basic DNS Translation"
      mode: "delete"
      adom: "ansible"

  - name: DELETE FMGR_FIREWALL_VIP FQDN
    fmgr_fwobj_vip:
      name: "Basic FQDN Translation"
      mode: "delete"
      adom: "ansible"
fmgr_fwobj_vip_run_all.sh
        #!/bin/bash
ansible-playbook fmgr_fwobj_vip_add_pnat.yml -vvvv
ansible-playbook fmgr_fwobj_vip_add_dnst.yml -vvvv
ansible-playbook fmgr_fwobj_vip_add_fqdn.yml -vvvv
ansible-playbook fmgr_fwobj_vip_add_snat.yml -vvvv
ansible-playbook fmgr_fwobj_vip_TEMPLATE.yml -vvvv
ansible-playbook fmgr_fwobj_vip_del_all.yml -vvvv

fmgr_fwpol_ipv4

Playbook Task Examples
- name: ADD VERY BASIC IPV4 POLICY WITH NO NAT (WIDE OPEN)
  fmgr_fwpol_ipv4:
    mode: "set"
    adom: "ansible"
    package_name: "default"
    name: "Basic_IPv4_Policy"
    comments: "Created by Ansible"
    action: "accept"
    dstaddr: "all"
    srcaddr: "all"
    dstintf: "any"
    srcintf: "any"
    logtraffic: "utm"
    service: "ALL"
    schedule: "always"

- name: ADD VERY BASIC IPV4 POLICY WITH NAT AND MULTIPLE ENTRIES
  fmgr_fwpol_ipv4:
    mode: "set"
    adom: "ansible"
    package_name: "default"
    name: "Basic_IPv4_Policy_2"
    comments: "Created by Ansible"
    action: "accept"
    dstaddr: "google-play"
    srcaddr: "all"
    dstintf: "any"
    srcintf: "any"
    logtraffic: "utm"
    service: "HTTP, HTTPS"
    schedule: "always"
    nat: "enable"
    users: "karen, kevin"

- name: ADD VERY BASIC IPV4 POLICY WITH NAT AND MULTIPLE ENTRIES AND SEC PROFILES
  fmgr_fwpol_ipv4:
    mode: "set"
    adom: "ansible"
    package_name: "default"
    name: "Basic_IPv4_Policy_3"
    comments: "Created by Ansible"
    action: "accept"
    dstaddr: "google-play, autoupdate.opera.com"
    srcaddr: "corp_internal"
    dstintf: "zone_wan1, zone_wan2"
    srcintf: "zone_int1"
    logtraffic: "utm"
    service: "HTTP, HTTPS"
    schedule: "always"
    nat: "enable"
    users: "karen, kevin"
    av_profile: "sniffer-profile"
    ips_sensor: "default"
Playbook File Examples
fmgr_fwpol_ipv4_add_basic.yml
- name: CONFIG FW POLICIES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: ADD VERY BASIC IPV4 POLICY WITH NO NAT (WIDE OPEN)
    fmgr_fwpol_ipv4:
      mode: "set"
      adom: "ansible"
      package_name: "default"
      name: "Basic_IPv4_Policy"
      comments: "Created by Ansible"
      action: "accept"
      dstaddr: "all"
      srcaddr: "all"
      dstintf: "any"
      srcintf: "any"
      logtraffic: "utm"
      service: "ALL"
      schedule: "always"
    ignore_errors: yes
    ignore_unreachable: yes

  - name: ADD VERY BASIC IPV4 POLICY WITH NAT AND MULTIPLE ENTRIES
    fmgr_fwpol_ipv4:
      mode: "set"
      adom: "ansible"
      package_name: "default"
      name: "Basic_IPv4_Policy_2"
      comments: "Created by Ansible"
      action: "accept"
      dstaddr: "google-play"
      srcaddr: "all"
      dstintf: "any"
      srcintf: "any"
      logtraffic: "utm"
      service: "HTTP, HTTPS"
      schedule: "always"
      nat: "enable"
      #users: "karen, kevin"
    ignore_errors: yes
    ignore_unreachable: yes

#  - name: ADD VERY BASIC IPV4 POLICY WITH NAT AND MULTIPLE ENTRIES AND SEC PROFILES
#    fmgr_fwpol_ipv4:
#      mode: "set"
#      adom: "ansible"
#      package_name: "default"
#      name: "Basic_IPv4_Policy_3"
#      comments: "Created by Ansible"
#      action: "accept"
#      dstaddr: "google-play, autoupdate.opera.com"
#      srcaddr: "any"
#      dstintf: "zone_wan1, zone_wan2"
#      srcintf: "zone_int1"
#      logtraffic: "utm"
#      service: "HTTP, HTTPS"
#      schedule: "always"
#      nat: "enable"
#      #users: "karen, kevin"
#      av_profile: "sniffer-profile"
#      ips_sensor: "default"
#    ignore_errors: yes
#    ignore_unreachable: yes
fmgr_fwpol_ipv4_run_all.sh
        #!/bin/bash
ansible-playbook fmgr_fwpol_ipv4_add_basic.yml -vvvv
ansible-playbook fmgr_fwpol_ipv4_delete_basic.yml -vvvv
fmgr_fwpol_ipv4_add_fsso.yml
- name: CONFIG FW POLICIES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: ADD VERY BASIC IPV4 POLICY WITH FSSO
    fmgr_fwpol_ipv4:
      mode: "set"
      adom: "root"
      package_name: "default"
      name: "Test_FSSO_IPv4_Policy"
      comments: "Created by Ansible"
      action: "accept"
      dstaddr: "srcaddr2"
      srcaddr: "srcaddr1"
      dstintf: "wan1"
      srcintf: "lan"
      logtraffic: "all"
      service: "ALL"
      schedule: "always"
      fsso: "enable"
      groups: "SSL_OMG_GR"
fmgr_fwpol_ipv4_delete_basic.yml
- name: CONFIG FW POLICIES
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: ADD VERY BASIC IPV4 POLICY WITH NO NAT (WIDE OPEN)
    fmgr_fwpol_ipv4:
      mode: "delete"
      adom: "ansible"
      package_name: "default"
      name: "Basic_IPv4_Policy"


  - name: ADD VERY BASIC IPV4 POLICY WITH NAT AND MULTIPLE ENTRIES
    fmgr_fwpol_ipv4:
      mode: "delete"
      adom: "ansible"
      package_name: "default"
      name: "Basic_IPv4_Policy_2"

#  - name: ADD VERY BASIC IPV4 POLICY WITH NAT AND MULTIPLE ENTRIES
#    fmgr_fwpol_ipv4:
#      mode: "delete"
#      adom: "ansible"
#      package_name: "default"
#      name: "Basic_IPv4_Policy_3"

fmgr_fwpol_package

Playbook Task Examples
- name: CREATE BASIC POLICY PACKAGE
  fmgr_fwpol_package:
    adom: "ansible"
    mode: "add"
    name: "testPackage"
    object_type: "pkg"

- name: ADD PACKAGE WITH TARGETS
  fmgr_fwpol_package:
    mode: "add"
    adom: "ansible"
    name: "ansibleTestPackage1"
    object_type: "pkg"
    inspection_mode: "flow"
    ngfw_mode: "profile-based"
    scope_members: "seattle-fgt02, seattle-fgt03"

- name: ADD FOLDER
  fmgr_fwpol_package:
    mode: "add"
    adom: "ansible"
    name: "ansibleTestFolder1"
    object_type: "folder"

- name: ADD PACKAGE INTO PARENT FOLDER
  fmgr_fwpol_package:
    mode: "set"
    adom: "ansible"
    name: "ansibleTestPackage2"
    object_type: "pkg"
    parent_folder: "ansibleTestFolder1"

- name: ADD FOLDER INTO PARENT FOLDER
  fmgr_fwpol_package:
    mode: "set"
    adom: "ansible"
    name: "ansibleTestFolder2"
    object_type: "folder"
    parent_folder: "ansibleTestFolder1"

- name: INSTALL PACKAGE
  fmgr_fwpol_package:
    mode: "install"
    adom: "ansible"
    name: "ansibleTestPackage1"

- name: REMOVE PACKAGE
  fmgr_fwpol_package:
    mode: "delete"
    adom: "ansible"
    name: "ansibleTestPackage1"
    object_type: "pkg"

- name: REMOVE NESTED PACKAGE
  fmgr_fwpol_package:
    mode: "delete"
    adom: "ansible"
    name: "ansibleTestPackage2"
    object_type: "pkg"
    parent_folder: "ansibleTestFolder1"

- name: REMOVE NESTED FOLDER
  fmgr_fwpol_package:
    mode: "delete"
    adom: "ansible"
    name: "ansibleTestFolder2"
    object_type: "folder"
    parent_folder: "ansibleTestFolder1"

- name: REMOVE FOLDER
  fmgr_fwpol_package:
    mode: "delete"
    adom: "ansible"
    name: "ansibleTestFolder1"
    object_type: "folder"
Playbook File Examples
fmgr_fwpol_plugin_install.yml
- name: CONFIG FW POLICY PACKAGES AND FOLDERS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
  - name: INSTALL PACKAGE 1
    fmgr_fwpol_package:
      mode: "install"
      object_type: "pkg"
      adom: "ansible"
      name: "ansibleTestPackage1"

  - name: INSTALL PACKAGE 2
    fmgr_fwpol_package:
      mode: "install"
      object_type: "pkg"
      adom: "ansible"
      name: "ansibleTestPackage2"
      parent_folder: "ansibleTestFolder1"
#
  - name: INSTALL PACKAGE 3
    fmgr_fwpol_package:
      mode: "install"
      object_type: "pkg"
      adom: "ansible"
      name: "ansibleTestPackage3"
      parent_folder: "ansibleTestFolder1/ansibleTestFolder2"
fmgr_fwpol_package_run_all.sh
        #!/bin/bash
ansible-playbook fmgr_fwpol_plugin_install.yml -vvvv
ansible-playbook fmgr_fwpol_package_add.yml -vvvv
ansible-playbook fmgr_fwpol_package_delete.yml -vvvv
ansible-playbook fmgr_fwpol_package_add_with_rules_install.yml -vvvv
ansible-playbook fmgr_fwpol_plugin_del.yml -vvvv
ansible-playbook fmgr_fwpol_package_install2vdom.yml -vvvv
ansible-playbook fmgr_fwpol_package_install.yml -vvvv
ansible-playbook fmgr_fwpol_package_assign2vdom.yml -vvvv
ansible-playbook fmgr_fwpol_plugin_add.yml -vvvv
fmgr_fwpol_package_add.yml
- name: CONFIG FW POLICY PACKAGES AND FOLDERS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
  - name: ADD PACKAGE WITH TARGETS
    fmgr_fwpol_package:
      mode: "add"
      adom: "ansible"
      name: "ansibleTestPackage1"
      object_type: "pkg"
      inspection_mode: "flow"
      ngfw_mode: "profile-based"
      scope_members: "FGT2, FGT3"

  - name: ADD FOLDER
    fmgr_fwpol_package:
      mode: "add"
      adom: "ansible"
      name: "ansibleTestFolder1"
      object_type: "folder"

  - name: ADD PACKAGE INTO PARENT FOLDER
    fmgr_fwpol_package:
      mode: "set"
      adom: "ansible"
      name: "ansibleTestPackage2"
      object_type: "pkg"
      parent_folder: "ansibleTestFolder1"

  - name: ADD FOLDER INTO PARENT FOLDER
    fmgr_fwpol_package:
      mode: "set"
      adom: "ansible"
      name: "ansibleTestFolder2"
      object_type: "folder"
      parent_folder: "ansibleTestFolder1"
fmgr_fwpol_package_delete.yml
- name: CONFIG FW POLICY PACKAGES AND FOLDERS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
  - name: REMOVE PACKAGE
    fmgr_fwpol_package:
      mode: "delete"
      adom: "ansible"
      name: "ansibleTestPackage1"
      object_type: "pkg"

  - name: REMOVE NESTED PACKAGE
    fmgr_fwpol_package:
      mode: "delete"
      adom: "ansible"
      name: "ansibleTestPackage2"
      object_type: "pkg"
      parent_folder: "ansibleTestFolder1"

  - name: REMOVE NESTED FOLDER
    fmgr_fwpol_package:
      mode: "delete"
      adom: "ansible"
      name: "ansibleTestFolder2"
      object_type: "folder"
      parent_folder: "ansibleTestFolder1"

  - name: REMOVE FOLDER
    fmgr_fwpol_package:
      mode: "delete"
      adom: "ansible"
      name: "ansibleTestFolder1"
      object_type: "folder"
fmgr_fwpol_package_add_with_rules_install.yml
- name: CONFIG FW POLICY PACKAGES AND FOLDERS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
  - name: ADD PACKAGE WITH TARGETS
    fmgr_fwpol_package:
      mode: "add"
      adom: "ansible"
      name: "ansibleTestPackage1"
      object_type: "pkg"
      inspection_mode: "flow"
      ngfw_mode: "profile-based"
      scope_members: "FGT2, FGT3"

  - name: ADD VERY BASIC IPV4 POLICY WITH NO NAT (WIDE OPEN)
    fmgr_fwpol_ipv4:
      mode: "set"
      adom: "ansible"
      package_name: "ansibleTestPackage1"
      name: "ansibleTestRule1"
      action: "accept"
      dstaddr: "all"
      srcaddr: "all"
      dstintf: "any"
      srcintf: "any"
      logtraffic: "utm"
      service: "ALL"
      schedule: "always"

  - name: INSTALL PACKAGE
    fmgr_fwpol_package:
      mode: "set"
      adom: "ansible"
      name: "ansibleTestPackage1"
      object_type: "install"
      scope_members: "FGT2, FGT3"
fmgr_fwpol_plugin_del.yml
- name: CONFIG FW POLICY PACKAGES AND FOLDERS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
  - name: DELETE ROOT PACKAGE
    fmgr_fwpol_package:
      mode: "delete"
      adom: "ansible"
      name: "ansibleTestPackage1"
      object_type: "pkg"
    ignore_errors: yes

  - name: REMOVE NESTED PACKAGE
    fmgr_fwpol_package:
      mode: "delete"
      adom: "ansible"
      name: "ansibleTestPackage2"
      object_type: "pkg"
      parent_folder: "ansibleTestFolder1"
    ignore_errors: yes

  - name: REMOVE NESTED PACKAGE 2
    fmgr_fwpol_package:
      mode: "delete"
      adom: "ansible"
      name: "ansibleTestPackage3"
      object_type: "pkg"
      parent_folder: "ansibleTestFolder1/ansibleTestFolder2"
    ignore_errors: yes

  - name: REMOVE NESTED PACKAGE 3
    fmgr_fwpol_package:
      mode: "delete"
      adom: "ansible"
      name: "ansibleTestPackage4"
      object_type: "pkg"
      parent_folder: "ansibleTestFolder1/ansibleTestFolder2/ansibleTestFolder3"
    ignore_errors: yes

  - name: REMOVE NESTED PACKAGE 4
    fmgr_fwpol_package:
      mode: "delete"
      adom: "ansible"
      name: "ansibleTestPackage5"
      object_type: "pkg"
      parent_folder: "ansibleTestFolder1/ansibleTestFolder2/ansibleTestFolder3/ansibleTestFolder4"
    ignore_errors: yes

  - name: REMOVE NESTED FOLDER 3
    fmgr_fwpol_package:
      mode: "delete"
      adom: "ansible"
      name: "ansibleTestFolder4"
      object_type: "folder"
      parent_folder: "ansibleTestFolder1/ansibleTestFolder2/ansibleTestFolder3"
    ignore_errors: yes

  - name: REMOVE NESTED FOLDER 3
    fmgr_fwpol_package:
      mode: "delete"
      adom: "ansible"
      name: "ansibleTestFolder3"
      object_type: "folder"
      parent_folder: "ansibleTestFolder1/ansibleTestFolder2"
    ignore_errors: yes

  - name: REMOVE NESTED FOLDER 2
    fmgr_fwpol_package:
      mode: "delete"
      adom: "ansible"
      name: "ansibleTestFolder2"
      object_type: "folder"
      parent_folder: "ansibleTestFolder1"
    ignore_errors: yes

  - name: REMOVE FOLDER
    fmgr_fwpol_package:
      mode: "delete"
      adom: "ansible"
      name: "ansibleTestFolder1"
      object_type: "folder"
    ignore_errors: yes
fmgr_fwpol_package_install2vdom.yml
- name: CONFIG FW POLICY PACKAGES AND FOLDERS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
  - name: INSTALL PACKAGE
    fmgr_fwpol_package:
      mode: "set"
      adom: "ansible"
      name: "ansibleTestPackage1"
      object_type: "install"
      scope_members: "FGT6"
      scope_members_vdom: "ansible1"
fmgr_fwpol_package_install.yml
- name: CONFIG FW POLICY PACKAGES AND FOLDERS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
  - name: INSTALL PACKAGE
    fmgr_fwpol_package:
      mode: "set"
      adom: "ansible"
      name: "ansibleTestPackage1"
      object_type: "install"
      scope_members: "FGT2, FGT3"
fmgr_fwpol_package_assign2vdom.yml
- name: CONFIG FW POLICY PACKAGES AND FOLDERS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
  - name: ADD PACKAGE WITH TARGETS
    fmgr_fwpol_package:
      mode: "add"
      adom: "ansible"
      name: "ansibleTestPackage1"
      object_type: "pkg"
      inspection_mode: "flow"
      ngfw_mode: "profile-based"
      scope_members: "FGT1"
      scope_members_vdom: "ansible1"
fmgr_fwpol_plugin_add.yml
- name: CONFIG FW POLICY PACKAGES AND FOLDERS
  hosts: FortiManager
  vars:
    json_dump: "True"
  connection: httpapi
  gather_facts: False

  tasks:
#  - name: ADD PACKAGE WITH TARGETS
#    fmgr_fwpol_package:
#      mode: "add"
#      adom: "ansible"
#      name: "ansibleTestPackage1"
#      object_type: "pkg"
#      inspection_mode: "flow"
#      ngfw_mode: "profile-based"
#      scope_members: "FGT2, FGT3"
#      scope_groups: "TestGroup"
#
#  - name: ADD PACKAGE MEMBERS
#    fmgr_fwpol_package:
#      mode: "add_targets"
#      adom: "ansible"
#      name: "ansibleTestPackage1"
#      object_type: "pkg"
#      scope_members: "FGT1"
#      scope_groups: "testtest"
#
#  - name: REMOVE PACKAGE MEMBERS
#    fmgr_fwpol_package:
#      mode: "delete_targets"
#      adom: "ansible"
#      name: "ansibleTestPackage1"
#      object_type: "pkg"
#      scope_members: "FGT2"
#      scope_groups: "TestGroup"
#
#  - name: ADD PACKAGE WITH TARGET GROUP
#    fmgr_fwpol_package:
#      mode: "set"
#      adom: "ansible"
#      name: "ansibleTestPackage1"
#      object_type: "pkg"
#      inspection_mode: "flow"
#      ngfw_mode: "profile-based"
#      scope_groups: "TestGroup"
#
  - name: ADD FOLDER
    fmgr_fwpol_package:
      mode: "set"
      adom: "ansible"
      name: "ansibleTestFolder1"
      object_type: "folder"

#  - name: ADD SECOND LEVEL FOLDER INTO PARENT FOLDER
#    fmgr_fwpol_package:
#      mode: "set"
#      adom: "ansible"
#      name: "ansibleTestFolder2"
#      object_type: "folder"
#      parent_folder: "ansibleTestFolder1"
#
#  - name: ADD THIRD LEVEL NESTED FOLDER
#    fmgr_fwpol_package:
#      mode: "set"
#      adom: "ansible"
#      name: "ansibleTestFolder3"
#      object_type: "folder"
#      parent_folder: "ansibleTestFolder1/ansibleTestFolder2"
#
#  - name: ADD FOURTH LEVEL NESTED FOLDER
#    fmgr_fwpol_package:
#      mode: "set"
#      adom: "ansible"
#      name: "ansibleTestFolder4"
#      object_type: "folder"
#      parent_folder: "ansibleTestFolder1/ansibleTestFolder2/ansibleTestFolder3"
#
#  - name: ADD PACKAGE INTO PARENT FOLDER 2
#    fmgr_fwpol_package:
#      mode: "set"
#      adom: "ansible"
#      name: "ansibleTestPackage2"
#      object_type: "pkg"
#      parent_folder: "ansibleTestFolder1"
#      inspection_mode: "flow"
#      ngfw_mode: "profile-based"
#      scope_members: "FGT2, FGT3"
#      scope_groups: "TestGroup"
#
#  - name: ADD PACKAGE MEMBERS 2
#    fmgr_fwpol_package:
#      mode: "add_targets"
#      adom: "ansible"
#      name: "ansibleTestPackage2"
#      object_type: "pkg"
#      scope_members: "FGT1, FGT2, FGT3"
#      scope_groups: "testtest, TestGroup"
#      parent_folder: "ansibleTestFolder1"
#
#  - name: REMOVE PACKAGE MEMBERS 2
#    fmgr_fwpol_package:
#      mode: "delete_targets"
#      adom: "ansible"
#      name: "ansibleTestPackage2"
#      object_type: "pkg"
#      scope_members: "FGT2"
#      scope_groups: "TestGroup"
#      parent_folder: "ansibleTestFolder1"
#
#
#  - name: ADD PACKAGE INTO CHILD FOLDER 3
#    fmgr_fwpol_package:
#      mode: "set"
#      adom: "ansible"
#      name: "ansibleTestPackage3"
#      object_type: "pkg"
#      parent_folder: "ansibleTestFolder1/ansibleTestFolder2"
#      inspection_mode: "flow"
#      ngfw_mode: "profile-based"
#      scope_members: "FGT2, FGT3"
#      scope_groups: "TestGroup"
#
#  - name: ADD NESTED PACKAGE MEMBERS 3
#    fmgr_fwpol_package:
#      mode: "add_targets"
#      adom: "ansible"
#      name: "ansibleTestPackage3"
#      object_type: "pkg"
#      scope_members: "FGT1, FGT2, FGT3"
#      scope_groups: "testtest, TestGroup"
#      parent_folder: "ansibleTestFolder1/ansibleTestFolder2"
#
#  - name: REMOVE NESTED PACKAGE MEMBERS 3
#    fmgr_fwpol_package:
#      mode: "delete_targets"
#      adom: "ansible"
#      name: "ansibleTestPackage3"
#      object_type: "pkg"
#      scope_members: "FGT2"
#      scope_groups: "TestGroup"
#      parent_folder: "ansibleTestFolder1/ansibleTestFolder2"
#
#  - name: ADD PACKAGE INTO CHILD FOLDER 4
#    fmgr_fwpol_package:
#      mode: "set"
#      adom: "ansible"
#      name: "ansibleTestPackage4"
#      object_type: "pkg"
#      parent_folder: "ansibleTestFolder1/ansibleTestFolder2/ansibleTestFolder3"
#      inspection_mode: "flow"
#      ngfw_mode: "profile-based"
#      scope_members: "FGT2, FGT3"
#      scope_groups: "TestGroup"
#
#  - name: ADD NESTED PACKAGE MEMBERS 4
#    fmgr_fwpol_package:
#      mode: "add_targets"
#      adom: "ansible"
#      name: "ansibleTestPackage4"
#      object_type: "pkg"
#      scope_members: "FGT1, FGT2, FGT3"
#      scope_groups: "testtest, TestGroup"
#      parent_folder: "ansibleTestFolder1/ansibleTestFolder2/ansibleTestFolder3"
#
#  - name: REMOVE NESTED PACKAGE MEMBERS 4
#    fmgr_fwpol_package:
#      mode: "delete_targets"
#      adom: "ansible"
#      name: "ansibleTestPackage4"
#      object_type: "pkg"
#      scope_members: "FGT2"
#      scope_groups: "TestGroup"
#      parent_folder: "ansibleTestFolder1/ansibleTestFolder2/ansibleTestFolder3"
#
#
#  - name: ADD PACKAGE INTO CHILD FOLDER 5
#    fmgr_fwpol_package:
#      mode: "set"
#      adom: "ansible"
#      name: "ansibleTestPackage5"
#      object_type: "pkg"
#      parent_folder: "ansibleTestFolder1/ansibleTestFolder2/ansibleTestFolder3/ansibleTestFolder4"
#      inspection_mode: "flow"
#      ngfw_mode: "profile-based"
#      scope_members: "FGT2, FGT3"
#      scope_groups: "TestGroup"
#
#  - name: ADD NESTED PACKAGE MEMBERS 5
#    fmgr_fwpol_package:
#      mode: "add_targets"
#      adom: "ansible"
#      name: "ansibleTestPackage5"
#      object_type: "pkg"
#      scope_members: "FGT1, FGT2, FGT3"
#      scope_groups: "testtest, TestGroup"
#      parent_folder: "ansibleTestFolder1/ansibleTestFolder2/ansibleTestFolder3/ansibleTestFolder4"
#
#  - name: REMOVE NESTED PACKAGE MEMBERS 5
#    fmgr_fwpol_package:
#      mode: "delete_targets"
#      adom: "ansible"
#      name: "ansibleTestPackage5"
#      object_type: "pkg"
#      scope_members: "FGT2"
#      scope_groups: "TestGroup"
#      parent_folder: "ansibleTestFolder1/ansibleTestFolder2/ansibleTestFolder3/ansibleTestFolder4"

fmgr_ha

Playbook Task Examples
- name: SET FORTIMANAGER HA NODE TO MASTER
  fmgr_ha:
    fmgr_ha_mode: "master"
    fmgr_ha_cluster_pw: "fortinet"
    fmgr_ha_cluster_id: "1"

- name: SET FORTIMANAGER HA NODE TO SLAVE
  fmgr_ha:
    fmgr_ha_mode: "slave"
    fmgr_ha_cluster_pw: "fortinet"
    fmgr_ha_cluster_id: "1"

- name: SET FORTIMANAGER HA NODE TO STANDALONE
  fmgr_ha:
    fmgr_ha_mode: "standalone"

- name: ADD FORTIMANAGER HA PEER
  fmgr_ha:
    fmgr_ha_peer_ipv4: "192.168.1.254"
    fmgr_ha_peer_sn: "FMG-VM1234567890"
    fmgr_ha_peer_status: "enable"

- name: CREATE CLUSTER ON MASTER
  fmgr_ha:
    fmgr_ha_mode: "master"
    fmgr_ha_cluster_pw: "fortinet"
    fmgr_ha_cluster_id: "1"
    fmgr_ha_hb_threshold: "10"
    fmgr_ha_hb_interval: "15"
    fmgr_ha_file_quota: "2048"
Playbook File Examples
fmgr_ha_run_all.sh
        #!/bin/bash
ansible-playbook fmgr_ha_run_all.sh -vvvv
ansible-playbook fmgr_ha_standalone.yml -vvvv
ansible-playbook fmgr_ha_enable_peer2.yml -vvvv
ansible-playbook fmgr_ha_slave.yml -vvvv
ansible-playbook fmgr_ha_enable_peer.yml -vvvv
ansible-playbook fmgr_ha_enable_peer_slave.yml -vvvv
ansible-playbook fmgr_ha_master.yml -vvvv
ansible-playbook fmgr_ha_disable_peer2.yml -vvvv
ansible-playbook fmgr_ha_disable_peer.yml -vvvv
fmgr_ha_standalone.yml
- name: SET FORTIMANAGER HA MODE TO STANDALONE
  hosts: FortiManager, FortiManagerSlave
  connection: httpapi
  gather_facts: False

  tasks:

  - name: SET FORTIMANAGER HA NODE TO STANDALONE
    fmgr_ha:
      fmgr_ha_mode: "standalone"
fmgr_ha_enable_peer2.yml
- name: ADD FMG HA PEER
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: ENABLE FORTIMANAGER HA PEER
      fmgr_ha:
        fmgr_ha_peer_ipv4: "10.7.220.140"
        fmgr_ha_peer_sn: "FMG-VM0A17005535"
        fmgr_ha_peer_status: "enable"
fmgr_ha_slave.yml
- name: SET FORTIMANAGER HA MODE TO SLAVE
  hosts: FortiManagerSlave
  connection: httpapi
  gather_facts: False

  tasks:
    - name: SET FORTIMANAGER HA NODE TO SLAVE
      fmgr_ha:
        fmgr_ha_mode: "slave"
        fmgr_ha_cluster_pw: "fortinet"
        fmgr_ha_cluster_id: "2"
fmgr_ha_enable_peer.yml
- name: ADD FMG HA PEER
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: ENABLE FORTIMANAGER HA PEER
      fmgr_ha:
        fmgr_ha_peer_ipv4: "10.7.220.36"
        fmgr_ha_peer_sn: "FMG-VMTM18001882"
        fmgr_ha_peer_status: "enable"
fmgr_ha_enable_peer_slave.yml
- name: ADD FMG HA PEER
  hosts: FortiManagerSlave
  connection: httpapi
  gather_facts: False

  tasks:
    - name: ADD FORTIMANAGER HA PEER
      fmgr_ha:
        fmgr_ha_peer_ipv4: "10.7.220.35"
        fmgr_ha_peer_sn: "FMG-VMTM18001881"
        fmgr_ha_peer_status: "enable"
        fmgr_ha_mode: "slave"
        fmgr_ha_cluster_pw: "fortinet"
        fmgr_ha_cluster_id: "2"
fmgr_ha_master.yml
- name: SET FORTIMANAGER HA MODE TO MASTER
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: SET FORTIMANAGER HA NODE TO MASTER
      fmgr_ha:
        fmgr_ha_mode: "master"
        fmgr_ha_cluster_pw: "fortinet"
        fmgr_ha_cluster_id: "2"
        fmgr_ha_hb_threshold: "10"
        fmgr_ha_hb_interval: "15"
        fmgr_ha_file_quota: "2048"
fmgr_ha_disable_peer2.yml
- name: ADD FMG HA PEER
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: DISABLE FORTIMANAGER HA PEER
      fmgr_ha:
        fmgr_ha_peer_ipv4: "10.7.220.140"
        fmgr_ha_peer_sn: "FMG-VM0A17005535"
        fmgr_ha_peer_status: "disable"
fmgr_ha_disable_peer.yml
- name: ADD FMG HA PEER
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: DISABLE FORTIMANAGER HA PEER
      fmgr_ha:
        fmgr_ha_peer_ipv4: "10.7.220.36"
        fmgr_ha_peer_sn: "FMG-VMTM18001882"
        fmgr_ha_peer_status: "disable"

fmgr_provisioning

Playbook Task Examples
- name: Create FGT1 Model Device
  fmgr_provisioning:
    adom: "root"
    vdom: "root"
    policy_package: "default"
    name: "FGT1"
    group: "Ansible"
    serial: "FGVM000000117994"
    platform: "FortiGate-VM64"
    description: "Provisioned by Ansible"
    os_version: '6.0'
    minor_release: 0
    patch_release: 0
    os_type: 'fos'


- name: Create FGT2 Model Device
  fmgr_provisioning:
    adom: "root"
    vdom: "root"
    policy_package: "test_pp"
    name: "FGT2"
    group: "Ansible"
    serial: "FGVM000000117992"
    platform: "FortiGate-VM64"
    description: "Provisioned by Ansible"
    os_version: '5.0'
    minor_release: 6
    patch_release: 0
    os_type: 'fos'
Playbook File Examples

%%PB_FILE_EXAMPLE_TOKEN%%

fmgr_query

Playbook Task Examples
- name: QUERY FORTIGATE DEVICE BY IP
  fmgr_query:
    object: "device"
    adom: "ansible"
    device_ip: "10.7.220.41"

- name: QUERY FORTIGATE DEVICE BY SERIAL
  fmgr_query:
    adom: "ansible"
    object: "device"
    device_serial: "FGVM000000117992"

- name: QUERY FORTIGATE DEVICE BY FRIENDLY NAME
  fmgr_query:
    adom: "ansible"
    object: "device"
    device_unique_name: "ansible-fgt01"

- name: VERIFY CLUSTER MEMBERS AND STATUS
  fmgr_query:
    adom: "ansible"
    object: "cluster_nodes"
    device_unique_name: "fgt-cluster01"
    nodes: ["ansible-fgt01", "ansible-fgt02", "ansible-fgt03"]

- name: GET STATUS OF TASK ID
  fmgr_query:
    adom: "ansible"
    object: "task"
    task_id: "3"

- name: USE CUSTOM TYPE TO QUERY AVAILABLE SCRIPTS
  fmgr_query:
    adom: "ansible"
    object: "custom"
    custom_endpoint: "/dvmdb/adom/ansible/script"
    custom_dict: { "type": "cli" }
Playbook File Examples
fmgr_query_test.yml
- name: CONFIG FW POLICY PACKAGES AND FOLDERS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
#  - name: QUERY FORTIGATE DEVICE BY IP
#    fmgr_query:
#      object: "device"
#      adom: "ansible"
#      device_ip: "10.7.220.151"

  - name: QUERY FORTIGATE DEVICE BY SERIAL
    fmgr_query:
      adom: "ansible"
      object: "device"
      device_serial: "FGVM04TM18000391"

  - name: QUERY FORTIGATE DEVICE BY FRIENDLY NAME
    fmgr_query:
      adom: "ansible"
      object: "device"
      device_unique_name: "FGT3"

#  - name: VERIFY CLUSTER MEMBERS AND STATUS
#    fmgr_query:
#      adom: "ansible"
#      object: "cluster_nodes"
#      device_unique_name: "nyc-fgt-cluster"
#      nodes: ["nyc-fgt01", "nyc-fgt02", "nyc-fgt03"]

  - name: GET STATUS OF TASK ID
    fmgr_query:
      adom: "ansible"
      object: "task"
      task_id: "247"

  - name: USE CUSTOM TYPE TO QUERY AVAILABLE SCRIPTS
    fmgr_query:
      adom: "ansible"
      object: "custom"
      custom_endpoint: "/dvmdb/adom/ansible/script"
      custom_dict: { "type": "cli" }
fmgr_query_run_all.sh
        #!/bin/bash
ansible-playbook fmgr_query_test.yml -vvvv
ansible-playbook fmgr_query_run_all.sh -vvvv

fmgr_script

Playbook Task Examples
- name: CREATE SCRIPT
  fmgr_script:
    adom: "root"
    script_name: "TestScript"
    script_type: "cli"
    script_target: "remote_device"
    script_description: "Create by Ansible"
    script_content: "get system status"

- name: EXECUTE SCRIPT
  fmgr_script:
    adom: "root"
    script_name: "TestScript"
    mode: "execute"
    script_scope: "FGT1,FGT2"

- name: DELETE SCRIPT
  fmgr_script:
    adom: "root"
    script_name: "TestScript"
    mode: "delete"
Playbook File Examples
fmgr_faz_scripts.yml
- name: CREATE AND EXECUTE SCRIPTS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: CREATE SCRIPT
      fmgr_script:
        adom: "ansible"
        script_name: "faz_init"
        script_type: "cli"
        script_target: "remote_device"
        script_description: "Created by Ansible"
        script_content: "config log fortianalyzer setting \n
                          set status enable \n
                          set server 10.7.220.38 \n
                          set upload-option realtime \n
                          set reliable enable \n
                          end \n"

    - name: EXECUTE SCRIPT
      fmgr_script:
        adom: "ansible"
        script_name: "faz_init"
        mode: "execute"
        script_scope: "FGT1"
fmgr_script_run_all.sh
        #!/bin/bash
ansible-playbook fmgr_faz_scripts.yml -vvvv
ansible-playbook fmgr_script_run_all.sh -vvvv
ansible-playbook fmgr_scripts.yml -vvvv
fmgr_scripts.yml
- name: CREATE AND EXECUTE SCRIPTS
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: CREATE SCRIPT
      fmgr_script:
        adom: "ansible"
        script_name: "TestScript"
        script_type: "cli"
        script_target: "remote_device"
        script_description: "Create by Ansible"
        script_content: "get system status"

    - name: EXECUTE SCRIPT
      fmgr_script:
        adom: "ansible"
        script_name: "TestScript"
        mode: "execute"
        script_scope: "FGT1"

    - name: DELETE SCRIPT
      fmgr_script:
        adom: "ansible"
        script_name: "TestScript"
        mode: "delete"

fmgr_secprof_appctrl

Playbook Task Examples
- name: DELETE Profile
  fmgr_secprof_appctrl:
    name: "Ansible_Application_Control_Profile"
    comment: "Created by Ansible Module TEST"
    mode: "delete"

- name: CREATE Profile
  fmgr_secprof_appctrl:
    name: "Ansible_Application_Control_Profile"
    comment: "Created by Ansible Module TEST"
    mode: "set"
    entries: [{
              action: "block",
              log: "enable",
              log-packet: "enable",
              protocols: ["1"],
              quarantine: "attacker",
              quarantine-log: "enable",
              },
              {action: "pass",
              category: ["2","3","4"]},
            ]
Playbook File Examples

%%PB_FILE_EXAMPLE_TOKEN%%

fmgr_secprof_av

Playbook Task Examples
- name: DELETE Profile
  fmgr_secprof_av:
    name: "Ansible_AV_Profile"
    mode: "delete"

- name: CREATE Profile
  fmgr_secprof_av:
    name: "Ansible_AV_Profile"
    comment: "Created by Ansible Module TEST"
    mode: "set"
    inspection_mode: "proxy"
    ftgd_analytics: "everything"
    av_block_log: "enable"
    av_virus_log: "enable"
    scan_mode: "full"
    mobile_malware_db: "enable"
    ftp_archive_block: "encrypted"
    ftp_outbreak_prevention: "files"
    ftp_archive_log: "timeout"
    ftp_emulator: "disable"
    ftp_options: "scan"
Playbook File Examples
fmgr_secprof_av_run_all.sh
        #!/bin/bash
ansible-playbook fmgr_secprof_av_add.yml -vvvv
ansible-playbook fmgr_secprof_av_del.yml -vvvv
ansible-playbook av.yml -vvvv
fmgr_secprof_av_add.yml
- name: SET FORTIMANAGER HA MODE TO SLAVE
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: CREATE Profile
      fmgr_secprof_av:
        name: "Ansible_AV_Profile"
        comment: "Created by Ansible Module TEST"
        mode: "set"
        inspection_mode: "proxy"
        ftgd_analytics: "everything"
        av_block_log: "enable"
        av_virus_log: "enable"
        scan_mode: "full"
        mobile_malware_db: "enable"
        ftp_archive_block: "encrypted"
        ftp_outbreak_prevention: "files"
        ftp_archive_log: "timeout"
        ftp_emulator: "disable"
        ftp_options: "scan"
        adom: "ansible"
fmgr_secprof_av_del.yml
- name: SET FORTIMANAGER HA MODE TO SLAVE
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
    - name: DELETE Profile
      fmgr_secprof_av:
        name: "Ansible_AV_Profile"
        mode: "delete"
av.yml
- name: Create and Delete security profile in FMG
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: DELETE Profile
    fmgr_secprof_av:
      name: "Ansible_AV_Profile"
      mode: "delete"
      adom: "ansible"


  - name: CREATE Profile
    fmgr_secprof_av:
      name: "Ansible_AV_Profile"
      comment: "Created by Ansible Module TEST"
      mode: "set"
      adom: "ansible"
      inspection_mode: "proxy"
      ftgd_analytics: "everything"
      av_block_log: "enable"
      av_virus_log: "enable"
      scan_mode: "full"
      mobile_malware_db: "enable"
      ftp_archive_block: "encrypted"
      ftp_outbreak_prevention: "files"
      ftp_archive_log: "timeout"
      ftp_emulator: "disable"
      ftp_options: "scan"

fmgr_secprof_dns

Playbook Task Examples
- name: DELETE Profile
  fmgr_secprof_dns:
    name: "Ansible_DNS_Profile"
    comment: "Created by Ansible Module TEST"
    mode: "delete"

- name: CREATE Profile
  fmgr_secprof_dns:
    name: "Ansible_DNS_Profile"
    comment: "Created by Ansible Module TEST"
    mode: "set"
    block_action: "block"
Playbook File Examples
fmgr_secprof_dns_run_all.sh
        #!/bin/bash
ansible-playbook dns.yml -vvvv
dns.yml
- name: Create and Delete security profile in FMG
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

#  - name: DELETE Profile
#    fmgr_secprof_dns:
#      name: "Ansible_DNS_Profile"
#      comment: "Created by Ansible Module TEST"
#      mode: "delete"


  - name: CREATE Profile
    fmgr_secprof_dns:
      name: "Ansible_DNS_Profile"
      comment: "Created by Ansible Module TEST"
      mode: "set"
      block_action: "block"

fmgr_secprof_ips

Playbook Task Examples
- name: DELETE Profile
  fmgr_secprof_ips:
    name: "Ansible_IPS_Profile"
    comment: "Created by Ansible Module TEST"
    mode: "delete"

- name: CREATE Profile
  fmgr_secprof_ips:
    name: "Ansible_IPS_Profile"
    comment: "Created by Ansible Module TEST"
    mode: "set"
    block_malicious_url: "enable"
    entries: [{severity: "high", action: "block", log-packet: "enable"}, {severity: "medium", action: "pass"}]
Playbook File Examples
ips.yml
- name: Create and Delete security profile in FMG
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

#  - name: DELETE Profile
#    fmgr_secprof_ips:
#      name: "Ansible_IPS_Profile"
#      comment: "Created by Ansible Module TEST"
#      mode: "delete"

  - name: CREATE Profile
    fmgr_secprof_ips:
      name: "Ansible_IPS_Profile"
      comment: "Created by Ansible Module TEST"
      mode: "set"
      block_malicious_url: "enable"
      entries: [{severity: "high", action: "block", log-packet: "enable"}, {severity: "medium", action: "pass"}]
#      replacemsg_group: "test"

#      replacemsg_group: [{admin: [{buffer: "buffer", format: "html", header: "http", msg-type: "test message"}],
#
#        alertmail: [{buffer: "buffer", format: "html", header: "http", msg-type: "test message"}],
#        auth: [{buffer: "buffer", format: "text", header: "8bit", msg-type: "test message"}],
#        comment: "Ansible",
#        group-type: "utm",
#        name: "replacement-message-ansible"
#      }
#      ]
ips2.yml
- name: Create and Delete security profile in FMG
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:
#    - name: DELETE Profile
#      fmgr_ips_sensor:
#        name: "Ansible_IPS_Profile"
#        comment: "Created by Ansible Module TEST"
#        mode: "delete"


    - name: CREATE Profile
      fmgr_ips_sensor:
        name: "Ansible_IPS_Profile"
        comment: "Created by Ansible Module TEST"
        mode: "set"
        block_malicious_url: "enable"

        entries_action: "block"
        entries_severity: "high"
        entries_log: "enable"
        entries_status: "enable"

        entries: [{severity: "high", action: "block"}, {severity: "low", action: "pass"}]
fmgr_secprof_ips_run_all.sh
        #!/bin/bash
ansible-playbook ips.yml -vvvv

fmgr_secprof_profile_group

Playbook Task Examples
- name: DELETE Profile
  fmgr_secprof_profile_group:
    name: "Ansible_TEST_Profile_Group"
    mode: "delete"

- name: CREATE Profile
  fmgr_secprof_profile_group:
    name: "Ansible_TEST_Profile_Group"
    mode: "set"
    av_profile: "Ansible_AV_Profile"
    profile_protocol_options: "default"
Playbook File Examples
security_profile.yml
- name: Create and Delete security profile in FMG
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: DELETE Profile
    fmgr_secprof_profile_group:
      name: "Ansible_TEST_Profile_Group"
      mode: "delete"


  - name: CREATE Profile
    fmgr_secprof_profile_group:
      name: "Ansible_TEST_Profile_Group"
      mode: "set"
      av_profile: "Ansible_AV_Profile"
      profile_protocol_options: "default"
fmgr_secprof_profile_group_run_all.sh
        #!/bin/bash
ansible-playbook security_profile.yml -vvvv

fmgr_secprof_proxy

Playbook Task Examples
- name: DELETE Profile
  fmgr_secprof_proxy:
    name: "Ansible_Web_Proxy_Profile"
    mode: "delete"

- name: CREATE Profile
  fmgr_secprof_proxy:
    name: "Ansible_Web_Proxy_Profile"
    mode: "set"
    header_client_ip: "pass"
    header_front_end_https: "add"
    header_via_request: "remove"
    header_via_response: "pass"
    header_x_authenticated_groups: "add"
    header_x_authenticated_user: "remove"
    strip_encoding: "enable"
    log_header_change: "enable"
    header_x_forwarded_for: "pass"
    headers_action: "add-to-request"
    headers_content: "test"
    headers_name: "test_header"
Playbook File Examples
proxy.yml
- name: Create and Delete security profile in FMG
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: DELETE Profile
    fmgr_secprof_proxy:
      name: "Ansible_Web_Proxy_Profile"
      mode: "delete"

  - name: CREATE Profile
    fmgr_secprof_proxy:
      name: "Ansible_Web_Proxy_Profile"
      mode: "set"
      header_client_ip: "pass"
      header_front_end_https: "add"
      header_via_request: "remove"
      header_via_response: "pass"
      header_x_authenticated_groups: "add"
      header_x_authenticated_user: "remove"
      strip_encoding: "enable"
      log_header_change: "enable"
      header_x_forwarded_for: "pass"
      headers_action: "add-to-request"
      headers_content: "test"
      headers_name: "test_header"
fmgr_secprof_proxy_run_all.sh
        #!/bin/bash
ansible-playbook proxy.yml -vvvv

fmgr_secprof_spam

Playbook Task Examples
- name: DELETE Profile
  fmgr_secprof_spam:
    name: "Ansible_Spam_Filter_Profile"
    mode: "delete"

- name: Create FMGR_SPAMFILTER_PROFILE
  fmgr_secprof_spam:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    mode: "set"
    adom: "root"
    spam_log_fortiguard_response: "enable"
    spam_iptrust_table:
    spam_filtering: "enable"
    spam_bword_threshold: 10
    options: ["bannedword", "spamfsip", "spamfsurl", "spamrbl", "spamfsphish", "spambwl"]
    name: "Ansible_Spam_Filter_Profile"
    flow_based: "enable"
    external: "enable"
    comment: "Created by Ansible"
    gmail_log: "enable"
    spam_log: "enable"
Playbook File Examples
fmgr_secprof_spam_run_all.sh
        #!/bin/bash
ansible-playbook spam.yml -vvvv
spam.yml
- name: Create and Delete security profile in FMG
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: DELETE Profile
    fmgr_secprof_spam:
      name: "Ansible_Spam_Filter_Profile"
      mode: "delete"

  - name: Create FMGR_SPAMFILTER_PROFILE
    fmgr_secprof_spam:
      mode: "set"
      adom: "root"
      spam_log_fortiguard_response: "enable"
      spam_iptrust_table:
      spam_filtering: "enable"
      spam_bword_threshold: 10
      options: ["bannedword", "spamfsip", "spamfsurl", "spamrbl", "spamfsphish", "spambwl"]
      name: "Ansible_Spam_Filter_Profile"
      flow_based: "enable"
      external: "enable"
      comment: "Created by Ansible"
      gmail_log: "enable"
      spam_log: "enable"

fmgr_secprof_ssl_ssh

Playbook Task Examples
- name: DELETE Profile
  fmgr_secprof_ssl_ssh:
    name: Ansible_SSL_SSH_Profile
    mode: delete

- name: CREATE Profile
  fmgr_secprof_ssl_ssh:
    name: Ansible_SSL_SSH_Profile
    comment: "Created by Ansible Module TEST"
    mode: set
    mapi_over_https: enable
    rpc_over_https: enable
    server_cert_mode: replace
    ssl_anomalies_log: enable
    ssl_exemptions_log: enable
    use_ssl_server: enable
    whitelist: enable
Playbook File Examples
ssl.yml
- name: Create and Delete security profile in FMG
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: DELETE Profile
    fmgr_secprof_ssl_ssh:
      name: "Ansible_SSL_SSH_Profile"
      mode: "delete"

  - name: CREATE Profile
    fmgr_secprof_ssl_ssh:
      name: "Ansible_SSL_SSH_Profile"
      comment: "Created by Ansible Module TEST"
      mode: "set"
      mapi_over_https: "enable"
      rpc_over_https: "enable"
      server_cert_mode: "replace"
      ssl_anomalies_log: "enable"
      ssl_exemptions_log: "enable"
      use_ssl_server: "enable"
      whitelist: "enable"
fmgr_secprof_ssl_ssh_run_all.sh
        #!/bin/bash
ansible-playbook ssl.yml -vvvv

fmgr_secprof_voip

Playbook Task Examples
- name: DELETE Profile
  fmgr_secprof_voip:
    name: "Ansible_VOIP_Profile"
    mode: "delete"

- name: Create FMGR_VOIP_PROFILE
  fmgr_secprof_voip:
    mode: "set"
    adom: "root"
    name: "Ansible_VOIP_Profile"
    comment: "Created by Ansible"
    sccp: {block-mcast: "enable", log-call-summary: "enable", log-violations: "enable", status: "enable"}
Playbook File Examples
voip.yml
- name: Create and Delete security profile in FMG
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: DELETE Profile
    fmgr_secprof_voip:
      name: "Ansible_VOIP_Profile"
      mode: "delete"

  - name: Create FMGR_VOIP_PROFILE
    fmgr_secprof_voip:
      mode: "set"
      adom: "root"
      name: "Ansible_VOIP_Profile"
      comment: "Created by Ansible"
      sccp: {block-mcast: "enable", log-call-summary: "enable", log-violations: "enable", status: "enable"}
fmgr_secprof_voip_run_all.sh
        #!/bin/bash
ansible-playbook voip.yml -vvvv

fmgr_secprof_waf

Playbook Task Examples
- name: DELETE Profile
  fmgr_secprof_waf:
    name: "Ansible_WAF_Profile"
    comment: "Created by Ansible Module TEST"
    mode: "delete"

- name: CREATE Profile
  fmgr_secprof_waf:
    name: "Ansible_WAF_Profile"
    comment: "Created by Ansible Module TEST"
    mode: "set"
Playbook File Examples
fmgr_secprof_waf_run_all.sh
        #!/bin/bash
ansible-playbook waf.yml -vvvv
waf.yml
- name: Create and Delete security profile in FMG
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: DELETE Profile
    fmgr_secprof_waf:
      name: "Ansible_WAF_Profile"
      comment: "Created by Ansible Module TEST"
      mode: "delete"

  - name: CREATE Profile
    fmgr_secprof_waf:
      name: "Ansible_WAF_Profile"
      comment: "Created by Ansible Module TEST"
      mode: "set"

fmgr_secprof_wanopt

Playbook Task Examples
- name: DELETE Profile
  fmgr_secprof_wanopt:
    name: "Ansible_WanOpt_Profile"
    mode: "delete"

- name: Create FMGR_WANOPT_PROFILE
  fmgr_secprof_wanopt:
    mode: "set"
    adom: "root"
    transparent: "enable"
    name: "Ansible_WanOpt_Profile"
    comments: "Created by Ansible"
    cifs: {byte-caching: "enable",
            log-traffic: "enable",
            port: 80,
            prefer-chunking: "dynamic",
            status: "enable",
            tunnel-sharing: "private"}
    ftp: {byte-caching: "enable",
            log-traffic: "enable",
            port: 80,
            prefer-chunking: "dynamic",
            secure-tunnel: "disable",
            status: "enable",
            tunnel-sharing: "private"}
Playbook File Examples
fmgr_secprof_wanopt_run_all.sh
        #!/bin/bash
ansible-playbook wanopt.yml -vvvv
wanopt.yml
- name: Create and Delete security profile in FMG
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

  - name: DELETE Profile
    fmgr_secprof_wanopt:
      name: "Ansible_WanOpt_Profile"
      mode: "delete"

  - name: Create FMGR_WANOPT_PROFILE
    fmgr_secprof_wanopt:
      mode: "set"
      adom: "root"
      transparent: "enable"
      name: "Ansible_WanOpt_Profile"
      comments: "Created by Ansible"
      cifs: {byte-caching: "enable",
              log-traffic: "enable",
              port: 80,
              prefer-chunking: "dynamic",
              status: "enable",
              tunnel-sharing: "private"}
      ftp: {byte-caching: "enable",
              log-traffic: "enable",
              port: 80,
              prefer-chunking: "dynamic",
              secure-tunnel: "disable",
              status: "enable",
              tunnel-sharing: "private"}

fmgr_secprof_web

Playbook Task Examples
- name: DELETE Profile
  fmgr_secprof_web:
    name: "Ansible_Web_Filter_Profile"
    mode: "delete"

- name: CREATE Profile
  fmgr_secprof_web:
    name: "Ansible_Web_Filter_Profile"
    comment: "Created by Ansible Module TEST"
    mode: "set"
    extended_log: "enable"
    inspection_mode: "proxy"
    log_all_url: "enable"
    options: "js"
    ovrd_perm: "bannedword-override"
    post_action: "block"
    web_content_log: "enable"
    web_extended_all_action_log: "enable"
    web_filter_activex_log: "enable"
    web_filter_applet_log: "enable"
    web_filter_command_block_log: "enable"
    web_filter_cookie_log: "enable"
    web_filter_cookie_removal_log: "enable"
    web_filter_js_log: "enable"
    web_filter_jscript_log: "enable"
    web_filter_referer_log: "enable"
    web_filter_unknown_log: "enable"
    web_filter_vbs_log: "enable"
    web_ftgd_err_log: "enable"
    web_ftgd_quota_usage: "enable"
    web_invalid_domain_log: "enable"
    web_url_log: "enable"
    wisp: "enable"
    wisp_algorithm: "auto-learning"
    youtube_channel_status: "blacklist"
Playbook File Examples
web.yml
- name: Create and Delete security profile in FMG
  hosts: FortiManager
  connection: httpapi
  gather_facts: False

  tasks:

#  - name: DELETE Profile
#    fmgr_secprof_web:
#      name: "Ansible_Web_Proxy_Profile"
#      mode: "delete"

  - name: CREATE Profile
    fmgr_secprof_web:
      name: "Ansible_Web_Proxy_Profile"
      comment: "Created by Ansible Module TEST"
      mode: "set"
      extended_log: "enable"
      inspection_mode: "proxy"
      log_all_url: "enable"
      options: "js"
      ovrd_perm: "bannedword-override"
      post_action: "block"
      web_content_log: "enable"
      web_extended_all_action_log: "enable"
      web_filter_activex_log: "enable"
      web_filter_applet_log: "enable"
      web_filter_command_block_log: "enable"
      web_filter_cookie_log: "enable"
      web_filter_cookie_removal_log: "enable"
      web_filter_js_log: "enable"
      web_filter_jscript_log: "enable"
      web_filter_referer_log: "enable"
      web_filter_unknown_log: "enable"
      web_filter_vbs_log: "enable"
      web_ftgd_err_log: "enable"
      web_ftgd_quota_usage: "enable"
      web_invalid_domain_log: "enable"
      web_url_log: "enable"
      wisp: "enable"
      wisp_algorithm: "auto-learning"
      youtube_channel_status: "blacklist"
fmgr_secprof_web_run_all.sh
        #!/bin/bash
ansible-playbook web.yml -vvvv

fmgr_sys_proxy

Playbook Task Examples
- name: Proxy FOS requests via FMG
  hosts: FortiManager
  connection: local
  gather_facts: False

  tasks:

    - name: Get upgrade path for FGT1
      fmgr_provision:
        adom: "root"
        action: "get"
        resource: "/api/v2/monitor/system/firmware/upgrade-paths?vdom=root"
        target: ["/adom/root/device/FGT1"]
    - name: Upgrade firmware of FGT1
      fmgr_provision:
        adom: "root"
        action: "post"
        payload: {source: upload, file_content: b64_encoded_string, file_name: file_name}
        resource: "/api/v2/monitor/system/firmware/upgrade?vdom=vdom"
        target: ["/adom/root/device/FGT1"]
Playbook File Examples

%%PB_FILE_EXAMPLE_TOKEN%%

FortiAnalyzer - DEPRECATED

These Ansible “base code” modules have been superseded by the new Ansible Galaxy Collections for FortiOS and FortiManager, and are no longer included in Ansible as of version 2.10.

Redhat has removed all vendor/partner modules from the Ansible Base Code, and moved everyone to Ansible Galaxy Collections.

Active maintenance and development for these “base code” modules has ended, and the new collections are to be used going forward, which is the new active project from Fortinet Engineering.

Getting Started - DEPRECATED

These Ansible “base code” modules have been superseded by the new Ansible Galaxy Collections for FortiOS and FortiManager, and are no longer included in Ansible as of version 2.10.

Redhat has removed all vendor/partner modules from the Ansible Base Code, and moved everyone to Ansible Galaxy Collections.

Active maintenance and development for these “base code” modules has ended, and the new collections are to be used going forward, which is the new active project from Fortinet Engineering.

Introduction

Beginning in Q1 of 2019 all up-to-date FortiAnalyzer modules now utilize a connection-plugin. Existing installations must convert going forward.

  • This requires modification to existing playbooks and inventory files that used the previous “connection: local” versions of FortiAnalyzer Plugins.
    • Follow the upgrade path defined below to utilize the new plugin.

Pre-Requisites

  • Minimum Ansible Version: 2.7+
  • Minimum Python Version: 2.7+
    • Works with Python 3.x
  • Minimum FortiAnalyzer Version: 6.0+
  • FortiAnalyzer account with rpc read/write enabled via CLI
  • A licensed FortiAnalyzer appliance or VM.

Fresh Installation

Step 1 - Auto Installation Method

This step is unavailable until we PR these components. TBA.

Step 2 (Optional) - Manual Installation Method
Summary
  • Until about 05-16-2019, the most recent versions of FortiAnalyzer ansible components must be manually installed to an existing Ansible 2.7+ installation.
  • Fortinet may make updates to Ansible components in-between Ansible release dates, and they can be installed in-between Ansible release schedules, manually.
  • These most-recent versions are located on the official FNDN github repo here: https://github.com/ftntcorecse/fndn_ansible
Steps
  • First, make sure Ansible is already installed, and shows version 2.7+.
  • The plugin and module_utils need to be copied to their correct locations. On Ubuntu running Python 2.7, the paths are:
/usr/lib/python2.7/dist-packages/ansible/plugins/httpapi/
/usr/lib/python2.7/dist-packages/ansible/module_utils/network/fortianalyzer/
  • If you’re unsure where to find this path on your own system, run this command:
find /usr -name "ansible"
Step 3 - Inventory File

The following variables must be added to the hosts file entries that correspond to the FortiAnalyzer hosts:

  • ansible_host=<ip/host>
    • Which FortiAnalyzer to connect to.
  • ansible_network_os=fortianalyzer
    • Tells Ansible which httpapi plugin to search for
  • ansible_user=<fmgr_username>
  • ansible_password=<fmgr_password>
  • ansible_become=no
  • ansible_become_method=disable
  • ansible_httpapi_use_ssl=true
  • ansible_httpapi_validate_certs=false
    • Switch to True if using in production!
  • ansible_httpapi_timeout=300
    • Sometimes it takes a while for FortiAnalyzer to process large requests or scripts. A large timeout is preferred.
    • In seconds.

These parameters can be added on the same line, or nested as shown in the code block below:

[FortiAnalyzer]
10.7.220.38 ansible_host=10.7.220.38

[FortiAnalyzerHA]
10.7.220.39 ansible_host=10.7.220.39

[faz_api:children]
FortiAnalyzer
FortiAnalyzerHA

[faz_api:vars]
ansible_network_os=fortianalyzer
ansible_user=ansible
ansible_password=fortinet
ansible_become=no
ansible_become_method=disable
ansible_httpapi_use_ssl=true
ansible_httpapi_validate_certs=false
ansible_httpapi_timeout=300
Step 4 - Playbook Test

Ansible should be ready to test now. Copy the following code block into a file named “test_faz.yml”:

---
- name: FAZ CONNECTION GET SYS STATUS
  hosts: FortiAnalyzer
  connection: httpapi
  gather_facts: False

  tasks:
  - name: TEST FAZ CONNECTION GET SYS STATUS
    faz_query:
      adom: "root"
      object: "custom"
      custom_endpoint: "/sys/status"

… and then run it with the following command:

ansible-playbook test_faz.yml -vvvv

If successful, it should report OK with Green Text and show various information about the target FortiAnalyzer.

If not successful, double check the hosts file, username/password combo, and that RPC read/write has been enabled for the FortiAnalyzer user. The -vvvv verbose mode should indicate where the issue lies.

Upgrade to Connection Plugin

Because all new modules are converted to use the connection plugin, the old method of using pyFMG and connection:local in playbooks is deprecated.

All playbooks must be converted to use the new plugin, and a few additions to the inventory file are required.

Step 1 - Inventory File

The following variables must be added to the hosts file entries that correspond to the FortiAnalyzer hosts:

  • ansible_host=<ip/host>
    • Which FortiAnalyzer to connect to.
  • ansible_network_os=fortianalyzer
    • Tells Ansible which httpapi plugin to search for
  • ansible_user=<fmgr_username>
  • ansible_password=<fmgr_password>
  • ansible_become=no
  • ansible_become_method=disable
  • ansible_httpapi_use_ssl=true
  • ansible_httpapi_validate_certs=false
    • Switch to True if using in production!
  • ansible_httpapi_timeout=300
    • Sometimes it takes a while for FortiAnalyzer to process large requests or scripts. A large timeout is preferred.
    • In seconds.

These parameters can be added on the same line, or nested as shown in the code block below:

[FortiAnalyzer]
10.7.220.38 ansible_host=10.7.220.38

[FortiAnalyzerHA]
10.7.220.39 ansible_host=10.7.220.39

[faz_api:children]
FortiAnalyzer
FortiAnalyzerHA

[faz_api:vars]
ansible_network_os=fortianalyzer
ansible_user=ansible
ansible_password=fortinet
ansible_become=no
ansible_become_method=disable
ansible_httpapi_use_ssl=true
ansible_httpapi_validate_certs=false
ansible_httpapi_timeout=300

Because the host, username, and password have all been added to the connection/host level they must be removed from playbooks.

Step 2 - Playbook Conversion

Previous playbooks might look like this:

---
- name: CONFIG FGT HOSTNAME AND INTERFACE
  hosts: FortiAnalyzer
  connection: local
  gather_facts: False

  tasks:

  - name: DISCOVER AND ADD DEVICE A VIRTUAL FORTIGATE
    faz_device:
      host: "{{inventory_hostname}}"
      username: "{{ username }}"
      password: "{{ password }}"
      adom: "root"
      device_ip: "10.7.220.151"
      device_password: "fortinet"
      device_unique_name: "FGT01"
      device_username: "ansible"
      mgmt_mode: "faz"
      os_minor_vers: 6
      os_type: "fos"
      os_ver: "5.0"
      platform_str: "FortiGate-VM64"
      mode: "add"
      device_serial: "FGVM010000122995"
  • The host, username, and password lines from each task need to be deleted.
  • The heading attribute “connection: local” must be changed to “connection: httpapi”

Converted version of the above playbook:

---
- name: CONFIG FGT HOSTNAME AND INTERFACE
  hosts: FortiAnalyzer
  connection: httpapi
  gather_facts: False

  tasks:

  - name: DISCOVER AND ADD DEVICE A VIRTUAL FORTIGATE
    faz_device:
      adom: "root"
      device_ip: "10.7.220.151"
      device_password: "fortinet"
      device_unique_name: "FGT01"
      device_username: "ansible"
      mgmt_mode: "faz"
      os_minor_vers: 6
      os_type: "fos"
      os_ver: "5.0"
      platform_str: "FortiGate-VM64"
      mode: "add"
      device_serial: "FGVM010000122995"
Step 3a - Auto Installation Method

This step is unavailable until we PR these components. TBA.

Step 2 (Optional) - Manual Installation Method
Summary
  • Until about 05-16-2019, the most recent versions of FortiAnalyzer ansible components must be manually installed to an existing Ansible 2.7+ installation.
  • Fortinet may make updates to Ansible components in-between Ansible release dates, and they can be installed in-between Ansible release schedules, manually.
  • These most-recent versions are located on the official FNDN github repo here: https://github.com/ftntcorecse/fndn_ansible
Steps
  • First, make sure Ansible is already installed, and shows version 2.7+.
  • The plugin and module_utils need to be copied to their correct locations. On Ubuntu running Python 2.7, the paths are:
/usr/lib/python2.7/dist-packages/ansible/plugins/httpapi/
/usr/lib/python2.7/dist-packages/ansible/module_utils/network/fortianalyzer/
  • If you’re unsure where to find this path on your own system, run this command:
find /usr -name "ansible"

- ... and the path under a python dist-packages should present itself.
Step 4 - Playbook Test

After modifying the hosts inventory file, and either manually or automatically installing the latest FortiAnalyzer Ansible components, the converted playbooks from Step 2 should now run.

For a sample status check, copy the following code block into a file named “test_faz.yml”:

---
- name: FAZ CONNECTION GET SYS STATUS
  hosts: FortiAnalyzer
  connection: httpapi
  gather_facts: False

  tasks:
  - name: TEST FAZ CONNECTION GET SYS STATUS
    faz_query:
      adom: "root"
      object: "custom"
      custom_endpoint: "/sys/status"

… and then run it with the following command:

ansible-playbook test_faz.yml -vvvv

If successful, it should report OK with Green Text and show various information about the target FortiAnalyzer.

If not successful, double check the hosts file, username/password combo, and that RPC read/write has been enabled for the FortiAnalyzer user. The -vvvv verbose mode should indicate where the issue lies.

Using Ansible Vault to Hide Logins

There are many ways to implement Ansible Vault. Feel free to use any method desired. If no previous experience with Ansible Vault exists, we recommend starting with this method:

The procedure is simple:

  • Use ‘ansible-vault encrypt string’ on ansible host to create a vault string.
  • Replace vault string in HOSTS or Variables file, for the username/password or both.
fortianalyzer:
  ansible_user: "ansible"
  ansible_host: "10.7.220.35"
  ansible_password: !vault |
    $ANSIBLE_VAULT;1.1;AES256
    61366437333436393062623438393663366138633265363930313763383964313130643134383839
    3630663661626365366334646661303338313866373032330a636165373833366166616465373830
    34356466653464313134313664613435356238666139623165623132306538336565376265356633
    6362396137306466630a666562393637353863626436376132643464366661323734363830383164
    6366
  • Add a reference to the variable file/vault file from the playbook itself:
---
- name: Create and Delete security profile in FMG
  hosts: FortiAnalyzer
  connection: httpapi
  gather_facts: False
  vars_files:
    - group_vars/vault.yml
  • And then run playbooks with –ask-vault-pass, or setup a password file to provide it.

It is recommended to keep vault secret variables in their own files, so the un-encrypted variables could be read by peers.

Additional Ansible Vault tutorials, references, and alternative implementation methods:

Appendix

Enabling FortiAnalyzer user for RPC Read/Write via FAZ CLI
config system admin user
  edit <username>
  set rpc read-write
  next
end

Modules

faz_device

Metadata

Name: faz_device

Description: Add or remove a device or list of devices to FortiAnalyzer Device Manager. ADOM Capable.

Author(s): Luke Weighall (@lweighall)

Ansible Version Added/Required: 2.9

Dev Status: No status updates, yet. Contact Authors.

Parameters
adom
  • Description: The ADOM the configuration should belong to.
  • Required: True
  • default: root
device_ip
  • Description: The IP of the device being added to FortiAnalyzer.
  • Required: False
device_password
  • Description: The password of the device being added to FortiAnalyzer.
  • Required: False
device_serial
  • Description: The serial number of the device being added to FortiAnalyzer.
  • Required: False
device_unique_name
  • Description: The desired “friendly” name of the device being added to FortiAnalyzer.
  • Required: False
device_username
  • Description: The username of the device being added to FortiAnalyzer.
  • Required: False
faz_quota
  • Description: Specifies the quota for the device in FAZ
  • Required: False
mgmt_mode
  • Description: Management Mode of the device you are adding.
  • Required: True
  • choices: [‘unreg’, ‘fmg’, ‘faz’, ‘fmgfaz’]
mode
  • Description: Add or delete devices. Or promote unregistered devices that are in the FortiAnalyzer “waiting pool”
  • Required: False
  • default: add
  • choices: [‘add’, ‘delete’, ‘promote’]
os_minor_vers
  • Description: Minor OS rev of the device
  • Required: True
os_type
  • Description: The os type of the device being added (default 0).
  • Required: True
  • choices: [‘unknown’, ‘fos’, ‘fsw’, ‘foc’, ‘fml’, ‘faz’, ‘fwb’, ‘fch’, ‘fct’, ‘log’, ‘fmg’, ‘fsa’, ‘fdd’, ‘fac’]
os_ver
  • Description: Major OS rev of the device
  • Required: True
  • choices: [‘unknown’, ‘0.0’, ‘1.0’, ‘2.0’, ‘3.0’, ‘4.0’, ‘5.0’, ‘6.0’]
platform_str
  • Description: Required for determine the platform for VM platforms. ie FortiGate-VM64
  • Required: False
Functions
  • faz_add_device
def faz_add_device(faz, paramgram):
    """
    This method is used to add devices to the faz or delete them
    """

    datagram = {
        "adom": paramgram["adom"],
        "device": {"adm_usr": paramgram["device_username"], "adm_pass": paramgram["device_password"],
                   "ip": paramgram["ip"], "name": paramgram["device_unique_name"],
                   "mgmt_mode": paramgram["mgmt_mode"], "os_type": paramgram["os_type"],
                   "mr": paramgram["os_minor_vers"]}
    }

    if paramgram["platform_str"] is not None:
        datagram["device"]["platform_str"] = paramgram["platform_str"]

    if paramgram["sn"] is not None:
        datagram["device"]["sn"] = paramgram["sn"]

    if paramgram["device_action"] is not None:
        datagram["device"]["device_action"] = paramgram["device_action"]

    if paramgram["faz.quota"] is not None:
        datagram["device"]["faz.quota"] = paramgram["faz.quota"]

    url = '/dvm/cmd/add/device/'
    response = faz.process_request(url, datagram, FAZMethods.EXEC)
    return response
  • faz_delete_device
def faz_delete_device(faz, paramgram):
    """
    This method deletes a device from the FAZ
    """
    datagram = {
        "adom": paramgram["adom"],
        "device": paramgram["device_unique_name"],
    }

    url = '/dvm/cmd/del/device/'
    response = faz.process_request(url, datagram, FAZMethods.EXEC)
    return response
  • faz_get_unknown_devices
def faz_get_unknown_devices(faz):
    """
    This method gets devices with an unknown management type field
    """

    faz_filter = ["mgmt_mode", "==", "0"]

    datagram = {
        "filter": faz_filter
    }

    url = "/dvmdb/device"
    response = faz.process_request(url, datagram, FAZMethods.GET)

    return response
  • faz_approve_unregistered_device_by_ip
def faz_approve_unregistered_device_by_ip(faz, paramgram):
    """
    This method approves unregistered devices by ip.
    """
    # TRY TO FIND DETAILS ON THIS UNREGISTERED DEVICE
    unknown_devices = faz_get_unknown_devices(faz)
    target_device = None
    if unknown_devices[0] == 0:
        for device in unknown_devices[1]:
            if device["ip"] == paramgram["ip"]:
                target_device = device
    else:
        return "No devices are waiting to be registered!"

    # now that we have the target device details...fill out the datagram and make the call to promote it
    if target_device is not None:
        target_device_paramgram = {
            "adom": paramgram["adom"],
            "ip": target_device["ip"],
            "device_username": paramgram["device_username"],
            "device_password": paramgram["device_password"],
            "device_unique_name": paramgram["device_unique_name"],
            "sn": target_device["sn"],
            "os_type": target_device["os_type"],
            "mgmt_mode": paramgram["mgmt_mode"],
            "os_minor_vers": target_device["mr"],
            "os_ver": target_device["os_ver"],
            "platform_str": target_device["platform_str"],
            "faz.quota": target_device["faz.quota"],
            "device_action": paramgram["device_action"]
        }

        add_device = faz_add_device(faz, target_device_paramgram)
        return add_device

    return str("Couldn't find the desired device with ip: " + str(paramgram["device_ip"]))
  • faz_approve_unregistered_device_by_name
def faz_approve_unregistered_device_by_name(faz, paramgram):
    # TRY TO FIND DETAILS ON THIS UNREGISTERED DEVICE
    unknown_devices = faz_get_unknown_devices(faz)
    target_device = None
    if unknown_devices[0] == 0:
        for device in unknown_devices[1]:
            if device["name"] == paramgram["device_unique_name"]:
                target_device = device
    else:
        return "No devices are waiting to be registered!"

    # now that we have the target device details...fill out the datagram and make the call to promote it
    if target_device is not None:
        target_device_paramgram = {
            "adom": paramgram["adom"],
            "ip": target_device["ip"],
            "device_username": paramgram["device_username"],
            "device_password": paramgram["device_password"],
            "device_unique_name": paramgram["device_unique_name"],
            "sn": target_device["sn"],
            "os_type": target_device["os_type"],
            "mgmt_mode": paramgram["mgmt_mode"],
            "os_minor_vers": target_device["mr"],
            "os_ver": target_device["os_ver"],
            "platform_str": target_device["platform_str"],
            "faz.quota": target_device["faz.quota"],
            "device_action": paramgram["device_action"]
        }

        add_device = faz_add_device(faz, target_device_paramgram)
        return add_device

    return str("Couldn't find the desired device with name: " + str(paramgram["device_unique_name"]))
  • main
def main():
    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        mode=dict(choices=["add", "delete", "promote"], type="str", default="add"),

        device_ip=dict(required=False, type="str"),
        device_username=dict(required=False, type="str"),
        device_password=dict(required=False, type="str", no_log=True),
        device_unique_name=dict(required=False, type="str"),
        device_serial=dict(required=False, type="str"),

        os_type=dict(required=False, type="str"),
        mgmt_mode=dict(required=False, type="str"),
        os_minor_vers=dict(required=False, type="str"),
        os_ver=dict(required=False, type="str"),
        platform_str=dict(required=False, type="str"),
        faz_quota=dict(required=False, type="str")
    )

    required_if = [
        ['mode', 'delete', ['device_unique_name']],
        ['mode', 'add', ['device_serial', 'device_username',
                         'device_password', 'device_unique_name', 'device_ip', 'mgmt_mode', 'platform_str']]

    ]

    module = AnsibleModule(argument_spec, supports_check_mode=True, required_if=required_if, )

    # START SESSION LOGIC
    paramgram = {
        "adom": module.params["adom"],
        "mode": module.params["mode"],
        "ip": module.params["device_ip"],
        "device_username": module.params["device_username"],
        "device_password": module.params["device_password"],
        "device_unique_name": module.params["device_unique_name"],
        "sn": module.params["device_serial"],
        "os_type": module.params["os_type"],
        "mgmt_mode": module.params["mgmt_mode"],
        "os_minor_vers": module.params["os_minor_vers"],
        "os_ver": module.params["os_ver"],
        "platform_str": module.params["platform_str"],
        "faz.quota": module.params["faz_quota"],
        "device_action": None
    }
    # INSERT THE PARAMGRAM INTO THE MODULE SO WHEN WE PASS IT TO MOD_UTILS.FortiManagerHandler IT HAS THAT INFO

    if paramgram["mode"] == "add":
        paramgram["device_action"] = "add_model"
    elif paramgram["mode"] == "promote":
        paramgram["device_action"] = "promote_unreg"
    module.paramgram = paramgram

    # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
    faz = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        faz = FortiAnalyzerHandler(connection, module)
        faz.tools = FAZCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION
    results = DEFAULT_RESULT_OBJ

    try:
        if paramgram["mode"] == "add":
            results = faz_add_device(faz, paramgram)
    except BaseException as err:
        raise FAZBaseException(msg="An error occurred trying to add the device. Error: " + str(err))

    try:
        if paramgram["mode"] == "promote":
            if paramgram["ip"] is not None:
                results = faz_approve_unregistered_device_by_ip(faz, paramgram)
            elif paramgram["device_unique_name"] is not None:
                results = faz_approve_unregistered_device_by_name(faz, paramgram)
    except BaseException as err:
        raise FAZBaseException(msg="An error occurred trying to promote the device. Error: " + str(err))

    try:
        if paramgram["mode"] == "delete":
            results = faz_delete_device(faz, paramgram)
    except BaseException as err:
        raise FAZBaseException(msg="An error occurred trying to delete the device. Error: " + str(err))

    # PROCESS RESULTS
    try:
        faz.govern_response(module=module, results=results,
                            ansible_facts=faz.construct_ansible_facts(results, module.params, paramgram))
    except BaseException as err:
        raise FAZBaseException(msg="An error occurred with govern_response(). Error: " + str(err))

    # This should only be hit if faz.govern_response is missed or failed somehow. In fact. It should never be hit.
    # But it's here JIC.
    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function

__metaclass__ = type

ANSIBLE_METADATA = {
    "metadata_version": "1.1",
    "status": ["preview"],
    "supported_by": "community"
}

DOCUMENTATION = '''
---
module: faz_device
version_added: "2.9"
author: Luke Weighall (@lweighall)
short_description: Add or remove device
description:
  - Add or remove a device or list of devices to FortiAnalyzer Device Manager. ADOM Capable.

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: true
    default: root

  mode:
    description:
      - Add or delete devices. Or promote unregistered devices that are in the FortiAnalyzer "waiting pool"
    required: false
    default: add
    choices: ["add", "delete", "promote"]

  device_username:
    description:
      - The username of the device being added to FortiAnalyzer.
    required: false

  device_password:
    description:
      - The password of the device being added to FortiAnalyzer.
    required: false

  device_ip:
    description:
      - The IP of the device being added to FortiAnalyzer.
    required: false

  device_unique_name:
    description:
      - The desired "friendly" name of the device being added to FortiAnalyzer.
    required: false

  device_serial:
    description:
      - The serial number of the device being added to FortiAnalyzer.
    required: false

  os_type:
    description:
      - The os type of the device being added (default 0).
    required: true
    choices: ["unknown", "fos", "fsw", "foc", "fml", "faz", "fwb", "fch", "fct", "log", "fmg", "fsa", "fdd", "fac"]

  mgmt_mode:
    description:
      - Management Mode of the device you are adding.
    choices: ["unreg", "fmg", "faz", "fmgfaz"]
    required: true

  os_minor_vers:
    description:
      - Minor OS rev of the device
    required: true

  os_ver:
    description:
      - Major OS rev of the device
    required: true
    choices: ["unknown", "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "6.0"]

  platform_str:
    description:
      - Required for determine the platform for VM platforms. ie FortiGate-VM64
    required: false

  faz_quota:
    description:
      - Specifies the quota for the device in FAZ
    required: False

'''

EXAMPLES = '''
- name: DISCOVER AND ADD DEVICE A PHYSICAL FORTIGATE
  faz_device:
    adom: "root"
    device_username: "admin"
    device_password: "admin"
    device_ip: "10.10.24.201"
    device_unique_name: "FGT1"
    device_serial: "FGVM000000117994"
    state: "present"
    mgmt_mode: "faz"
    os_type: "fos"
    os_ver: "5.0"
    minor_rev: 6


- name: DISCOVER AND ADD DEVICE A VIRTUAL FORTIGATE
  faz_device:
    adom: "root"
    device_username: "admin"
    device_password: "admin"
    device_ip: "10.10.24.202"
    device_unique_name: "FGT2"
    mgmt_mode: "faz"
    os_type: "fos"
    os_ver: "5.0"
    minor_rev: 6
    state: "present"
    platform_str: "FortiGate-VM64"

- name: DELETE DEVICE FGT01
  faz_device:
    adom: "root"
    device_unique_name: "ansible-fgt01"
    mode: "delete"

- name: DELETE DEVICE FGT02
  faz_device:
    adom: "root"
    device_unique_name: "ansible-fgt02"
    mode: "delete"

- name: PROMOTE FGT01 IN FAZ BY IP
  faz_device:
    adom: "root"
    device_password: "fortinet"
    device_ip: "10.7.220.151"
    device_username: "ansible"
    mgmt_mode: "faz"
    mode: "promote"


- name: PROMOTE FGT02 IN FAZ
  faz_device:
    adom: "root"
    device_password: "fortinet"
    device_unique_name: "ansible-fgt02"
    device_username: "ansible"
    mgmt_mode: "faz"
    mode: "promote"

'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: string
"""

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortianalyzer.fortianalyzer import FortiAnalyzerHandler
from ansible.module_utils.network.fortianalyzer.common import FAZBaseException
from ansible.module_utils.network.fortianalyzer.common import FAZCommon
from ansible.module_utils.network.fortianalyzer.common import FAZMethods
from ansible.module_utils.network.fortianalyzer.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortianalyzer.common import FAIL_SOCKET_MSG


def faz_add_device(faz, paramgram):
    """
    This method is used to add devices to the faz or delete them
    """

    datagram = {
        "adom": paramgram["adom"],
        "device": {"adm_usr": paramgram["device_username"], "adm_pass": paramgram["device_password"],
                   "ip": paramgram["ip"], "name": paramgram["device_unique_name"],
                   "mgmt_mode": paramgram["mgmt_mode"], "os_type": paramgram["os_type"],
                   "mr": paramgram["os_minor_vers"]}
    }

    if paramgram["platform_str"] is not None:
        datagram["device"]["platform_str"] = paramgram["platform_str"]

    if paramgram["sn"] is not None:
        datagram["device"]["sn"] = paramgram["sn"]

    if paramgram["device_action"] is not None:
        datagram["device"]["device_action"] = paramgram["device_action"]

    if paramgram["faz.quota"] is not None:
        datagram["device"]["faz.quota"] = paramgram["faz.quota"]

    url = '/dvm/cmd/add/device/'
    response = faz.process_request(url, datagram, FAZMethods.EXEC)
    return response


def faz_delete_device(faz, paramgram):
    """
    This method deletes a device from the FAZ
    """
    datagram = {
        "adom": paramgram["adom"],
        "device": paramgram["device_unique_name"],
    }

    url = '/dvm/cmd/del/device/'
    response = faz.process_request(url, datagram, FAZMethods.EXEC)
    return response


def faz_get_unknown_devices(faz):
    """
    This method gets devices with an unknown management type field
    """

    faz_filter = ["mgmt_mode", "==", "0"]

    datagram = {
        "filter": faz_filter
    }

    url = "/dvmdb/device"
    response = faz.process_request(url, datagram, FAZMethods.GET)

    return response


def faz_approve_unregistered_device_by_ip(faz, paramgram):
    """
    This method approves unregistered devices by ip.
    """
    # TRY TO FIND DETAILS ON THIS UNREGISTERED DEVICE
    unknown_devices = faz_get_unknown_devices(faz)
    target_device = None
    if unknown_devices[0] == 0:
        for device in unknown_devices[1]:
            if device["ip"] == paramgram["ip"]:
                target_device = device
    else:
        return "No devices are waiting to be registered!"

    # now that we have the target device details...fill out the datagram and make the call to promote it
    if target_device is not None:
        target_device_paramgram = {
            "adom": paramgram["adom"],
            "ip": target_device["ip"],
            "device_username": paramgram["device_username"],
            "device_password": paramgram["device_password"],
            "device_unique_name": paramgram["device_unique_name"],
            "sn": target_device["sn"],
            "os_type": target_device["os_type"],
            "mgmt_mode": paramgram["mgmt_mode"],
            "os_minor_vers": target_device["mr"],
            "os_ver": target_device["os_ver"],
            "platform_str": target_device["platform_str"],
            "faz.quota": target_device["faz.quota"],
            "device_action": paramgram["device_action"]
        }

        add_device = faz_add_device(faz, target_device_paramgram)
        return add_device

    return str("Couldn't find the desired device with ip: " + str(paramgram["device_ip"]))


def faz_approve_unregistered_device_by_name(faz, paramgram):
    # TRY TO FIND DETAILS ON THIS UNREGISTERED DEVICE
    unknown_devices = faz_get_unknown_devices(faz)
    target_device = None
    if unknown_devices[0] == 0:
        for device in unknown_devices[1]:
            if device["name"] == paramgram["device_unique_name"]:
                target_device = device
    else:
        return "No devices are waiting to be registered!"

    # now that we have the target device details...fill out the datagram and make the call to promote it
    if target_device is not None:
        target_device_paramgram = {
            "adom": paramgram["adom"],
            "ip": target_device["ip"],
            "device_username": paramgram["device_username"],
            "device_password": paramgram["device_password"],
            "device_unique_name": paramgram["device_unique_name"],
            "sn": target_device["sn"],
            "os_type": target_device["os_type"],
            "mgmt_mode": paramgram["mgmt_mode"],
            "os_minor_vers": target_device["mr"],
            "os_ver": target_device["os_ver"],
            "platform_str": target_device["platform_str"],
            "faz.quota": target_device["faz.quota"],
            "device_action": paramgram["device_action"]
        }

        add_device = faz_add_device(faz, target_device_paramgram)
        return add_device

    return str("Couldn't find the desired device with name: " + str(paramgram["device_unique_name"]))


def main():
    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        mode=dict(choices=["add", "delete", "promote"], type="str", default="add"),

        device_ip=dict(required=False, type="str"),
        device_username=dict(required=False, type="str"),
        device_password=dict(required=False, type="str", no_log=True),
        device_unique_name=dict(required=False, type="str"),
        device_serial=dict(required=False, type="str"),

        os_type=dict(required=False, type="str"),
        mgmt_mode=dict(required=False, type="str"),
        os_minor_vers=dict(required=False, type="str"),
        os_ver=dict(required=False, type="str"),
        platform_str=dict(required=False, type="str"),
        faz_quota=dict(required=False, type="str")
    )

    required_if = [
        ['mode', 'delete', ['device_unique_name']],
        ['mode', 'add', ['device_serial', 'device_username',
                         'device_password', 'device_unique_name', 'device_ip', 'mgmt_mode', 'platform_str']]

    ]

    module = AnsibleModule(argument_spec, supports_check_mode=True, required_if=required_if, )

    # START SESSION LOGIC
    paramgram = {
        "adom": module.params["adom"],
        "mode": module.params["mode"],
        "ip": module.params["device_ip"],
        "device_username": module.params["device_username"],
        "device_password": module.params["device_password"],
        "device_unique_name": module.params["device_unique_name"],
        "sn": module.params["device_serial"],
        "os_type": module.params["os_type"],
        "mgmt_mode": module.params["mgmt_mode"],
        "os_minor_vers": module.params["os_minor_vers"],
        "os_ver": module.params["os_ver"],
        "platform_str": module.params["platform_str"],
        "faz.quota": module.params["faz_quota"],
        "device_action": None
    }
    # INSERT THE PARAMGRAM INTO THE MODULE SO WHEN WE PASS IT TO MOD_UTILS.FortiManagerHandler IT HAS THAT INFO

    if paramgram["mode"] == "add":
        paramgram["device_action"] = "add_model"
    elif paramgram["mode"] == "promote":
        paramgram["device_action"] = "promote_unreg"
    module.paramgram = paramgram

    # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
    faz = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        faz = FortiAnalyzerHandler(connection, module)
        faz.tools = FAZCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION
    results = DEFAULT_RESULT_OBJ

    try:
        if paramgram["mode"] == "add":
            results = faz_add_device(faz, paramgram)
    except BaseException as err:
        raise FAZBaseException(msg="An error occurred trying to add the device. Error: " + str(err))

    try:
        if paramgram["mode"] == "promote":
            if paramgram["ip"] is not None:
                results = faz_approve_unregistered_device_by_ip(faz, paramgram)
            elif paramgram["device_unique_name"] is not None:
                results = faz_approve_unregistered_device_by_name(faz, paramgram)
    except BaseException as err:
        raise FAZBaseException(msg="An error occurred trying to promote the device. Error: " + str(err))

    try:
        if paramgram["mode"] == "delete":
            results = faz_delete_device(faz, paramgram)
    except BaseException as err:
        raise FAZBaseException(msg="An error occurred trying to delete the device. Error: " + str(err))

    # PROCESS RESULTS
    try:
        faz.govern_response(module=module, results=results,
                            ansible_facts=faz.construct_ansible_facts(results, module.params, paramgram))
    except BaseException as err:
        raise FAZBaseException(msg="An error occurred with govern_response(). Error: " + str(err))

    # This should only be hit if faz.govern_response is missed or failed somehow. In fact. It should never be hit.
    # But it's here JIC.
    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

faz_query

Metadata

Name: faz_query

Description: Provides information on data objects within FortiAnalyzer so that playbooks can perform conditionals.

Author(s): Luke Weighall (@lweighall)

Ansible Version Added/Required: 2.8

Dev Status: No status updates, yet. Contact Authors.

Parameters
adom
  • Description: The ADOM the configuration should belong to.
  • Required: False
  • default: root
custom_dict
  • Description: ADVANCED USERS ONLY! REQUIRES KNOWLEDGE OF FAZ JSON API!

    DICTIONARY JSON FORMAT ONLY – Custom dictionary/datagram to send to the endpoint.

  • Required: False

custom_endpoint
  • Description: ADVANCED USERS ONLY! REQUIRES KNOWLEDGE OF FAZ JSON API!

    The HTTP Endpoint on FortiAnalyzer you wish to GET from.

  • Required: False

device_ip
  • Description: The IP of the device you want to query.
  • Required: False
device_serial
  • Description: The serial number of the device you want to query.
  • Required: False
device_unique_name
  • Description: The desired “friendly” name of the device you want to query.
  • Required: False
nodes
  • Description: A LIST of firewalls in the cluster you want to verify i.e. [“firewall_A”,”firewall_B”].
  • Required: False
object
  • Description: The data object we wish to query (device, package, rule, etc). Will expand choices as improves.
  • Required: True
  • choices: [‘device’, ‘cluster_nodes’, ‘task’, ‘custom’]
task_id
  • Description: The ID of the task you wish to query status on. If left blank and object = ‘task’ a list of tasks are returned.
  • Required: False
Functions
  • faz_get_custom
def faz_get_custom(faz, paramgram):
    """
    :param faz: The faz object instance from fortianalyzer.py
    :type faz: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiAnalyzer
    :rtype: dict
    """
    # IF THE CUSTOM DICTIONARY (OFTEN CONTAINING FILTERS) IS DEFINED CREATED THAT
    if paramgram["custom_dict"] is not None:
        datagram = paramgram["custom_dict"]
    else:
        datagram = dict()

    # SET THE CUSTOM ENDPOINT PROVIDED
    url = paramgram["custom_endpoint"]
    # MAKE THE CALL AND RETURN RESULTS
    response = faz.process_request(url, datagram, FAZMethods.GET)
    return response
  • faz_get_task_status
def faz_get_task_status(faz, paramgram):
    """
    :param faz: The faz object instance from fortianalyzer.py
    :type faz: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiAnalyzer
    :rtype: dict
    """
    # IF THE TASK_ID IS DEFINED, THEN GET THAT SPECIFIC TASK
    # OTHERWISE, GET ALL RECENT TASKS IN A LIST
    if paramgram["task_id"] is not None:

        datagram = {
            "adom": paramgram["adom"]
        }
        url = '/task/task/{task_id}'.format(task_id=paramgram["task_id"])
        response = faz.process_request(url, datagram, FAZMethods.GET)
    else:
        datagram = {
            "adom": paramgram["adom"]
        }
        url = '/task/task'
        response = faz.process_request(url, datagram, FAZMethods.GET)
    return response
  • main
def main():
    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        object=dict(required=True, type="str", choices=["task", "custom"]),
        custom_endpoint=dict(required=False, type="str"),
        custom_dict=dict(required=False, type="dict"),
        task_id=dict(required=False, type="str")
    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    paramgram = {
        "adom": module.params["adom"],
        "object": module.params["object"],
        "task_id": module.params["task_id"],
        "custom_endpoint": module.params["custom_endpoint"],
        "custom_dict": module.params["custom_dict"]
    }
    module.paramgram = paramgram
    faz = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        faz = FortiAnalyzerHandler(connection, module)
        faz.tools = FAZCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    results = DEFAULT_RESULT_OBJ

    try:
        # IF OBJECT IS TASK
        if paramgram["object"] == "task":
            results = faz_get_task_status(faz, paramgram)
            if results[0] != 0:
                module.fail_json(**results[1])
            if results[0] == 0:
                module.exit_json(**results[1])
    except Exception as err:
        raise FAZBaseException(err)

    try:
        # IF OBJECT IS CUSTOM
        if paramgram["object"] == "custom":
            results = faz_get_custom(faz, paramgram)
            if results[0] != 0:
                module.fail_json(msg="QUERY FAILED -- Please check syntax check JSON guide if needed.")
            if results[0] == 0:
                results_len = len(results[1])
                if results_len > 0:
                    results_combine = dict()
                    if isinstance(results[1], dict):
                        results_combine["results"] = results[1]
                    if isinstance(results[1], list):
                        results_combine["results"] = results[1][0:results_len]
                    module.exit_json(msg="Custom Query Success", **results_combine)
                else:
                    module.exit_json(msg="NO RESULTS")
    except Exception as err:
        raise FAZBaseException(err)

    # PROCESS RESULTS
    try:
        faz.govern_response(module=module, results=results,
                            ansible_facts=faz.construct_ansible_facts(results, module.params, paramgram))
    except BaseException as err:
        raise FAZBaseException(msg="An error occurred with govern_response(). Error: " + str(err))

    return module.exit_json(**results[1])
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {
    "metadata_version": "1.1",
    "status": ["preview"],
    "supported_by": "community"
}

DOCUMENTATION = '''
---
module: faz_query
version_added: "2.8"
notes:
    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
author: Luke Weighall (@lweighall)
short_description: Query FortiAnalyzer data objects for use in Ansible workflows.
description:
  - Provides information on data objects within FortiAnalyzer so that playbooks can perform conditionals.

options:
  adom:
    description:
      - The ADOM the configuration should belong to.
    required: false
    default: root

  object:
    description:
      - The data object we wish to query (device, package, rule, etc). Will expand choices as improves.
    required: true
    choices:
    - device
    - cluster_nodes
    - task
    - custom

  custom_endpoint:
    description:
        - ADVANCED USERS ONLY! REQUIRES KNOWLEDGE OF FAZ JSON API!
        - The HTTP Endpoint on FortiAnalyzer you wish to GET from.
    required: false

  custom_dict:
    description:
        - ADVANCED USERS ONLY! REQUIRES KNOWLEDGE OF FAZ JSON API!
        - DICTIONARY JSON FORMAT ONLY -- Custom dictionary/datagram to send to the endpoint.
    required: false

  device_ip:
    description:
      - The IP of the device you want to query.
    required: false

  device_unique_name:
    description:
      - The desired "friendly" name of the device you want to query.
    required: false

  device_serial:
    description:
      - The serial number of the device you want to query.
    required: false

  task_id:
    description:
      - The ID of the task you wish to query status on. If left blank and object = 'task' a list of tasks are returned.
    required: false

  nodes:
    description:
      - A LIST of firewalls in the cluster you want to verify i.e. ["firewall_A","firewall_B"].
    required: false
'''


EXAMPLES = '''
- name: GET STATUS OF TASK ID
  faz_query:
    adom: "ansible"
    object: "task"
    task_id: "3"

- name: USE CUSTOM TYPE TO QUERY AVAILABLE SCRIPTS
  faz_query:
    adom: "ansible"
    object: "custom"
    custom_endpoint: "/dvmdb/adom/ansible/script"
    custom_dict: { "type": "cli" }
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.fortianalyzer.fortianalyzer import FortiAnalyzerHandler
from ansible.module_utils.network.fortianalyzer.common import FAZBaseException
from ansible.module_utils.network.fortianalyzer.common import FAZCommon
from ansible.module_utils.network.fortianalyzer.common import FAZMethods
from ansible.module_utils.network.fortianalyzer.common import DEFAULT_RESULT_OBJ
from ansible.module_utils.network.fortianalyzer.common import FAIL_SOCKET_MSG


def faz_get_custom(faz, paramgram):
    """
    :param faz: The faz object instance from fortianalyzer.py
    :type faz: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiAnalyzer
    :rtype: dict
    """
    # IF THE CUSTOM DICTIONARY (OFTEN CONTAINING FILTERS) IS DEFINED CREATED THAT
    if paramgram["custom_dict"] is not None:
        datagram = paramgram["custom_dict"]
    else:
        datagram = dict()

    # SET THE CUSTOM ENDPOINT PROVIDED
    url = paramgram["custom_endpoint"]
    # MAKE THE CALL AND RETURN RESULTS
    response = faz.process_request(url, datagram, FAZMethods.GET)
    return response


def faz_get_task_status(faz, paramgram):
    """
    :param faz: The faz object instance from fortianalyzer.py
    :type faz: class object
    :param paramgram: The formatted dictionary of options to process
    :type paramgram: dict
    :return: The response from the FortiAnalyzer
    :rtype: dict
    """
    # IF THE TASK_ID IS DEFINED, THEN GET THAT SPECIFIC TASK
    # OTHERWISE, GET ALL RECENT TASKS IN A LIST
    if paramgram["task_id"] is not None:

        datagram = {
            "adom": paramgram["adom"]
        }
        url = '/task/task/{task_id}'.format(task_id=paramgram["task_id"])
        response = faz.process_request(url, datagram, FAZMethods.GET)
    else:
        datagram = {
            "adom": paramgram["adom"]
        }
        url = '/task/task'
        response = faz.process_request(url, datagram, FAZMethods.GET)
    return response


def main():
    argument_spec = dict(
        adom=dict(required=False, type="str", default="root"),
        object=dict(required=True, type="str", choices=["task", "custom"]),
        custom_endpoint=dict(required=False, type="str"),
        custom_dict=dict(required=False, type="dict"),
        task_id=dict(required=False, type="str")
    )

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
    paramgram = {
        "adom": module.params["adom"],
        "object": module.params["object"],
        "task_id": module.params["task_id"],
        "custom_endpoint": module.params["custom_endpoint"],
        "custom_dict": module.params["custom_dict"]
    }
    module.paramgram = paramgram
    faz = None
    if module._socket_path:
        connection = Connection(module._socket_path)
        faz = FortiAnalyzerHandler(connection, module)
        faz.tools = FAZCommon()
    else:
        module.fail_json(**FAIL_SOCKET_MSG)

    results = DEFAULT_RESULT_OBJ

    try:
        # IF OBJECT IS TASK
        if paramgram["object"] == "task":
            results = faz_get_task_status(faz, paramgram)
            if results[0] != 0:
                module.fail_json(**results[1])
            if results[0] == 0:
                module.exit_json(**results[1])
    except Exception as err:
        raise FAZBaseException(err)

    try:
        # IF OBJECT IS CUSTOM
        if paramgram["object"] == "custom":
            results = faz_get_custom(faz, paramgram)
            if results[0] != 0:
                module.fail_json(msg="QUERY FAILED -- Please check syntax check JSON guide if needed.")
            if results[0] == 0:
                results_len = len(results[1])
                if results_len > 0:
                    results_combine = dict()
                    if isinstance(results[1], dict):
                        results_combine["results"] = results[1]
                    if isinstance(results[1], list):
                        results_combine["results"] = results[1][0:results_len]
                    module.exit_json(msg="Custom Query Success", **results_combine)
                else:
                    module.exit_json(msg="NO RESULTS")
    except Exception as err:
        raise FAZBaseException(err)

    # PROCESS RESULTS
    try:
        faz.govern_response(module=module, results=results,
                            ansible_facts=faz.construct_ansible_facts(results, module.params, paramgram))
    except BaseException as err:
        raise FAZBaseException(msg="An error occurred with govern_response(). Error: " + str(err))

    return module.exit_json(**results[1])


if __name__ == "__main__":
    main()

Playbook Examples

faz_device

Playbook Task Examples
- name: DISCOVER AND ADD DEVICE A PHYSICAL FORTIGATE
  faz_device:
    adom: "root"
    device_username: "admin"
    device_password: "admin"
    device_ip: "10.10.24.201"
    device_unique_name: "FGT1"
    device_serial: "FGVM000000117994"
    state: "present"
    mgmt_mode: "faz"
    os_type: "fos"
    os_ver: "5.0"
    minor_rev: 6


- name: DISCOVER AND ADD DEVICE A VIRTUAL FORTIGATE
  faz_device:
    adom: "root"
    device_username: "admin"
    device_password: "admin"
    device_ip: "10.10.24.202"
    device_unique_name: "FGT2"
    mgmt_mode: "faz"
    os_type: "fos"
    os_ver: "5.0"
    minor_rev: 6
    state: "present"
    platform_str: "FortiGate-VM64"

- name: DELETE DEVICE FGT01
  faz_device:
    adom: "root"
    device_unique_name: "ansible-fgt01"
    mode: "delete"

- name: DELETE DEVICE FGT02
  faz_device:
    adom: "root"
    device_unique_name: "ansible-fgt02"
    mode: "delete"

- name: PROMOTE FGT01 IN FAZ BY IP
  faz_device:
    adom: "root"
    device_password: "fortinet"
    device_ip: "10.7.220.151"
    device_username: "ansible"
    mgmt_mode: "faz"
    mode: "promote"


- name: PROMOTE FGT02 IN FAZ
  faz_device:
    adom: "root"
    device_password: "fortinet"
    device_unique_name: "ansible-fgt02"
    device_username: "ansible"
    mgmt_mode: "faz"
    mode: "promote"
Playbook File Examples

%%PB_FILE_EXAMPLE_TOKEN%%

faz_query

Playbook Task Examples
- name: GET STATUS OF TASK ID
  faz_query:
    adom: "ansible"
    object: "task"
    task_id: "3"

- name: USE CUSTOM TYPE TO QUERY AVAILABLE SCRIPTS
  faz_query:
    adom: "ansible"
    object: "custom"
    custom_endpoint: "/dvmdb/adom/ansible/script"
    custom_dict: { "type": "cli" }
Playbook File Examples

%%PB_FILE_EXAMPLE_TOKEN%%

FortiGate (FortiOS) - DEPRECATED

These Ansible “base code” modules have been superseded by the new Ansible Galaxy Collections for FortiOS and FortiManager, and are no longer included in Ansible as of version 2.10.

Redhat has removed all vendor/partner modules from the Ansible Base Code, and moved everyone to Ansible Galaxy Collections.

Active maintenance and development for these “base code” modules has ended, and the new collections are to be used going forward, which is the new active project from Fortinet Engineering.

These Ansible “base code” modules have been superseded by the new Ansible Galaxy Collections for FortiOS and FortiManager, and are no longer included in Ansible as of version 2.10.

Redhat has removed all vendor/partner modules from the Ansible Base Code, and moved everyone to Ansible Galaxy Collections.

Active maintenance and development for these “base code” modules has ended, and the new collections are to be used going forward, which is the new active project from Fortinet Engineering.

Modules

Playbook Examples

FortiSIEM - DEPRECATED

These Ansible “base code” modules have been superseded by the new Ansible Galaxy Collections for FortiOS and FortiManager, and are no longer included in Ansible as of version 2.10.

Redhat has removed all vendor/partner modules from the Ansible Base Code, and moved everyone to Ansible Galaxy Collections.

Active maintenance and development for these “base code” modules has ended, and the new collections are to be used going forward, which is the new active project from Fortinet Engineering.

Getting Started - DEPRECATED

These Ansible “base code” modules have been superseded by the new Ansible Galaxy Collections for FortiOS and FortiManager, and are no longer included in Ansible as of version 2.10.

Redhat has removed all vendor/partner modules from the Ansible Base Code, and moved everyone to Ansible Galaxy Collections.

Active maintenance and development for these “base code” modules has ended, and the new collections are to be used going forward, which is the new active project from Fortinet Engineering.

Introduction

The FortiSIEM Modules are connection: local modules. In other words, they do not use a plugin.

The FortiSIEM API is stateless, so a username and password authentication header must be sent with every request. Thus, a connection plug-in (which expects an API token or Session ID) will never likely be developed for FortiSIEM modules.

As of this writing, Ansible Vault is a valid option for encoding and storing the username/password.

Pre-Requisites

  • Minimum Ansible Version: 2.7+
  • Minimum Python Version: 2.7+
    • Works with Python 3.x
  • Minimum FortiSIEM Version: 5.0+

Installation

Step 1 - Auto Installation Method (Currently Unavailable)

Until we PR these modules and module_utils, this method is unavailable. Please see the manual installation below.

Expect this installation method to be un-available when Ansible 2.9+ is released, or perhaps a maintenance release to 2.8+.

Step 2 (Optional) - Manual Installation Method

Until we get this code past the Pull-Request process with Redhat, it should be released in Ansible 2.9+. Until then…

Step 2a - Base Ansible Install
  • First, make sure Ansible is already installed, and shows version 2.7+.
  • If version isn’t 2.7+, upgrade.
Step 2b - Clone FNDN Git Repo
Step 2c - Install Module Utils
  • The module_utils need to be copied to their correct locations.
  • Find the module utils under fndn_ansible/fortisiem/module_utils/network/fortisiem/, copy them all to: .
/usr/lib/python2.7/dist-packages/ansible/module_utils/network/fortisiem/
  • If you’re unsure where to find this path on your own system, run this command:
find /usr -name "ansible"
  • … and the path under a python dist-packages should present itself. It will be similar to the path above. Create the directory if required.
Step 2d - Install Modules
Step 3 - Inventory File

The FortiSIEM Super should be added to the hosts file under the header [FortiSIEM]. It should also have declarations for username and password. The username must be in org/user format, and the password must be valid, and the account must have admin privileges of some kind in FortiSIEM. We recommend creating a user named “ansible” with the permissions required, and using that account in the hosts fie.

[FortiSIEM]
10.0.0.15

[FortiSIEM_MSP]
10.7.220.61

[fsm_api:children]
FortiSIEM
FortiSIEM_MSP

[fsm_api:vars]
username=super/api_user
password=Fortinet!1
Step 4 - Playbook Test

Ansible should be ready to test now. Copy the following code block into a file named “test_fsm.yml”:

---
- name: CUSTOM QUERIES
  hosts: FortiSIEM
  connection: local
  gather_facts: False

  tasks:
    - name: SIMPLE CUSTOM QUERY TO CMDB
      fsm_custom_query:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "get"
        export_json_to_screen: "enable"
        uri: "/phoenix/rest/config/Domain"

… and then run it with the following command:

ansible-playbook test_fsm.yml -vvvv

If successful, it should report OK with Green Text and show various information about the target FortiSIEM Organizations.

If not successful, double check the hosts file, username/password combo, and that the credentials have appropriate RBAC access in FortiSIEM. The -vvvv verbose mode should indicate where the issue lies.

Using Ansible Vault to Hide Logins

There are many ways to implement Ansible Vault. Feel free to use any method desired. If no previous experience with Ansible Vault exists, we recommend starting with this method:

The procedure is simple:

  • Use ‘ansible-vault encrypt string’ on ansible host to create a vault string.
  • Replace vault string in HOSTS or Variables file, for the username/password or both.
fortisiem:
  ansible_user: "ansible"
  ansible_host: "10.7.220.35"
  ansible_password: !vault |
    $ANSIBLE_VAULT;1.1;AES256
    61366437333436393062623438393663366138633265363930313763383964313130643134383839
    3630663661626365366334646661303338313866373032330a636165373833366166616465373830
    34356466653464313134313664613435356238666139623165623132306538336565376265356633
    6362396137306466630a666562393637353863626436376132643464366661323734363830383164
    6366
  • Add a reference to the variable file/vault file from the playbook itself:
---
- name: Query FSM
  hosts: FortiSIEM
  connection: local
  gather_facts: False
  vars_files:
    - group_vars/vault.yml
  • And then run playbooks with –ask-vault-pass, or setup a password file to provide it.

It is recommended to keep vault secret variables in their own files, so the un-encrypted variables could be read by peers.

Additional Ansible Vault tutorials, references, and alternative implementation methods:

Use Cases

In this guide will be a list of use cases for the Ansible modules provided for FortiSIEM. These are just some examples of what is possible. You are limited only by your imagination, with the power of ansible. If you develop a unique use case, we want to hear about it!

Introduction

The FortiSIEM Engineering Team has maintained an API guide for quite some time now.

The Core CSE DevOps Team have provided Ansible modules for all published API’s in above referenced guide.

The results from their efforts are the following ten modules:

  • fsm_cmdb_devices
  • fsm_credentials
  • fsm_custom_query
  • fsm_device_monitors
  • fsm_discovery
  • fsm_maintenance
  • fsm_organizations
  • fsm_report_query
  • fsm_send_syslog
  • fsm_verify_device_ip

Module Use Cases

fsm_cmdb_devices
  • This module can be used to verify the presence of a device in FortiSIEM CMDB.
  • It can called to get detailed information on a single device, or simple information on many devices.
  • Able to return discovered methods, enabling the audit of credentials on devices.
  • Can be used in Ansible to cross-reference inventory with third-party systems.
  • Allows FortiSIEM inventory to be used in Ansible pipelines.
fsm_credentials
  • This module can be used to add or update credentials.
  • Allows update/add of IP Mappings for credentials.
  • Ad-hoc credential mappings, for commmon credentials, would assist in automatic discovery
  • Pull list of Windows systems from another list accessible to ansible, create mappings for each
  • Do the same ^ for any other type of system
  • When new server detected, if IP isn’t under an existing credential mapping, map it.
fsm_custom_query
  • This module allows the query of any URI endpoint on a FortiSIEM system:
    • XML payloads are supported
    • Allows use of any endpoint
  • Limited by your imagination. All of FortiSIEM is ran on APIs. 90% of them aren’t documented.
  • Allows the integration of almost any FortiSIEM API endpoint, with any supported Ansible device.
fsm_device_monitors
  • Quickly discover which monitors are in place for a FortiSIEM system.
    • Use this information to audit devices, or cross-reference with a list from another system.
  • Used to discover if monitors are in place for a device, or not.
fsm_discovery
  • Allows the ad-hoc discovery of devices.
  • If fsm_cmdb_devices or fsm_custom_query or fsm_report_query or fsm_verify_device doesn’t provide enough proof that a device is discovered, it can be remediated here.
  • Keep FortiSIEM devices in-sync with another system or list accessible to Ansible.
fsm_maintenance
  • Add or Delete FortiSIEM Maintenance Calendar Objects.
  • Allows the synchronization of Maintenance Periods with other systems.
fsm_organizations
  • Allows the addition or updating of any Organization, for a FortiSIEM instance in MSP mode.
  • Create a web-hook into another system via Ansible to automatically create new organizations in FortiSIEM as they are created in other systems.
  • Allows the definition of Collectors
  • Get a list of organizations on a MSP instance of FortiSIEM.
fsm_report_query
  • Allows the query of almost all data contained with FortiSIEM.
  • How to Setup New Report:
    • Step 1 | Create the desired report in FSM GUI
    • Step 2 | Export to XML
    • Step 3 | Copy XML to Ansible Host
    • Step 4 | Run XML report in Ansible to provide any information contained within FortiSIEM.
  • Do not under-estimate the power of this module. A report can be created for almost ANYTHING.
fsm_send_syslog
  • Allows the logging of virtually any source to FortiSIEM via Syslog.
  • Network protocols include UDP, TCP, and TCP over TLS.
  • Usually requires a parser to understand what is being sent.
  • An “ansible-generic” parser could be created to take in all events that happen to Ansible.
  • Used to send events to FortiSIEM that are discovered by Ansible, or to track Ansible data pipelines.
fsm_verify_device_ip
  • Checks by IP address only
  • Returns if an IP address is present in the CMDB, if it has any events within the last 15m, and if any monitors are currently active.
  • Scores devices based on the amount of data in the system for each device.
  • Possible to send device scores to a text file for comparison.
  • Makes identification of devices, “lacking in data”, much more easy.

Modules

fsm_cmdb_devices

Metadata

Name: fsm_cmdb_devices

Description: Gets a short description of each device in the FortiSIEM CMDB and returns the data

Author(s): Luke Weighall (@lweighall)

Ansible Version Added/Required: 2.8

Dev Status: No status updates, yet. Contact Authors.

Parameters
export_json_to_file_path
  • Description: When populated, an attempt to write JSON dictionary to file is made.

    An error will be thrown if this fails.

  • Required: False

  • default: None

export_json_to_screen
  • Description: When enabled this will print the JSON results to screen.
  • Required: False
  • default: enable
  • choices: [‘enable’, ‘disable’]
export_xml_to_file_path
  • Description: When populated, an attempt to write XML to file is made.

    An error will be thrown if this fails.

  • Required: False

  • default: None

host
  • Description: The FortiSIEM’s FQDN or IP Address.
  • Required: True
ignore_ssl_errors
  • Description: When Enabled this will instruct the HTTP Libraries to ignore any ssl validation errors.
  • Required: False
  • default: enable
  • choices: [‘enable’, ‘disable’]
ip
  • Description: Specifies the single IP address of a device to get detailed information from.

    Ignored unless “detailed_single” is set for mode

  • Required: False

ip_range
  • Description: Specifies the IP Range of devices to search for and return.

    Ignored unless “ip_range” is set for mode

  • Required: False

mode
  • Description: Handles how the query is formatted.
  • Required: False
  • default: short_all
  • choices: [‘short_all’, ‘ip_range’, ‘detailed_single’]
password
  • Description: The password associated with the username account.
  • Required: False
username
  • Description: The username used to authenticate with the FortiManager.

    organization/username format. The Organization is important, and will only return data from specified Org.

  • Required: False

Functions
  • main
def main():
    argument_spec = dict(
        host=dict(required=True, type="str"),
        username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"])),
        password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True),
        ignore_ssl_errors=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_screen=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_file_path=dict(required=False, type="str"),
        export_xml_to_file_path=dict(required=False, type="str"),
        export_csv_to_file_path=dict(required=False, type="str"),

        mode=dict(required=False, type="str",
                  choices=["short_all", "ip_range", "detailed_single"], default="short_all"),
        ip_range=dict(required=False, type="str"),
        ip=dict(required=False, type="str")
    )

    required_if = [
        ['mode', 'ip_range', ['ip_range']],
        ['mode', 'detailed_single', ['ip']],
    ]

    module = AnsibleModule(argument_spec, supports_check_mode=False, required_if=required_if)

    paramgram = {
        "host": module.params["host"],
        "username": module.params["username"],
        "password": module.params["password"],
        "export_json_to_screen": module.params["export_json_to_screen"],
        "export_json_to_file_path": module.params["export_json_to_file_path"],
        "export_xml_to_file_path": module.params["export_xml_to_file_path"],
        "export_csv_to_file_path": module.params["export_csv_to_file_path"],
        "ignore_ssl_errors": module.params["ignore_ssl_errors"],

        "mode": module.params["mode"],
        "uri": None
    }

    # DETERMINE THE MODE AND ADD THE CORRECT DATA TO THE PARAMGRAM
    if paramgram["mode"] == "short_all":
        paramgram["uri"] = FSMEndpoints.GET_CMDB_SHORT
    elif paramgram["mode"] == "ip_range":
        paramgram["uri"] = FSMEndpoints.GET_CMDB_IPRANGE + module.params["ip_range"]
    elif paramgram["mode"] == "detailed_single":
        paramgram["uri"] = FSMEndpoints.GET_CMDB_DETAILED_SINGLE + module.params["ip"] + "&loadDepend=true"

    if paramgram["uri"] is None:
        raise FSMBaseException("Base URI couldn't be constructed. Check options.")

    module.paramgram = paramgram

    # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
    fsm = None
    results = DEFAULT_EXIT_MSG
    try:
        fsm = FortiSIEMHandler(module)
    except BaseException as err:
        raise FSMBaseException("Couldn't load FortiSIEM Handler from mod_utils. Error: " + str(err))
    # EXECUTE THE MODULE OPERATION
    try:
        results = fsm.handle_simple_request()
    except BaseException as err:
        raise FSMBaseException(err)
    # EXIT USING GOVERN_RESPONSE()
    fsm.govern_response(module=module, results=results, changed=False,
                        ansible_facts=fsm.construct_ansible_facts(results["json_results"],
                                                                  module.params,
                                                                  paramgram))

    return module.exit_json(msg=results)
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function

__metaclass__ = type

ANSIBLE_METADATA = {
    "metadata_version": "1.1",
    "status": ["preview"],
    "supported_by": "community"
}

DOCUMENTATION = '''
---
module: fsm_cmdb_devices
version_added: "2.8"
author: Luke Weighall (@lweighall)
short_description: Get a list of devices from the FortiSIEM CMDB
description:
  - Gets a short description of each device in the FortiSIEM CMDB and returns the data

options:
  host:
    description:
      - The FortiSIEM's FQDN or IP Address.
    required: true

  username:
    description:
      - The username used to authenticate with the FortiManager.
      - organization/username format. The Organization is important, and will only return data from specified Org.
    required: false

  password:
    description:
      - The password associated with the username account.
    required: false

  ignore_ssl_errors:
    description:
      - When Enabled this will instruct the HTTP Libraries to ignore any ssl validation errors.
    required: false
    default: "enable"
    choices: ["enable", "disable"]

  export_json_to_screen:
    description:
      - When enabled this will print the JSON results to screen.
    required: false
    default: "enable"
    choices: ["enable", "disable"]

  export_json_to_file_path:
    description:
      - When populated, an attempt to write JSON dictionary to file is made.
      - An error will be thrown if this fails.
    required: false
    default: None

  export_xml_to_file_path:
    description:
      - When populated, an attempt to write XML to file is made.
      - An error will be thrown if this fails.
    required: false
    default: None

  mode:
    description:
      - Handles how the query is formatted.
    required: false
    default: "short_all"
    choices: ["short_all", "ip_range", "detailed_single"]

  ip_range:
    description:
      - Specifies the IP Range of devices to search for and return.
      - Ignored unless "ip_range" is set for mode
    required: false

  ip:
    description:
      - Specifies the single IP address of a device to get detailed information from.
      - Ignored unless "detailed_single" is set for mode
    required: false

'''

EXAMPLES = '''
- name: GET SIMPLE DEVICE LIST FROM CMDB
  fsm_cmdb_devices:
    host: "10.0.0.15"
    username: "super/api_user"
    password: "Fortinet!1"
    ignore_ssl_errors: "enable"
    mode: "short_all"

- name: GET SIMPLE DEVICE LIST FROM CMDB IP RANGE
  fsm_cmdb_devices:
    host: "10.0.0.15"
    username: "super/api_user"
    password: "Fortinet!1"
    ignore_ssl_errors: "enable"
    mode: "ip_range"
    ip_range: "10.0.0.100-10.0.0.120"

- name: GET DETAILED INFO ON ONE DEVICE
  fsm_cmdb_devices:
    host: "10.0.0.15"
    username: "super/api_user"
    password: "Fortinet!1"
    ignore_ssl_errors: "enable"
    mode: "detailed_single"
    ip: "10.0.0.5"


'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.network.fortisiem.common import FSMEndpoints
from ansible.module_utils.network.fortisiem.common import FSMBaseException
from ansible.module_utils.network.fortisiem.common import DEFAULT_EXIT_MSG
from ansible.module_utils.network.fortisiem.fortisiem import FortiSIEMHandler


def main():
    argument_spec = dict(
        host=dict(required=True, type="str"),
        username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"])),
        password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True),
        ignore_ssl_errors=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_screen=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_file_path=dict(required=False, type="str"),
        export_xml_to_file_path=dict(required=False, type="str"),
        export_csv_to_file_path=dict(required=False, type="str"),

        mode=dict(required=False, type="str",
                  choices=["short_all", "ip_range", "detailed_single"], default="short_all"),
        ip_range=dict(required=False, type="str"),
        ip=dict(required=False, type="str")
    )

    required_if = [
        ['mode', 'ip_range', ['ip_range']],
        ['mode', 'detailed_single', ['ip']],
    ]

    module = AnsibleModule(argument_spec, supports_check_mode=False, required_if=required_if)

    paramgram = {
        "host": module.params["host"],
        "username": module.params["username"],
        "password": module.params["password"],
        "export_json_to_screen": module.params["export_json_to_screen"],
        "export_json_to_file_path": module.params["export_json_to_file_path"],
        "export_xml_to_file_path": module.params["export_xml_to_file_path"],
        "export_csv_to_file_path": module.params["export_csv_to_file_path"],
        "ignore_ssl_errors": module.params["ignore_ssl_errors"],

        "mode": module.params["mode"],
        "uri": None
    }

    # DETERMINE THE MODE AND ADD THE CORRECT DATA TO THE PARAMGRAM
    if paramgram["mode"] == "short_all":
        paramgram["uri"] = FSMEndpoints.GET_CMDB_SHORT
    elif paramgram["mode"] == "ip_range":
        paramgram["uri"] = FSMEndpoints.GET_CMDB_IPRANGE + module.params["ip_range"]
    elif paramgram["mode"] == "detailed_single":
        paramgram["uri"] = FSMEndpoints.GET_CMDB_DETAILED_SINGLE + module.params["ip"] + "&loadDepend=true"

    if paramgram["uri"] is None:
        raise FSMBaseException("Base URI couldn't be constructed. Check options.")

    module.paramgram = paramgram

    # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
    fsm = None
    results = DEFAULT_EXIT_MSG
    try:
        fsm = FortiSIEMHandler(module)
    except BaseException as err:
        raise FSMBaseException("Couldn't load FortiSIEM Handler from mod_utils. Error: " + str(err))
    # EXECUTE THE MODULE OPERATION
    try:
        results = fsm.handle_simple_request()
    except BaseException as err:
        raise FSMBaseException(err)
    # EXIT USING GOVERN_RESPONSE()
    fsm.govern_response(module=module, results=results, changed=False,
                        ansible_facts=fsm.construct_ansible_facts(results["json_results"],
                                                                  module.params,
                                                                  paramgram))

    return module.exit_json(msg=results)


if __name__ == "__main__":
    main()

fsm_credentials

Metadata

Name: fsm_credentials

Description: Adds or Updates Credentials in FortiSIEM.

Author(s): Luke Weighall (@lweighall)

Ansible Version Added/Required: 2.8

Dev Status: No status updates, yet. Contact Authors.

Parameters
access_id
  • Description: The Access_ID of the credential you want to map.

    Only used when mode is “map”

  • Required: False

access_protocol
  • Description: Defines the access protocol in use. Also plays a large role in included/excluded parameters.
  • Required: True
  • choices: [‘ftp’, ‘ftp_over_ssl’, ‘imap’, ‘imap_over_ssl’, ‘jdbc’, ‘jmx’, ‘pop3’, ‘pop3_over_ssl’, ‘smtp’, ‘smtp_over_ssl’, ‘smtp_over_tls’, ‘ssh’, ‘telnet’, ‘vm_sdk’]
cred_password
  • Description: Specifies the password for the credential.
  • Required: False
cred_username
  • Description: Specifies the username for the credential.
  • Required: False
description
  • Description: Specifies the description for the credential
  • Required: False
export_json_to_file_path
  • Description: When populated, an attempt to write JSON dictionary to file is made.

    An error will be thrown if this fails.

  • Required: False

  • default: None

export_json_to_screen
  • Description: When enabled this will print the JSON results to screen.
  • Required: False
  • default: enable
  • choices: [‘enable’, ‘disable’]
export_xml_to_file_path
  • Description: When populated, an attempt to write XML to file is made.

    An error will be thrown if this fails.

  • Required: False

  • default: None

friendly_name
  • Description: Specifies the friendly name specified for the credential.

    Required when mode equals get.

  • Required: False

host
  • Description: The FortiSIEM’s FQDN or IP Address.
  • Required: True
ignore_ssl_errors
  • Description: When Enabled this will instruct the HTTP Libraries to ignore any ssl validation errors.
  • Required: False
  • default: enable
  • choices: [‘enable’, ‘disable’]
input_xml_file
  • Description: If defined, all other options are ignored. The XML in the file path specified is strictly used.
  • Required: False
ip_range
  • Description: The IP range(s) you want to map x.x.x.x or x.x.x.x-x.x.x.x, comma seperated.

    Used in “add” and “map” modes

  • Required: False

mode
  • Description: Defines the HTTP method used in the playbook.

    When updating friendly_name is the primary key.

  • Required: False

  • default: add

  • choices: [‘add’, ‘update’, ‘get’]

password
  • Description: The password associated with the username account.
  • Required: False
port
  • Description: Specifies port number.
  • Required: False
pull_interval
  • Description: Specifies the pull interval for any monitors created as a result of this credential..
  • Required: False
  • default: 5
super_password
  • Description: Specifies the super or config password for the credential. Only required for devices that require elevation.
  • Required: False
username
  • Description: The username used to authenticate with the FortiManager.

    organization/username format. The Organization is important, and will only return data from specified Org.

  • Required: False

Functions
  • main
def main():
    argument_spec = dict(
        host=dict(required=True, type="str"),
        username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"])),
        password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True),
        ignore_ssl_errors=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_screen=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_file_path=dict(required=False, type="str"),
        export_xml_to_file_path=dict(required=False, type="str"),
        export_csv_to_file_path=dict(required=False, type="str"),

        mode=dict(required=False, type="str",
                  choices=["add", "update", "get"], default="get"),
        ip_range=dict(required=False, type="str"),
        access_id=dict(required=False, type="str"),
        input_xml_file=dict(required=False, type="str"),
        access_protocol=dict(required=False, type="str", choices=['ftp', 'ftp_over_ssl',
                                                                  'imap', 'imap_over_ssl', 'jdbc', 'jmx', 'kafka_api',
                                                                  'pop3', 'pop3_over_ssl', 'smtp', 'smtp_over_ssl',
                                                                  'smtp_over_tls', 'ssh', 'telnet', 'vm_sdk']),
        friendly_name=dict(required=False, type="str"),
        description=dict(required=False, type="str"),
        pull_interval=dict(required=False, type="str", default="5"),
        cred_username=dict(required=False, type="str"),
        cred_password=dict(required=False, type="str", no_log=True),
        super_password=dict(required=False, type="str", no_log=True),
        port=dict(required=False, type="str"),
    )

    module = AnsibleModule(argument_spec, supports_check_mode=False, )

    paramgram = {
        "host": module.params["host"],
        "username": module.params["username"],
        "password": module.params["password"],
        "export_json_to_screen": module.params["export_json_to_screen"],
        "export_json_to_file_path": module.params["export_json_to_file_path"],
        "export_xml_to_file_path": module.params["export_xml_to_file_path"],
        "export_csv_to_file_path": module.params["export_csv_to_file_path"],
        "ignore_ssl_errors": module.params["ignore_ssl_errors"],

        "mode": module.params["mode"],
        "uri": None,
        "input_xml": None,
        "ip_range": module.params["ip_range"],
        "access_id": module.params["access_id"],
        "password_type": "Manual",
        "input_xml_file": module.params["input_xml_file"],
        "access_protocol": module.params["access_protocol"],
        "friendly_name": module.params["friendly_name"],
        "description": module.params["description"],
        "pull_interval": module.params["pull_interval"],
        "cred_username": module.params["cred_username"],
        "cred_password": module.params["cred_password"],
        "super_password": module.params["super_password"],
        "port": module.params["port"],
    }

    # DETERMINE THE MODE AND ADD THE CORRECT DATA TO THE PARAMGRAM
    if paramgram["mode"] in ["add", "update"]:
        paramgram["uri"] = FSMEndpoints.SET_CREDS
    elif paramgram["mode"] == "get":
        paramgram["uri"] = FSMEndpoints.GET_CREDS

    if paramgram["uri"] is None:
        raise FSMBaseException("Base URI couldn't be constructed. Check options.")

    if not paramgram["port"]:
        if paramgram["access_protocol"] == "ftp":
            paramgram["port"] = "21"
        if paramgram["access_protocol"] == "ftp_over_ssl":
            paramgram["port"] = "990"
        if paramgram["access_protocol"] == "imap":
            paramgram["port"] = "143"
        if paramgram["access_protocol"] == "imap_over_ssl":
            paramgram["port"] = "993"
        if paramgram["access_protocol"] == "jdbc":
            paramgram["port"] = "1433"
        if paramgram["access_protocol"] == "jmx":
            paramgram["port"] = "0"
        if paramgram["access_protocol"] == "pop3":
            paramgram["port"] = "110"
        if paramgram["access_protocol"] == "pop3_over_ssl":
            paramgram["port"] = "995"
        if paramgram["access_protocol"] == "smtp":
            paramgram["port"] = "25"
        if paramgram["access_protocol"] == "smtp_over_ssl":
            paramgram["port"] = "465"
        if paramgram["access_protocol"] == "smtp_over_tls":
            paramgram["port"] = "465"
        if paramgram["access_protocol"] == "ssh":
            paramgram["port"] = "22"
        if paramgram["access_protocol"] == "telnet":
            paramgram["port"] = "23"
        if paramgram["access_protocol"] == "vm_sdk":
            paramgram["port"] = None

    module.paramgram = paramgram

    # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
    fsm = None
    results = DEFAULT_EXIT_MSG
    try:
        fsm = FortiSIEMHandler(module)
    except BaseException as err:
        raise FSMBaseException("Couldn't load FortiSIEM Handler from mod_utils. Error: " + str(err))

    # EXECUTE THE MODULE OPERATION
    if paramgram["mode"] in ["add", "update"]:
        if paramgram["input_xml_file"]:
            paramgram["input_xml"] = fsm.get_file_contents(paramgram["input_xml_file"])
            try:
                results = fsm.handle_simple_payload_request(paramgram["input_xml"])
            except BaseException as err:
                raise FSMBaseException(err)
        else:
            paramgram["input_xml"] = fsm._xml.create_credential_payload()

            try:
                results = fsm.handle_simple_payload_request(paramgram["input_xml"])
            except BaseException as err:
                raise FSMBaseException(err)
    elif paramgram["mode"] == "get":
        try:
            results = fsm.handle_simple_request()
        except BaseException as err:
            raise FSMBaseException(err)

    # EXIT USING GOVERN_RESPONSE()
    fsm.govern_response(module=module, results=results, changed=False,
                        ansible_facts=fsm.construct_ansible_facts(results["json_results"],
                                                                  module.params,
                                                                  paramgram))

    return module.exit_json(msg=results)
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function

__metaclass__ = type

ANSIBLE_METADATA = {
    "metadata_version": "1.1",
    "status": ["preview"],
    "supported_by": "community"
}

DOCUMENTATION = '''
---
module: fsm_credentials
version_added: "2.8"
author: Luke Weighall (@lweighall)
short_description: Adds or Updates Credentials in FortiSIEM.
description:
  - Adds or Updates Credentials in FortiSIEM.

options:
  host:
    description:
      - The FortiSIEM's FQDN or IP Address.
    required: true

  username:
    description:
      - The username used to authenticate with the FortiManager.
      - organization/username format. The Organization is important, and will only return data from specified Org.
    required: false

  password:
    description:
      - The password associated with the username account.
    required: false

  ignore_ssl_errors:
    description:
      - When Enabled this will instruct the HTTP Libraries to ignore any ssl validation errors.
    required: false
    default: "enable"
    choices: ["enable", "disable"]

  export_json_to_screen:
    description:
      - When enabled this will print the JSON results to screen.
    required: false
    default: "enable"
    choices: ["enable", "disable"]

  export_json_to_file_path:
    description:
      - When populated, an attempt to write JSON dictionary to file is made.
      - An error will be thrown if this fails.
    required: false
    default: None

  export_xml_to_file_path:
    description:
      - When populated, an attempt to write XML to file is made.
      - An error will be thrown if this fails.
    required: false
    default: None

  mode:
    description:
      - Defines the HTTP method used in the playbook.
      - When updating friendly_name is the primary key.
    required: false
    default: "add"
    choices: ["add", "update", "get"]

  input_xml_file:
    description:
      - If defined, all other options are ignored. The XML in the file path specified is strictly used.
    required: false

  access_protocol:
    description:
      - Defines the access protocol in use. Also plays a large role in included/excluded parameters.
    required: true
    choices:
      - ftp
      - ftp_over_ssl
      - imap
      - imap_over_ssl
      - jdbc
      - jmx
      - pop3
      - pop3_over_ssl
      - smtp
      - smtp_over_ssl
      - smtp_over_tls
      - ssh
      - telnet
      - vm_sdk

  ip_range:
    description:
      - The IP range(s) you want to map x.x.x.x or x.x.x.x-x.x.x.x, comma seperated.
      - Used in "add" and "map" modes
    required: false

  access_id:
    description:
      - The Access_ID of the credential you want to map.
      - Only used when mode is "map"
    required: false

  friendly_name:
    description:
      - Specifies the friendly name specified for the credential.
      - Required when mode equals get.
    required: false

  description:
    description:
      - Specifies the description for the credential
    required: false

  pull_interval:
    description:
      - Specifies the pull interval for any monitors created as a result of this credential..
    required: false
    default: 5

  cred_username:
    description:
      - Specifies the username for the credential.
    required: false

  cred_password:
    description:
      - Specifies the password for the credential.
    required: false

  super_password:
    description:
      - Specifies the super or config password for the credential. Only required for devices that require elevation.
    required: false

  port:
    description:
      - Specifies port number.
    required: false

'''

EXAMPLES = '''
- name: ADD AN SSH CREDENTIAL
  fsm_credentials:
    host: "10.0.0.15"
    username: "super/api_user"
    password: "Fortinet!1"
    ignore_ssl_errors: "enable"
    cred_username: "fortinet"
    cred_password: "fortinet123!"
    access_protocol: "ssh"
    friendly_name: "AnsibleTestSSHCred"
    mode: "add"

- name: ADD AN SSH CREDENTIAL FOR ELEVATED DEVICE
  fsm_credentials:
    host: "10.0.0.15"
    username: "super/api_user"
    password: "Fortinet!1"
    ignore_ssl_errors: "enable"
    cred_username: "fortinet"
    cred_password: "fortinet123!"
    super_username: "fortinet_super"
    super_password: "fortinet321!"
    access_protocol: "ssh"
    friendly_name: "AnsibleTestCiscoCred"
    mode: "add"
    ip_range: "10.0.254.1-10.0.254.255"

- name: ADD AN VM_SDK CREDENTIAL
  fsm_credentials:
    host: "10.0.0.15"
    username: "super/api_user"
    password: "Fortinet!1"
    ignore_ssl_errors: "enable"
    cred_username: "fortinet"
    cred_password: "fortinet123!"
    access_protocol: "vm_sdk"
    friendly_name: "AnsibleTestVMSDKCred"
    mode: "add"

- name: MSP UPDATE AN SSH CREDENTIAL
  fsm_credentials:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    cred_username: "fortinet"
    cred_password: "fortinet123!123"
    access_protocol: "ssh"
    description: "AnsibleTestSSHCredUPDATE"
    mode: "update"
    friendly_name: "AnsibleTestSSHCred"
    ip_range: "10.7.220.100"

'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.network.fortisiem.common import FSMEndpoints
from ansible.module_utils.network.fortisiem.common import FSMBaseException
from ansible.module_utils.network.fortisiem.common import DEFAULT_EXIT_MSG
from ansible.module_utils.network.fortisiem.fortisiem import FortiSIEMHandler


def main():
    argument_spec = dict(
        host=dict(required=True, type="str"),
        username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"])),
        password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True),
        ignore_ssl_errors=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_screen=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_file_path=dict(required=False, type="str"),
        export_xml_to_file_path=dict(required=False, type="str"),
        export_csv_to_file_path=dict(required=False, type="str"),

        mode=dict(required=False, type="str",
                  choices=["add", "update", "get"], default="get"),
        ip_range=dict(required=False, type="str"),
        access_id=dict(required=False, type="str"),
        input_xml_file=dict(required=False, type="str"),
        access_protocol=dict(required=False, type="str", choices=['ftp', 'ftp_over_ssl',
                                                                  'imap', 'imap_over_ssl', 'jdbc', 'jmx', 'kafka_api',
                                                                  'pop3', 'pop3_over_ssl', 'smtp', 'smtp_over_ssl',
                                                                  'smtp_over_tls', 'ssh', 'telnet', 'vm_sdk']),
        friendly_name=dict(required=False, type="str"),
        description=dict(required=False, type="str"),
        pull_interval=dict(required=False, type="str", default="5"),
        cred_username=dict(required=False, type="str"),
        cred_password=dict(required=False, type="str", no_log=True),
        super_password=dict(required=False, type="str", no_log=True),
        port=dict(required=False, type="str"),
    )

    module = AnsibleModule(argument_spec, supports_check_mode=False, )

    paramgram = {
        "host": module.params["host"],
        "username": module.params["username"],
        "password": module.params["password"],
        "export_json_to_screen": module.params["export_json_to_screen"],
        "export_json_to_file_path": module.params["export_json_to_file_path"],
        "export_xml_to_file_path": module.params["export_xml_to_file_path"],
        "export_csv_to_file_path": module.params["export_csv_to_file_path"],
        "ignore_ssl_errors": module.params["ignore_ssl_errors"],

        "mode": module.params["mode"],
        "uri": None,
        "input_xml": None,
        "ip_range": module.params["ip_range"],
        "access_id": module.params["access_id"],
        "password_type": "Manual",
        "input_xml_file": module.params["input_xml_file"],
        "access_protocol": module.params["access_protocol"],
        "friendly_name": module.params["friendly_name"],
        "description": module.params["description"],
        "pull_interval": module.params["pull_interval"],
        "cred_username": module.params["cred_username"],
        "cred_password": module.params["cred_password"],
        "super_password": module.params["super_password"],
        "port": module.params["port"],
    }

    # DETERMINE THE MODE AND ADD THE CORRECT DATA TO THE PARAMGRAM
    if paramgram["mode"] in ["add", "update"]:
        paramgram["uri"] = FSMEndpoints.SET_CREDS
    elif paramgram["mode"] == "get":
        paramgram["uri"] = FSMEndpoints.GET_CREDS

    if paramgram["uri"] is None:
        raise FSMBaseException("Base URI couldn't be constructed. Check options.")

    if not paramgram["port"]:
        if paramgram["access_protocol"] == "ftp":
            paramgram["port"] = "21"
        if paramgram["access_protocol"] == "ftp_over_ssl":
            paramgram["port"] = "990"
        if paramgram["access_protocol"] == "imap":
            paramgram["port"] = "143"
        if paramgram["access_protocol"] == "imap_over_ssl":
            paramgram["port"] = "993"
        if paramgram["access_protocol"] == "jdbc":
            paramgram["port"] = "1433"
        if paramgram["access_protocol"] == "jmx":
            paramgram["port"] = "0"
        if paramgram["access_protocol"] == "pop3":
            paramgram["port"] = "110"
        if paramgram["access_protocol"] == "pop3_over_ssl":
            paramgram["port"] = "995"
        if paramgram["access_protocol"] == "smtp":
            paramgram["port"] = "25"
        if paramgram["access_protocol"] == "smtp_over_ssl":
            paramgram["port"] = "465"
        if paramgram["access_protocol"] == "smtp_over_tls":
            paramgram["port"] = "465"
        if paramgram["access_protocol"] == "ssh":
            paramgram["port"] = "22"
        if paramgram["access_protocol"] == "telnet":
            paramgram["port"] = "23"
        if paramgram["access_protocol"] == "vm_sdk":
            paramgram["port"] = None

    module.paramgram = paramgram

    # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
    fsm = None
    results = DEFAULT_EXIT_MSG
    try:
        fsm = FortiSIEMHandler(module)
    except BaseException as err:
        raise FSMBaseException("Couldn't load FortiSIEM Handler from mod_utils. Error: " + str(err))

    # EXECUTE THE MODULE OPERATION
    if paramgram["mode"] in ["add", "update"]:
        if paramgram["input_xml_file"]:
            paramgram["input_xml"] = fsm.get_file_contents(paramgram["input_xml_file"])
            try:
                results = fsm.handle_simple_payload_request(paramgram["input_xml"])
            except BaseException as err:
                raise FSMBaseException(err)
        else:
            paramgram["input_xml"] = fsm._xml.create_credential_payload()

            try:
                results = fsm.handle_simple_payload_request(paramgram["input_xml"])
            except BaseException as err:
                raise FSMBaseException(err)
    elif paramgram["mode"] == "get":
        try:
            results = fsm.handle_simple_request()
        except BaseException as err:
            raise FSMBaseException(err)

    # EXIT USING GOVERN_RESPONSE()
    fsm.govern_response(module=module, results=results, changed=False,
                        ansible_facts=fsm.construct_ansible_facts(results["json_results"],
                                                                  module.params,
                                                                  paramgram))

    return module.exit_json(msg=results)


if __name__ == "__main__":
    main()

fsm_custom_query

Metadata

Name: fsm_custom_query

Description: Gets a short description of each device in the FortiSIEM CMDB and returns the data

Author(s): Luke Weighall (@lweighall)

Ansible Version Added/Required: 2.8

Dev Status: No status updates, yet. Contact Authors.

Parameters
export_json_to_file_path
  • Description: When populated, an attempt to write JSON dictionary to file is made.

    An error will be thrown if this fails.

  • Required: False

  • default: None

export_json_to_screen
  • Description: When enabled this will print the JSON results to screen.
  • Required: False
  • default: enable
  • choices: [‘enable’, ‘disable’]
export_xml_to_file_path
  • Description: When populated, an attempt to write XML to file is made.

    An error will be thrown if this fails.

  • Required: False

  • default: None

host
  • Description: The FortiSIEM’s FQDN or IP Address.
  • Required: True
ignore_ssl_errors
  • Description: When Enabled this will instruct the HTTP Libraries to ignore any ssl validation errors.
  • Required: False
  • default: enable
  • choices: [‘enable’, ‘disable’]
mode
  • Description: Handles how the query is formatted.
  • Required: False
  • default: get
  • choices: [‘get’, ‘set’, ‘update’, ‘delete’, ‘add’]
password
  • Description: The password associated with the username account.
  • Required: False
payload_file
  • Description: Specifies the file path to a custom XML payload file.
  • Required: False
uri
  • Description: Custom URI to query.
  • Required: False
username
  • Description: The username used to authenticate with the FortiManager.

    organization/username format. The Organization is important, and will only return data from specified Org.

  • Required: False

Functions
  • main
def main():
    argument_spec = dict(
        host=dict(required=True, type="str"),
        username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"])),
        password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True),
        ignore_ssl_errors=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_screen=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_file_path=dict(required=False, type="str"),
        export_xml_to_file_path=dict(required=False, type="str"),
        export_csv_to_file_path=dict(required=False, type="str"),

        mode=dict(required=False, type="str",
                  choices=["get", "set", "update", "delete", "add"], default="get"),
        uri=dict(required=True, type="str"),
        payload_file=dict(required=False, type="str", default=None)
    )

    module = AnsibleModule(argument_spec, supports_check_mode=False, )

    paramgram = {
        "host": module.params["host"],
        "username": module.params["username"],
        "password": module.params["password"],
        "export_json_to_screen": module.params["export_json_to_screen"],
        "export_json_to_file_path": module.params["export_json_to_file_path"],
        "export_xml_to_file_path": module.params["export_xml_to_file_path"],
        "export_csv_to_file_path": module.params["export_csv_to_file_path"],
        "ignore_ssl_errors": module.params["ignore_ssl_errors"],

        "mode": module.params["mode"],
        "uri": module.params["uri"],
        "payload_file": module.params["payload_file"],
        "input_xml": None

    }

    module.paramgram = paramgram

    # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
    fsm = None
    results = DEFAULT_EXIT_MSG
    try:
        fsm = FortiSIEMHandler(module)
    except BaseException as err:
        raise FSMBaseException("Couldn't load FortiSIEM Handler from mod_utils. Error: " + str(err))

    if paramgram["payload_file"]:
        paramgram["input_xml"] = fsm.get_file_contents(paramgram["payload_file"])
        try:
            results = fsm.handle_simple_payload_request(paramgram["input_xml"])
        except BaseException as err:
            raise FSMBaseException(err)
    else:
        try:
            results = fsm.handle_simple_request()
        except BaseException as err:
            raise FSMBaseException(err)

    # EXIT USING GOVERN_RESPONSE()
    fsm.govern_response(module=module, results=results, changed=False,
                        ansible_facts=fsm.construct_ansible_facts(results["json_results"],
                                                                  module.params,
                                                                  paramgram))

    return module.exit_json(msg=results)
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function

__metaclass__ = type

ANSIBLE_METADATA = {
    "metadata_version": "1.1",
    "status": ["preview"],
    "supported_by": "community"
}

DOCUMENTATION = '''
---
module: fsm_custom_query
version_added: "2.8"
author: Luke Weighall (@lweighall)
short_description: Get a list of devices from the FortiSIEM CMDB
description:
  - Gets a short description of each device in the FortiSIEM CMDB and returns the data

options:
  host:
    description:
      - The FortiSIEM's FQDN or IP Address.
    required: true

  username:
    description:
      - The username used to authenticate with the FortiManager.
      - organization/username format. The Organization is important, and will only return data from specified Org.
    required: false

  password:
    description:
      - The password associated with the username account.
    required: false

  ignore_ssl_errors:
    description:
      - When Enabled this will instruct the HTTP Libraries to ignore any ssl validation errors.
    required: false
    default: "enable"
    choices: ["enable", "disable"]

  export_json_to_screen:
    description:
      - When enabled this will print the JSON results to screen.
    required: false
    default: "enable"
    choices: ["enable", "disable"]

  export_json_to_file_path:
    description:
      - When populated, an attempt to write JSON dictionary to file is made.
      - An error will be thrown if this fails.
    required: false
    default: None

  export_xml_to_file_path:
    description:
      - When populated, an attempt to write XML to file is made.
      - An error will be thrown if this fails.
    required: false
    default: None

  mode:
    description:
      - Handles how the query is formatted.
    required: false
    default: "get"
    choices: ["get", "set", "update", "delete", "add"]

  uri:
    description:
      - Custom URI to query.
    required: false

  payload_file:
    description:
      - Specifies the file path to a custom XML payload file.
    required: false

'''

EXAMPLES = '''
- name: SIMPLE CUSTOM QUERY FOR ORGANIZATIONS
  fsm_custom_query:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "get"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/custom_query1.json"
    export_xml_to_file_path: "/root/custom_query1.xml"
    uri: "/phoenix/rest/config/Domain"
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.network.fortisiem.common import FSMBaseException
from ansible.module_utils.network.fortisiem.common import DEFAULT_EXIT_MSG
from ansible.module_utils.network.fortisiem.fortisiem import FortiSIEMHandler


def main():
    argument_spec = dict(
        host=dict(required=True, type="str"),
        username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"])),
        password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True),
        ignore_ssl_errors=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_screen=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_file_path=dict(required=False, type="str"),
        export_xml_to_file_path=dict(required=False, type="str"),
        export_csv_to_file_path=dict(required=False, type="str"),

        mode=dict(required=False, type="str",
                  choices=["get", "set", "update", "delete", "add"], default="get"),
        uri=dict(required=True, type="str"),
        payload_file=dict(required=False, type="str", default=None)
    )

    module = AnsibleModule(argument_spec, supports_check_mode=False, )

    paramgram = {
        "host": module.params["host"],
        "username": module.params["username"],
        "password": module.params["password"],
        "export_json_to_screen": module.params["export_json_to_screen"],
        "export_json_to_file_path": module.params["export_json_to_file_path"],
        "export_xml_to_file_path": module.params["export_xml_to_file_path"],
        "export_csv_to_file_path": module.params["export_csv_to_file_path"],
        "ignore_ssl_errors": module.params["ignore_ssl_errors"],

        "mode": module.params["mode"],
        "uri": module.params["uri"],
        "payload_file": module.params["payload_file"],
        "input_xml": None

    }

    module.paramgram = paramgram

    # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
    fsm = None
    results = DEFAULT_EXIT_MSG
    try:
        fsm = FortiSIEMHandler(module)
    except BaseException as err:
        raise FSMBaseException("Couldn't load FortiSIEM Handler from mod_utils. Error: " + str(err))

    if paramgram["payload_file"]:
        paramgram["input_xml"] = fsm.get_file_contents(paramgram["payload_file"])
        try:
            results = fsm.handle_simple_payload_request(paramgram["input_xml"])
        except BaseException as err:
            raise FSMBaseException(err)
    else:
        try:
            results = fsm.handle_simple_request()
        except BaseException as err:
            raise FSMBaseException(err)

    # EXIT USING GOVERN_RESPONSE()
    fsm.govern_response(module=module, results=results, changed=False,
                        ansible_facts=fsm.construct_ansible_facts(results["json_results"],
                                                                  module.params,
                                                                  paramgram))

    return module.exit_json(msg=results)


if __name__ == "__main__":
    main()

fsm_device_monitors

Metadata

Name: fsm_device_monitors

Description: Gets a short description of each devices monitors status in FortiSIEM. Results are returned via dictionary json with the key “summary”

Author(s): Luke Weighall (@lweighall)

Ansible Version Added/Required: 2.8

Dev Status: No status updates, yet. Contact Authors.

Parameters
export_json_to_file_path
  • Description: When populated, an attempt to write JSON dictionary to file is made.

    An error will be thrown if this fails.

  • Required: False

  • default: None

export_json_to_screen
  • Description: When enabled this will print the JSON results to screen.
  • Required: False
  • default: enable
  • choices: [‘enable’, ‘disable’]
export_xml_to_file_path
  • Description: When populated, an attempt to write XML to file is made.

    An error will be thrown if this fails.

  • Required: False

  • default: None

host
  • Description: The FortiSIEM’s FQDN or IP Address.
  • Required: True
ignore_ssl_errors
  • Description: When Enabled this will instruct the HTTP Libraries to ignore any ssl validation errors.
  • Required: False
  • default: enable
  • choices: [‘enable’, ‘disable’]
ip
  • Description: Specifies the single IP address of a device to get detailed information from.

    Ignored unless “detailed_single” is set for mode

  • Required: False

ip_range
  • Description: Specifies the IP Range of devices to search for and return.

    Ignored unless “ip_range” is set for mode

  • Required: False

mode
  • Description: Handles how the query is formatted upon return.

    When in update mode, update_xml_file is required.

  • Required: False

  • default: short_all

  • choices: [‘short_all’, ‘ip_range’, ‘detailed_single’, ‘update’]

password
  • Description: The password associated with the username account.
  • Required: False
update_xml_file
  • Description: Specifies the XML file path that contains the pre-formatted XML to update the monitor with.
  • Required: False
username
  • Description: The username used to authenticate with the FortiManager.

    organization/username format. The Organization is important, and will only return data from specified Org.

  • Required: False

Functions
  • main
def main():
    argument_spec = dict(
        host=dict(required=True, type="str"),
        username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"])),
        password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True),
        ignore_ssl_errors=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_screen=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_file_path=dict(required=False, type="str"),
        export_xml_to_file_path=dict(required=False, type="str"),
        export_csv_to_file_path=dict(required=False, type="str"),

        mode=dict(required=False, type="str",
                  choices=["short_all", "ip_range", "detailed_single", "update"], default="short_all"),
        ip_range=dict(required=False, type="str"),
        ip=dict(required=False, type="str"),
        update_xml_file=dict(required=False, type="str")
    )

    required_if = [
        ['mode', 'ip_range', ['ip_range']],
        ['mode', 'detailed_single', ['ip']],
        ['mode', 'update', ['update_xml_file']],
    ]

    module = AnsibleModule(argument_spec, supports_check_mode=False, required_if=required_if)

    paramgram = {
        "host": module.params["host"],
        "username": module.params["username"],
        "password": module.params["password"],
        "export_json_to_screen": module.params["export_json_to_screen"],
        "export_json_to_file_path": module.params["export_json_to_file_path"],
        "export_xml_to_file_path": module.params["export_xml_to_file_path"],
        "export_csv_to_file_path": module.params["export_csv_to_file_path"],
        "ignore_ssl_errors": module.params["ignore_ssl_errors"],
        "ip_range": module.params["ip_range"],
        "ip": module.params["ip"],
        "update_xml_file": module.params["update_xml_file"],
        "mode": module.params["mode"],
        "uri": None
    }

    # DETERMINE THE MODE AND ADD THE CORRECT DATA TO THE PARAMGRAM
    if paramgram["mode"] in ["short_all", "ip_range", "detailed_single"]:
        paramgram["uri"] = FSMEndpoints.GET_MONITORED_DEVICES
    elif paramgram["mode"] == "update":
        paramgram["uri"] = FSMEndpoints.UPDATE_DEVICE_MONITORING

    if paramgram["uri"] is None:
        raise FSMBaseException("Base URI couldn't be constructed. Check options.")

    module.paramgram = paramgram

    # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
    fsm = None
    results = DEFAULT_EXIT_MSG
    try:
        fsm = FortiSIEMHandler(module)
    except BaseException as err:
        raise FSMBaseException("Couldn't load FortiSIEM Handler from mod_utils. Error: " + str(err))

    # RUN IF MODE = SHORT ALL
    if paramgram["mode"] == "short_all":
        try:
            results = fsm.handle_simple_request()
        except BaseException as err:
            raise FSMBaseException(err)
        # ADD A SUMMARY TO THE RESULTS
        try:
            results = fsm._tools.get_monitors_summary_for_short_all(results)
        except BaseException as err:
            raise FSMBaseException(err)

    # RUN IF MODE = IP RANGE
    if paramgram["mode"] == "ip_range":
        try:
            results = fsm.handle_simple_request()
        except BaseException as err:
            raise FSMBaseException(err)
        # FOR EACH IP ADDRESS IN RANGE, RUN THE METHOD get_monitors_info_for_specific_ip

        try:
            ipr = str(paramgram["ip_range"]).split("-")
            ipr_list = FSMCommon.get_ip_list_from_range(ipr[0], ipr[1])
        except BaseException as err:
            raise FSMBaseException(err)
        try:
            results_append_list = []
            for ip in ipr_list:
                append = fsm._tools.get_monitors_info_for_specific_ip(results, str(ip))
                if len(append) > 0:
                    results_append_list.append(append)
            results["json_results"]["summary"] = results_append_list
            # REMOVE THE FULL QUERY TO CLEAN UP THE RESULTS
            del results["json_results"]["monitoredDevices"]
        except BaseException as err:
            raise FSMBaseException(err)

    # RUN IF MODE = SINGLE IP ADDRESS
    if paramgram["mode"] == "detailed_single":
        try:
            results = fsm.handle_simple_request()
        except BaseException as err:
            raise FSMBaseException(err)
        results_append_list = []
        append = fsm._tools.get_monitors_info_for_specific_ip(results, paramgram["ip"])
        if len(append) > 0:
            results_append_list.append(append)
        results["json_results"]["summary"] = results_append_list
        # REMOVE THE FULL QUERY TO CLEAN UP THE RESULTS
        del results["json_results"]["monitoredDevices"]
        if isinstance(results["json_results"]["summary"], dict):
            # CONVERT SUMMARY DICT INTO XML
            results["xml_results"] = fsm._tools.dict2xml(results["json_results"]["summary"])
        elif isinstance(results["json_results"]["summary"], list):
            temp_xml_dict = {"results": results["xml_results"]}
            results["xml_results"] = fsm._tools.dict2xml(temp_xml_dict)

    # RUN IF MODE = UPDATE
    if paramgram["mode"] == "update":
        try:
            paramgram["input_xml"] = fsm.get_file_contents(paramgram["update_xml_file"])
            paramgram["input_xml"] = re.sub(r'\n', '', paramgram["input_xml"])
        except BaseException as err:
            raise FSMBaseException(msg="Couldn't find or load update_xml_file path. Double check. Error: " + str(err))
        # REFRESH PARAMGRAM
        module.paramgram = paramgram
        try:
            results = fsm.handle_simple_payload_request(str(paramgram["input_xml"]))
        except BaseException as err:
            raise FSMBaseException(err)
        # CONVERT SUMMARY DICT INTO XML
        results["xml_results"] = fsm._tools.dict2xml(results["json_results"])

    # EXIT USING GOVERN_RESPONSE()
    fsm.govern_response(module=module, results=results, changed=False, good_codes=[200, 204],
                        ansible_facts=fsm.construct_ansible_facts(results["json_results"],
                                                                  module.params,
                                                                  paramgram))
    # elif paramgram["mode"] == "update":

    return module.exit_json(msg=results)
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function

__metaclass__ = type

ANSIBLE_METADATA = {
    "metadata_version": "1.1",
    "status": ["preview"],
    "supported_by": "community"
}

DOCUMENTATION = '''
---
module: fsm_device_monitors
version_added: "2.8"
author: Luke Weighall (@lweighall)
short_description: Get a list of monitors for specified devices.
description:
  - Gets a short description of each devices monitors status in FortiSIEM.
  - Results are returned via dictionary json with the key "summary"

options:
  host:
    description:
      - The FortiSIEM's FQDN or IP Address.
    required: true

  username:
    description:
      - The username used to authenticate with the FortiManager.
      - organization/username format. The Organization is important, and will only return data from specified Org.
    required: false

  password:
    description:
      - The password associated with the username account.
    required: false

  ignore_ssl_errors:
    description:
      - When Enabled this will instruct the HTTP Libraries to ignore any ssl validation errors.
    required: false
    default: "enable"
    choices: ["enable", "disable"]

  export_json_to_screen:
    description:
      - When enabled this will print the JSON results to screen.
    required: false
    default: "enable"
    choices: ["enable", "disable"]

  export_json_to_file_path:
    description:
      - When populated, an attempt to write JSON dictionary to file is made.
      - An error will be thrown if this fails.
    required: false
    default: None

  export_xml_to_file_path:
    description:
      - When populated, an attempt to write XML to file is made.
      - An error will be thrown if this fails.
    required: false
    default: None

  mode:
    description:
      - Handles how the query is formatted upon return.
      - When in update mode, update_xml_file is required.
    required: false
    default: "short_all"
    choices: ["short_all", "ip_range", "detailed_single", "update"]

  ip_range:
    description:
      - Specifies the IP Range of devices to search for and return.
      - Ignored unless "ip_range" is set for mode
    required: false

  ip:
    description:
      - Specifies the single IP address of a device to get detailed information from.
      - Ignored unless "detailed_single" is set for mode
    required: false

  update_xml_file:
    description:
      - Specifies the XML file path that contains the pre-formatted XML to update the monitor with.
    required: false

'''

EXAMPLES = '''
- name: GET SIMPLE MONITOR LIST FROM CMDB
  fsm_device_monitors:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "short_all"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/monitors_out1.json"
    export_xml_to_file_path: "/root/monitors_out1.xml"

- name: GET SIMPLE MONITOR LIST FROM CMDB IP RANGE
  fsm_device_monitors:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "ip_range"
    ip_range: "10.0.0.5-10.0.0.15"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/monitors_out2.json"
    export_xml_to_file_path: "/root/monitors_out2.xml"

- name: GET DETAILED MONITOR INFO ON ONE DEVICE
  fsm_device_monitors:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "detailed_single"
    ip: "10.0.0.5"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/monitors_out3.json"
    export_xml_to_file_path: "/root/monitors_out3.xml"
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.network.fortisiem.common import FSMEndpoints
from ansible.module_utils.network.fortisiem.common import FSMBaseException
from ansible.module_utils.network.fortisiem.common import DEFAULT_EXIT_MSG
from ansible.module_utils.network.fortisiem.common import FSMCommon
from ansible.module_utils.network.fortisiem.fortisiem import FortiSIEMHandler
import re


def main():
    argument_spec = dict(
        host=dict(required=True, type="str"),
        username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"])),
        password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True),
        ignore_ssl_errors=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_screen=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_file_path=dict(required=False, type="str"),
        export_xml_to_file_path=dict(required=False, type="str"),
        export_csv_to_file_path=dict(required=False, type="str"),

        mode=dict(required=False, type="str",
                  choices=["short_all", "ip_range", "detailed_single", "update"], default="short_all"),
        ip_range=dict(required=False, type="str"),
        ip=dict(required=False, type="str"),
        update_xml_file=dict(required=False, type="str")
    )

    required_if = [
        ['mode', 'ip_range', ['ip_range']],
        ['mode', 'detailed_single', ['ip']],
        ['mode', 'update', ['update_xml_file']],
    ]

    module = AnsibleModule(argument_spec, supports_check_mode=False, required_if=required_if)

    paramgram = {
        "host": module.params["host"],
        "username": module.params["username"],
        "password": module.params["password"],
        "export_json_to_screen": module.params["export_json_to_screen"],
        "export_json_to_file_path": module.params["export_json_to_file_path"],
        "export_xml_to_file_path": module.params["export_xml_to_file_path"],
        "export_csv_to_file_path": module.params["export_csv_to_file_path"],
        "ignore_ssl_errors": module.params["ignore_ssl_errors"],
        "ip_range": module.params["ip_range"],
        "ip": module.params["ip"],
        "update_xml_file": module.params["update_xml_file"],
        "mode": module.params["mode"],
        "uri": None
    }

    # DETERMINE THE MODE AND ADD THE CORRECT DATA TO THE PARAMGRAM
    if paramgram["mode"] in ["short_all", "ip_range", "detailed_single"]:
        paramgram["uri"] = FSMEndpoints.GET_MONITORED_DEVICES
    elif paramgram["mode"] == "update":
        paramgram["uri"] = FSMEndpoints.UPDATE_DEVICE_MONITORING

    if paramgram["uri"] is None:
        raise FSMBaseException("Base URI couldn't be constructed. Check options.")

    module.paramgram = paramgram

    # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
    fsm = None
    results = DEFAULT_EXIT_MSG
    try:
        fsm = FortiSIEMHandler(module)
    except BaseException as err:
        raise FSMBaseException("Couldn't load FortiSIEM Handler from mod_utils. Error: " + str(err))

    # RUN IF MODE = SHORT ALL
    if paramgram["mode"] == "short_all":
        try:
            results = fsm.handle_simple_request()
        except BaseException as err:
            raise FSMBaseException(err)
        # ADD A SUMMARY TO THE RESULTS
        try:
            results = fsm._tools.get_monitors_summary_for_short_all(results)
        except BaseException as err:
            raise FSMBaseException(err)

    # RUN IF MODE = IP RANGE
    if paramgram["mode"] == "ip_range":
        try:
            results = fsm.handle_simple_request()
        except BaseException as err:
            raise FSMBaseException(err)
        # FOR EACH IP ADDRESS IN RANGE, RUN THE METHOD get_monitors_info_for_specific_ip

        try:
            ipr = str(paramgram["ip_range"]).split("-")
            ipr_list = FSMCommon.get_ip_list_from_range(ipr[0], ipr[1])
        except BaseException as err:
            raise FSMBaseException(err)
        try:
            results_append_list = []
            for ip in ipr_list:
                append = fsm._tools.get_monitors_info_for_specific_ip(results, str(ip))
                if len(append) > 0:
                    results_append_list.append(append)
            results["json_results"]["summary"] = results_append_list
            # REMOVE THE FULL QUERY TO CLEAN UP THE RESULTS
            del results["json_results"]["monitoredDevices"]
        except BaseException as err:
            raise FSMBaseException(err)

    # RUN IF MODE = SINGLE IP ADDRESS
    if paramgram["mode"] == "detailed_single":
        try:
            results = fsm.handle_simple_request()
        except BaseException as err:
            raise FSMBaseException(err)
        results_append_list = []
        append = fsm._tools.get_monitors_info_for_specific_ip(results, paramgram["ip"])
        if len(append) > 0:
            results_append_list.append(append)
        results["json_results"]["summary"] = results_append_list
        # REMOVE THE FULL QUERY TO CLEAN UP THE RESULTS
        del results["json_results"]["monitoredDevices"]
        if isinstance(results["json_results"]["summary"], dict):
            # CONVERT SUMMARY DICT INTO XML
            results["xml_results"] = fsm._tools.dict2xml(results["json_results"]["summary"])
        elif isinstance(results["json_results"]["summary"], list):
            temp_xml_dict = {"results": results["xml_results"]}
            results["xml_results"] = fsm._tools.dict2xml(temp_xml_dict)

    # RUN IF MODE = UPDATE
    if paramgram["mode"] == "update":
        try:
            paramgram["input_xml"] = fsm.get_file_contents(paramgram["update_xml_file"])
            paramgram["input_xml"] = re.sub(r'\n', '', paramgram["input_xml"])
        except BaseException as err:
            raise FSMBaseException(msg="Couldn't find or load update_xml_file path. Double check. Error: " + str(err))
        # REFRESH PARAMGRAM
        module.paramgram = paramgram
        try:
            results = fsm.handle_simple_payload_request(str(paramgram["input_xml"]))
        except BaseException as err:
            raise FSMBaseException(err)
        # CONVERT SUMMARY DICT INTO XML
        results["xml_results"] = fsm._tools.dict2xml(results["json_results"])

    # EXIT USING GOVERN_RESPONSE()
    fsm.govern_response(module=module, results=results, changed=False, good_codes=[200, 204],
                        ansible_facts=fsm.construct_ansible_facts(results["json_results"],
                                                                  module.params,
                                                                  paramgram))
    # elif paramgram["mode"] == "update":

    return module.exit_json(msg=results)


if __name__ == "__main__":
    main()

fsm_discovery

Metadata

Name: fsm_discovery

Description: Able to submit ad-hoc discoveries and query for the results of any task ID that was a discovery.

Author(s): Luke Weighall (@lweighall)

Ansible Version Added/Required: 2.8

Dev Status: No status updates, yet. Contact Authors.

Parameters
delta
  • Description: Only discovers new devices.
  • Required: False
  • default: False
discover_routes
  • Description: Discovers routes and follows those in smart scans.
  • Required: False
  • default: True
exclude_range
  • Description: Specifies the IP ranges to specify, in comma seperated format.
  • Required: False
export_json_to_file_path
  • Description: When populated, an attempt to write JSON dictionary to file is made.

    An error will be thrown if this fails.

  • Required: False

  • default: None

export_json_to_screen
  • Description: When enabled this will print the JSON results to screen.
  • Required: False
  • default: enable
  • choices: [‘enable’, ‘disable’]
export_xml_to_file_path
  • Description: When populated, an attempt to write XML to file is made.

    An error will be thrown if this fails.

  • Required: False

  • default: None

host
  • Description: The FortiSIEM’s FQDN or IP Address.
  • Required: True
ignore_ssl_errors
  • Description: When Enabled this will instruct the HTTP Libraries to ignore any ssl validation errors.
  • Required: False
  • default: enable
  • choices: [‘enable’, ‘disable’]
include_range
  • Description: Specifies the IP ranges to specify, in comma seperated format.
  • Required: False
monitor_installed_sw
  • Description: Turns on or off Windows Installed Software monitoring.
  • Required: False
  • default: True
monitor_win_events
  • Description: Turns on or off Windows Event log mointor for newly discovered devices.
  • Required: False
  • default: True
monitor_win_patches
  • Description: Turns on or off Windows Patching logging.
  • Required: False
  • default: True
name_resolution_dns_first
  • Description: Specifies to use DNS for name resolution first, and then SNMP/NETBIOS/SSH.

    When false, uses SNMP/NETBIOS/SSH first, then DNS

  • Required: False

  • default: True

no_ping
  • Description: Tells FortiSIEM not to attempt to ping a device before attempting to discover it.

    Useful when ICMP is blocked on target devices.

  • Required: False

  • default: False

only_ping
  • Description: Tells FortiSIEM to only discover devices with ICMP pings.
  • Required: False
  • default: False
password
  • Description: The password associated with the username account.
  • Required: False
root_ip
  • Description: Specifies the IP of a device to use as the “root” scanning device. Usually a router or switch.

    Ignored unless “SmartScan” is set for mode

  • Required: False

task_id
  • Description: Tells the module which task ID to query for when type = status.
  • Required: False
type
  • Description: Discovery type to use in FortiSIEM.
  • Required: True
  • choices: [‘RangeScan’, ‘SmartScan’, ‘L2Scan’, ‘status’]
unmanaged
  • Description: Sets newly discovered devices to unmanaged.
  • Required: False
  • default: False
username
  • Description: The username used to authenticate with the FortiManager.

    organization/username format. The Organization is important, and will only return data from specified Org.

  • Required: False

vm_off
  • Description: Doesn’t discover VMs.
  • Required: False
  • default: False
vm_templates
  • Description: Discover VM templates.
  • Required: False
  • default: False
wait_to_finish
  • Description: When enabled, the module will WAIT until the discovery actually finishes. This may or may not be desired depending on how big the discovery range is.

    When disabled, the module will simply submit the discovery and exit. You’ll have to record the task ID that was exported, and re-run the module with type = status.

  • Required: False

  • default: enable

  • choices: [‘enable’, ‘disable’]

winexe_based
  • Description: Discovers windows boxes with winExe.
  • Required: False
  • default: False
Functions
  • main
def main():
    argument_spec = dict(
        host=dict(required=True, type="str"),
        username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"])),
        password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True),
        ignore_ssl_errors=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_screen=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_file_path=dict(required=False, type="str"),
        export_xml_to_file_path=dict(required=False, type="str"),
        export_csv_to_file_path=dict(required=False, type="str"),

        wait_to_finish=dict(required=False, type="bool", default="false"),
        type=dict(required=True, type="str",
                  choices=["RangeScan", "SmartScan", "L2Scan", "status"]),
        root_ip=dict(required=False, type="str"),
        include_range=dict(required=False, type="str"),
        exclude_range=dict(required=False, type="str"),
        no_ping=dict(required=False, type="bool", default="false"),
        only_ping=dict(required=False, type="bool", default="false"),
        task_id=dict(required=False, type="int"),
        delta=dict(required=False, type="bool", default="false"),
        vm_off=dict(required=False, type="bool", default="false"),
        vm_templates=dict(required=False, type="bool", default="false"),
        discover_routes=dict(required=False, type="bool", default="true"),
        winexe_based=dict(required=False, type="bool", default="false"),
        unmanaged=dict(required=False, type="bool", default="false"),
        monitor_win_events=dict(required=False, type="bool", default="true"),
        monitor_win_patches=dict(required=False, type="bool", default="true"),
        monitor_installed_sw=dict(required=False, type="bool", default="true"),
        name_resolution_dns_first=dict(required=False, type="bool", default="true"),
    )

    required_if = [
        ['type', 'SmartScan', ['root_ip']],
        ['type', 'RangeScan', ['include_range']],
        ['type', 'L2Scan', ['include_range']],
        ['type', 'status', ['task_id']],
    ]

    module = AnsibleModule(argument_spec, supports_check_mode=False, required_if=required_if)

    paramgram = {
        "host": module.params["host"],
        "username": module.params["username"],
        "password": module.params["password"],
        "export_json_to_screen": module.params["export_json_to_screen"],
        "export_json_to_file_path": module.params["export_json_to_file_path"],
        "export_xml_to_file_path": module.params["export_xml_to_file_path"],
        "export_csv_to_file_path": module.params["export_csv_to_file_path"],
        "ignore_ssl_errors": module.params["ignore_ssl_errors"],

        "type": module.params["type"],
        "wait_to_finish": module.params["wait_to_finish"],
        "root_ip": module.params["root_ip"],
        "include_range": module.params["include_range"],
        "exclude_range": module.params["exclude_range"],
        "no_ping": module.params["no_ping"],
        "only_ping": module.params["only_ping"],
        "task_id": module.params["task_id"],
        "delta": module.params["delta"],
        "vm_off": module.params["vm_off"],
        "vm_templates": module.params["vm_templates"],
        "discover_routes": module.params["discover_routes"],
        "winexe_based": module.params["winexe_based"],
        "unmanaged": module.params["unmanaged"],
        "monitor_win_events": module.params["monitor_win_events"],
        "monitor_win_patches": module.params["monitor_win_patches"],
        "monitor_installed_sw": module.params["monitor_installed_sw"],
        "name_resolution_dns_first": module.params["name_resolution_dns_first"],

        "uri": FSMEndpoints.SET_DISCOVERY,
        "input_xml": None
    }

    module.paramgram = paramgram

    # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
    fsm = None
    results = DEFAULT_EXIT_MSG
    try:
        fsm = FortiSIEMHandler(module)
    except BaseException as err:
        raise FSMBaseException("Couldn't load FortiSIEM Handler from mod_utils. Error: " + str(err))

    # EXECUTE THE MODULE OPERATION
    # SEND THE DISCOVERY XML PAYLOAD
    if paramgram["type"] != "status":
        paramgram["input_xml"] = fsm._xml.create_discover_payload()
        try:
            results = fsm.handle_simple_payload_request(paramgram["input_xml"])
        except BaseException as err:
            raise FSMBaseException(err)

        # REFACTOR THE GENERIC RESPONSE BECAUSE IT WASN'T STRUCTURED BY FORTISIEM IN AN XML RESPONSE
        # RECORD THE TASK ID
        try:
            paramgram["task_id"] = results["json_results"]["fsm_response"]
            del results["json_results"]["fsm_response"]
            results["json_results"]["task_id"] = paramgram["task_id"]
            results["xml_results"] = "<task_id>" + str(paramgram["task_id"]) + "</task_id>"
        except BaseException as err:
            raise FSMBaseException(msg="Couldn't extract discovery task ID from response! Error: " + str(err))

    # START THE STATUS CHECKING PORTION
    if paramgram["type"] == "status" or paramgram["wait_to_finish"]:
        if not paramgram["task_id"]:
            raise FSMBaseException(msg="fsm_discovery was called to status "
                                       "or wait_to_finish but the task ID was empty")
        if paramgram["task_id"]:
            paramgram["uri"] = FSMEndpoints.GET_DISCOVERY + str(paramgram["task_id"])
            module.paramgram = paramgram
            try:
                results = fsm.handle_simple_request()
            except BaseException as err:
                raise FSMBaseException(msg="Failed to get status of task ID: " +
                                           str(paramgram["task_id"]) + " - Error: " + str(err))

            # PROCESS WAIT TO FINISH!
            if paramgram["wait_to_finish"]:
                try:
                    task_status_result = results["json_results"]["fsm_response"].split(":")

                    # SLEEP FOR 5 SECOND INTERVALS AND KEEP CHECKING UNTIL PROGRESS IS 100%
                    while task_status_result[1] != "Done":
                        time.sleep(5)
                        try:
                            results = fsm.handle_simple_request()
                        except BaseException as err:
                            raise FSMBaseException(msg="Failed to get status of task ID: " +
                                                       str(paramgram["task_id"]) + " - Error: " + str(err))
                        try:
                            if results["json_results"]["taskResults"]:
                                task_status_result = [str(paramgram["task_id"]), "Done"]
                        except BaseException:
                            try:
                                task_status_result = results["json_results"]["fsm_response"].split(":")
                            except BaseException as err:
                                raise FSMBaseException(err)
                except BaseException:
                    try:
                        if results["json_results"]["taskResults"]:
                            pass
                    except BaseException as err:
                        raise FSMBaseException(msg="Something happened while looping "
                                                   "for the status. Error: " + str(err))
                    pass

    # EXIT USING GOVERN_RESPONSE()
    fsm.govern_response(module=module, results=results, changed=False,
                        ansible_facts=fsm.construct_ansible_facts(results["json_results"],
                                                                  module.params,
                                                                  paramgram))

    return module.exit_json(msg=results)
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function

__metaclass__ = type

ANSIBLE_METADATA = {
    "metadata_version": "1.1",
    "status": ["preview"],
    "supported_by": "community"
}

DOCUMENTATION = '''
---
module: fsm_discovery
version_added: "2.8"
author: Luke Weighall (@lweighall)
short_description: Submits and Queries for Discovery Tasks.
description:
  - Able to submit ad-hoc discoveries and query for the results of any task ID that was a discovery.

options:
  host:
    description:
      - The FortiSIEM's FQDN or IP Address.
    required: true

  username:
    description:
      - The username used to authenticate with the FortiManager.
      - organization/username format. The Organization is important, and will only return data from specified Org.
    required: false

  password:
    description:
      - The password associated with the username account.
    required: false

  ignore_ssl_errors:
    description:
      - When Enabled this will instruct the HTTP Libraries to ignore any ssl validation errors.
    required: false
    default: "enable"
    choices: ["enable", "disable"]

  export_json_to_screen:
    description:
      - When enabled this will print the JSON results to screen.
    required: false
    default: "enable"
    choices: ["enable", "disable"]

  export_json_to_file_path:
    description:
      - When populated, an attempt to write JSON dictionary to file is made.
      - An error will be thrown if this fails.
    required: false
    default: None

  export_xml_to_file_path:
    description:
      - When populated, an attempt to write XML to file is made.
      - An error will be thrown if this fails.
    required: false
    default: None

  wait_to_finish:
    description:
      - When enabled, the module will WAIT until the discovery actually finishes.
        This may or may not be desired depending on how big the discovery range is.
      - When disabled, the module will simply submit the discovery and exit.
        You'll have to record the task ID that was exported, and re-run the module with type = status.
    required: false
    default: "enable"
    choices: ["enable", "disable"]

  type:
    description:
      - Discovery type to use in FortiSIEM.
    required: true
    choices: ["RangeScan", "SmartScan", "L2Scan", "status"]

  root_ip:
    description:
      - Specifies the IP of a device to use as the "root" scanning device. Usually a router or switch.
      - Ignored unless "SmartScan" is set for mode
    required: false

  include_range:
    description:
      - Specifies the IP ranges to specify, in comma seperated format.
    required: false

  exclude_range:
    description:
      - Specifies the IP ranges to specify, in comma seperated format.
    required: false

  no_ping:
    description:
      - Tells FortiSIEM not to attempt to ping a device before attempting to discover it.
      - Useful when ICMP is blocked on target devices.
    required: false
    default: false
    type: bool

  only_ping:
    description:
      - Tells FortiSIEM to only discover devices with ICMP pings.
    required: false
    default: false
    type: bool

  task_id:
    description:
      - Tells the module which task ID to query for when type = status.
    required: false
    type: int

  delta:
    description:
      - Only discovers new devices.
    required: false
    default: false
    type: bool

  vm_off:
    description:
      - Doesn't discover VMs.
    required: false
    default: false
    type: bool

  vm_templates:
    description:
      - Discover VM templates.
    required: false
    default: false
    type: bool

  discover_routes:
    description:
      - Discovers routes and follows those in smart scans.
    required: false
    default: true
    type: bool

  winexe_based:
    description:
      - Discovers windows boxes with winExe.
    required: false
    default: false
    type: bool

  unmanaged:
    description:
      - Sets newly discovered devices to unmanaged.
    required: false
    default: false
    type: bool

  monitor_win_events:
    description:
      - Turns on or off Windows Event log mointor for newly discovered devices.
    required: false
    default: true
    type: bool

  monitor_win_patches:
    description:
      - Turns on or off Windows Patching logging.
    required: false
    default: true
    type: bool

  monitor_installed_sw:
    description:
      - Turns on or off Windows Installed Software monitoring.
    required: false
    default: true
    type: bool

  name_resolution_dns_first:
    description:
      - Specifies to use DNS for name resolution first, and then SNMP/NETBIOS/SSH.
      - When false, uses SNMP/NETBIOS/SSH first, then DNS
    required: false
    default: true
    type: bool

'''

EXAMPLES = '''
- name: SUBMIT RANGE SCAN FOR SINGLE DEVICE
  fsm_discovery:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/range_scan.json"
    export_xml_to_file_path: "/root/range_scan.xml"
    type: "RangeScan"
    include_range: "10.0.0.254"

- name: SUBMIT RANGE SCAN FOR SINGLE DEVICE AND WAIT FOR FINISH WITH MANY OPTIONS
  fsm_discovery:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/range_scan2.json"
    export_xml_to_file_path: "/root/range_scan2.xml"
    type: "RangeScan"
    include_range: "10.0.0.5-10.0.0.20"
    wait_to_finish: True
    only_ping: False
    vm_off: True
    unmanaged: True
    delta: True
    name_resolution_dns_first: False
    winexe_based: True
    vm_templates: True
    discover_routes: True
    monitor_win_events: False
    monitor_win_patches: False
    monitor_installed_sw: False

- name: SUBMIT RANGE SCAN FOR SINGLE DEVICE AND WAIT FOR FINISH WITH NO PING
  fsm_discovery:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/json_test_out.json"
    export_xml_to_file_path: "/root/xml_test_out.xml"
    type: "RangeScan"
    include_range: "10.0.0.5-10.0.0.50"
    wait_to_finish: True
    no_ping: True


- name: SUBMIT RANGE SCAN FOR RANGE OF DEVICES
  fsm_discovery:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/json_test_out.json"
    export_xml_to_file_path: "/root/xml_test_out.xml"
    type: "RangeScan"
    include_range: "10.0.0.1-10.0.0.10"
    exclude_range: "10.0.0.5-10.0.0.6"

- name: SUBMIT SMART SCAN
  fsm_discovery:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/json_test_out.json"
    export_xml_to_file_path: "/root/xml_test_out.xml"
    type: "SmartScan"
    root_ip: "10.0.0.254"

- name: SUBMIT L2SCAN
  fsm_discovery:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/json_test_out.json"
    export_xml_to_file_path: "/root/xml_test_out.xml"
    type: "L2Scan"
    include_range: "10.0.0.1-10.0.0.254"
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule, env_fallback
import time
from ansible.module_utils.network.fortisiem.common import FSMEndpoints
from ansible.module_utils.network.fortisiem.common import FSMBaseException
from ansible.module_utils.network.fortisiem.common import DEFAULT_EXIT_MSG
from ansible.module_utils.network.fortisiem.fortisiem import FortiSIEMHandler


def main():
    argument_spec = dict(
        host=dict(required=True, type="str"),
        username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"])),
        password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True),
        ignore_ssl_errors=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_screen=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_file_path=dict(required=False, type="str"),
        export_xml_to_file_path=dict(required=False, type="str"),
        export_csv_to_file_path=dict(required=False, type="str"),

        wait_to_finish=dict(required=False, type="bool", default="false"),
        type=dict(required=True, type="str",
                  choices=["RangeScan", "SmartScan", "L2Scan", "status"]),
        root_ip=dict(required=False, type="str"),
        include_range=dict(required=False, type="str"),
        exclude_range=dict(required=False, type="str"),
        no_ping=dict(required=False, type="bool", default="false"),
        only_ping=dict(required=False, type="bool", default="false"),
        task_id=dict(required=False, type="int"),
        delta=dict(required=False, type="bool", default="false"),
        vm_off=dict(required=False, type="bool", default="false"),
        vm_templates=dict(required=False, type="bool", default="false"),
        discover_routes=dict(required=False, type="bool", default="true"),
        winexe_based=dict(required=False, type="bool", default="false"),
        unmanaged=dict(required=False, type="bool", default="false"),
        monitor_win_events=dict(required=False, type="bool", default="true"),
        monitor_win_patches=dict(required=False, type="bool", default="true"),
        monitor_installed_sw=dict(required=False, type="bool", default="true"),
        name_resolution_dns_first=dict(required=False, type="bool", default="true"),
    )

    required_if = [
        ['type', 'SmartScan', ['root_ip']],
        ['type', 'RangeScan', ['include_range']],
        ['type', 'L2Scan', ['include_range']],
        ['type', 'status', ['task_id']],
    ]

    module = AnsibleModule(argument_spec, supports_check_mode=False, required_if=required_if)

    paramgram = {
        "host": module.params["host"],
        "username": module.params["username"],
        "password": module.params["password"],
        "export_json_to_screen": module.params["export_json_to_screen"],
        "export_json_to_file_path": module.params["export_json_to_file_path"],
        "export_xml_to_file_path": module.params["export_xml_to_file_path"],
        "export_csv_to_file_path": module.params["export_csv_to_file_path"],
        "ignore_ssl_errors": module.params["ignore_ssl_errors"],

        "type": module.params["type"],
        "wait_to_finish": module.params["wait_to_finish"],
        "root_ip": module.params["root_ip"],
        "include_range": module.params["include_range"],
        "exclude_range": module.params["exclude_range"],
        "no_ping": module.params["no_ping"],
        "only_ping": module.params["only_ping"],
        "task_id": module.params["task_id"],
        "delta": module.params["delta"],
        "vm_off": module.params["vm_off"],
        "vm_templates": module.params["vm_templates"],
        "discover_routes": module.params["discover_routes"],
        "winexe_based": module.params["winexe_based"],
        "unmanaged": module.params["unmanaged"],
        "monitor_win_events": module.params["monitor_win_events"],
        "monitor_win_patches": module.params["monitor_win_patches"],
        "monitor_installed_sw": module.params["monitor_installed_sw"],
        "name_resolution_dns_first": module.params["name_resolution_dns_first"],

        "uri": FSMEndpoints.SET_DISCOVERY,
        "input_xml": None
    }

    module.paramgram = paramgram

    # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
    fsm = None
    results = DEFAULT_EXIT_MSG
    try:
        fsm = FortiSIEMHandler(module)
    except BaseException as err:
        raise FSMBaseException("Couldn't load FortiSIEM Handler from mod_utils. Error: " + str(err))

    # EXECUTE THE MODULE OPERATION
    # SEND THE DISCOVERY XML PAYLOAD
    if paramgram["type"] != "status":
        paramgram["input_xml"] = fsm._xml.create_discover_payload()
        try:
            results = fsm.handle_simple_payload_request(paramgram["input_xml"])
        except BaseException as err:
            raise FSMBaseException(err)

        # REFACTOR THE GENERIC RESPONSE BECAUSE IT WASN'T STRUCTURED BY FORTISIEM IN AN XML RESPONSE
        # RECORD THE TASK ID
        try:
            paramgram["task_id"] = results["json_results"]["fsm_response"]
            del results["json_results"]["fsm_response"]
            results["json_results"]["task_id"] = paramgram["task_id"]
            results["xml_results"] = "<task_id>" + str(paramgram["task_id"]) + "</task_id>"
        except BaseException as err:
            raise FSMBaseException(msg="Couldn't extract discovery task ID from response! Error: " + str(err))

    # START THE STATUS CHECKING PORTION
    if paramgram["type"] == "status" or paramgram["wait_to_finish"]:
        if not paramgram["task_id"]:
            raise FSMBaseException(msg="fsm_discovery was called to status "
                                       "or wait_to_finish but the task ID was empty")
        if paramgram["task_id"]:
            paramgram["uri"] = FSMEndpoints.GET_DISCOVERY + str(paramgram["task_id"])
            module.paramgram = paramgram
            try:
                results = fsm.handle_simple_request()
            except BaseException as err:
                raise FSMBaseException(msg="Failed to get status of task ID: " +
                                           str(paramgram["task_id"]) + " - Error: " + str(err))

            # PROCESS WAIT TO FINISH!
            if paramgram["wait_to_finish"]:
                try:
                    task_status_result = results["json_results"]["fsm_response"].split(":")

                    # SLEEP FOR 5 SECOND INTERVALS AND KEEP CHECKING UNTIL PROGRESS IS 100%
                    while task_status_result[1] != "Done":
                        time.sleep(5)
                        try:
                            results = fsm.handle_simple_request()
                        except BaseException as err:
                            raise FSMBaseException(msg="Failed to get status of task ID: " +
                                                       str(paramgram["task_id"]) + " - Error: " + str(err))
                        try:
                            if results["json_results"]["taskResults"]:
                                task_status_result = [str(paramgram["task_id"]), "Done"]
                        except BaseException:
                            try:
                                task_status_result = results["json_results"]["fsm_response"].split(":")
                            except BaseException as err:
                                raise FSMBaseException(err)
                except BaseException:
                    try:
                        if results["json_results"]["taskResults"]:
                            pass
                    except BaseException as err:
                        raise FSMBaseException(msg="Something happened while looping "
                                                   "for the status. Error: " + str(err))
                    pass

    # EXIT USING GOVERN_RESPONSE()
    fsm.govern_response(module=module, results=results, changed=False,
                        ansible_facts=fsm.construct_ansible_facts(results["json_results"],
                                                                  module.params,
                                                                  paramgram))

    return module.exit_json(msg=results)


if __name__ == "__main__":
    main()

fsm_maintenance

Metadata

Name: fsm_maintenance

Description: Creates and Deletes maintenance calendar objects.

Author(s): Luke Weighall (@lweighall)

Ansible Version Added/Required: 2.8

Dev Status: No status updates, yet. Contact Authors.

Parameters
description
  • Description: Description of the Schedule Entry.
  • Required: False
devices
  • Description: Comma seperated list of IP addresses to put into maintenance mode.
  • Required: False
duration
  • Description: The duration in minutes the maintenance period should last.
  • Required: True
end_date
  • Description: The end date of the maintenance period in YYYY-MM-DD format.

    Optional if end_date_open = True

  • Required: False

end_date_open
  • Description: If no end_date is required then specify as true.

    When true then end_date is ignored.

  • Required: False

  • default: False

export_json_to_file_path
  • Description: When populated, an attempt to write JSON dictionary to file is made.

    An error will be thrown if this fails.

  • Required: False

  • default: None

export_json_to_screen
  • Description: When enabled this will print the JSON results to screen.
  • Required: False
  • default: enable
  • choices: [‘enable’, ‘disable’]
export_xml_to_file_path
  • Description: When populated, an attempt to write XML to file is made.

    An error will be thrown if this fails.

  • Required: False

  • default: None

fire_incidents
  • Description: Decides whether or not to fire incidents for devices during the maintenance mode.
  • Required: False
groups
  • Description: Comma seperated list of Group Names to put into maintenance mode.
  • Required: False
host
  • Description: The FortiSIEM’s FQDN or IP Address.
  • Required: True
ignore_ssl_errors
  • Description: When Enabled this will instruct the HTTP Libraries to ignore any ssl validation errors.
  • Required: False
  • default: enable
  • choices: [‘enable’, ‘disable’]
input_xml_file
  • Description: If defined, all other options are ignored. The XML in the file path specified is strictly used.
  • Required: False
mode
  • Description: Defines which operation to use (add or delete).

    When deleting, the entire playbook and all parameters must match. It’s not enough to use the name.

    Recommend copy and paste task used to create org, and change mode to delete.

  • Required: False

  • default: add

  • choices: [‘add’, ‘delete’]

name
  • Description: Friendly Name of Schedule Entry.
  • Required: True
password
  • Description: The password associated with the username account.
  • Required: False
start_date
  • Description: The start date of the maintenance period in YYYY-MM-DD format.
  • Required: True
start_hour
  • Description: The 24-hour format hour of when the maintenance period should begin.
  • Required: True
start_min
  • Description: The xx digit version of minutes when the maintenance period should begin..
  • Required: True
time_zone
  • Description: The integer value of the relative timezone to GMT.

    i.e. -8 for NA/Pacific or -5 for NA/EastCoast or 0 for GMT

  • Required: True

time_zone_id
  • Description: The linux string version of the timezone.

    i.e. America/Los Angeles

  • Required: False

username
  • Description: The username used to authenticate with the FortiManager.

    organization/username format. The Organization is important, and will only return data from specified Org.

  • Required: False

Functions
  • main
def main():
    argument_spec = dict(
        host=dict(required=True, type="str"),
        username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"])),
        password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True),
        ignore_ssl_errors=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_screen=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_file_path=dict(required=False, type="str"),
        export_xml_to_file_path=dict(required=False, type="str"),
        export_csv_to_file_path=dict(required=False, type="str"),
        input_xml_file=dict(required=False, type="str"),
        mode=dict(required=False, type="str", default="add", choices=["add", "delete"]),
        name=dict(required=False, type="str"),
        description=dict(required=False, type="str"),
        devices=dict(required=False, type="str"),
        groups=dict(required=False, type="str"),
        fire_incidents=dict(required=False, type="bool"),
        time_zone_id=dict(required=False, type="str"),
        start_hour=dict(required=False, type="str"),
        start_min=dict(required=False, type="str"),
        duration=dict(required=False, type="str"),
        time_zone=dict(required=False, type="str"),
        start_date=dict(required=False, type="str"),
        end_date=dict(required=False, type="str"),
        end_date_open=dict(required=False, type="bool"),

    )

    module = AnsibleModule(argument_spec, supports_check_mode=False)

    paramgram = {
        "host": module.params["host"],
        "username": module.params["username"],
        "password": module.params["password"],
        "export_json_to_screen": module.params["export_json_to_screen"],
        "export_json_to_file_path": module.params["export_json_to_file_path"],
        "export_xml_to_file_path": module.params["export_xml_to_file_path"],
        "export_csv_to_file_path": module.params["export_csv_to_file_path"],
        "ignore_ssl_errors": module.params["ignore_ssl_errors"],
        "input_xml_file": module.params["input_xml_file"],
        "mode": module.params["mode"],
        "name": module.params["name"],
        "description": module.params["description"],
        "devices": module.params["devices"],
        "groups": module.params["groups"],
        "fire_incidents": module.params["fire_incidents"],
        "time_zone_id": module.params["time_zone_id"],
        "start_hour": module.params["start_hour"],
        "start_min": module.params["start_min"],
        "duration": module.params["duration"],
        "time_zone": module.params["time_zone"],
        "start_date": module.params["start_date"],
        "end_date": module.params["end_date"],
        "end_date_open": module.params["end_date_open"],

        "uri": None,
        "input_xml": None,
    }

    if not paramgram["end_date_open"]:
        paramgram["end_date_open"] = False
    module.paramgram = paramgram

    # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
    fsm = None
    results = DEFAULT_EXIT_MSG
    try:
        fsm = FortiSIEMHandler(module)
    except BaseException as err:
        raise FSMBaseException("Couldn't load FortiSIEM Handler from mod_utils. Error: " + str(err))

    # EXECUTE THE MODULE OPERATION
    if paramgram["mode"] == "add":
        paramgram["uri"] = FSMEndpoints.SET_MAINTENANCE
        try:
            if paramgram["input_xml_file"]:
                paramgram["input_xml"] = fsm.get_file_contents(paramgram["input_xml_file"])
            else:
                paramgram["input_xml"] = fsm._xml.create_maint_payload()
            results = fsm.handle_simple_payload_request(paramgram["input_xml"])
        except BaseException as err:
            raise FSMBaseException(err)
    elif paramgram["mode"] == "delete":
        paramgram["uri"] = FSMEndpoints.DEL_MAINTENANCE
        try:
            if paramgram["input_xml_file"]:
                paramgram["input_xml"] = fsm.get_file_contents(paramgram["input_xml_file"])
            else:
                paramgram["input_xml"] = fsm._xml.create_maint_payload()
            results = fsm.handle_simple_payload_request(paramgram["input_xml"])
        except BaseException as err:
            raise FSMBaseException(err)

    # EXIT USING GOVERN_RESPONSE()
    fsm.govern_response(module=module, results=results, changed=False, good_codes=[200, 204, ],
                        ansible_facts=fsm.construct_ansible_facts(results["json_results"],
                                                                  module.params,
                                                                  paramgram))

    return module.exit_json(msg=results)
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function

__metaclass__ = type

ANSIBLE_METADATA = {
    "metadata_version": "1.1",
    "status": ["preview"],
    "supported_by": "community"
}

DOCUMENTATION = '''
---
module: fsm_maintenance
version_added: "2.8"
author: Luke Weighall (@lweighall)
short_description: Creates and Deletes maintenance calendar objects.
description:
  - Creates and Deletes maintenance calendar objects.

options:
  host:
    description:
      - The FortiSIEM's FQDN or IP Address.
    required: true

  username:
    description:
      - The username used to authenticate with the FortiManager.
      - organization/username format. The Organization is important, and will only return data from specified Org.
    required: false

  password:
    description:
      - The password associated with the username account.
    required: false

  ignore_ssl_errors:
    description:
      - When Enabled this will instruct the HTTP Libraries to ignore any ssl validation errors.
    required: false
    default: "enable"
    choices: ["enable", "disable"]

  export_json_to_screen:
    description:
      - When enabled this will print the JSON results to screen.
    required: false
    default: "enable"
    choices: ["enable", "disable"]

  export_json_to_file_path:
    description:
      - When populated, an attempt to write JSON dictionary to file is made.
      - An error will be thrown if this fails.
    required: false
    default: None

  export_xml_to_file_path:
    description:
      - When populated, an attempt to write XML to file is made.
      - An error will be thrown if this fails.
    required: false
    default: None

  input_xml_file:
    description:
      - If defined, all other options are ignored. The XML in the file path specified is strictly used.
    required: false

  mode:
    description:
      - Defines which operation to use (add or delete).
      - When deleting, the entire playbook and all parameters must match. It's not enough to use the name.
      - Recommend copy and paste task used to create org, and change mode to delete.
    required: false
    default: "add"
    choices: ["add", "delete"]

  name:
    description:
      - Friendly Name of Schedule Entry.
    required: true

  description:
    description:
      - Description of the Schedule Entry.
    required: false

  devices:
    description:
      - Comma seperated list of IP addresses to put into maintenance mode.
    required: false

  groups:
    description:
      - Comma seperated list of Group Names to put into maintenance mode.
    required: false

  fire_incidents:
    description:
      - Decides whether or not to fire incidents for devices during the maintenance mode.
    required: false
    type: bool

  time_zone_id:
    description:
      - The linux string version of the timezone.
      - i.e. America/Los Angeles
    required: false

  start_hour:
    description:
      - The 24-hour format hour of when the maintenance period should begin.
    required: true

  start_min:
    description:
      - The xx digit version of minutes when the maintenance period should begin..
    required: true

  duration:
    description:
      - The duration in minutes the maintenance period should last.
    required: true

  time_zone:
    description:
      - The integer value of the relative timezone to GMT.
      - i.e. -8 for NA/Pacific or -5 for NA/EastCoast or 0 for GMT
    required: true

  start_date:
    description:
      - The start date of the maintenance period in YYYY-MM-DD format.
    required: true

  end_date:
    description:
      - The end date of the maintenance period in YYYY-MM-DD format.
      - Optional if end_date_open = True
    required: false

  end_date_open:
    description:
      - If no end_date is required then specify as true.
      - When true then end_date is ignored.
    required: false
    default: False
    type: bool
'''

EXAMPLES = '''
- name: SET BASIC MAINT SCHEDULE
   fsm_maintenance:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "add"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/json_main_1.json"
    export_xml_to_file_path: "/root/xml_main_1.json"
    name: "testMaintAnsible1"
    description: "created by ansible test workbook"
    devices: "10.0.0.5"
    fire_incidents: False
    time_zone_id: "Americas/Los_Angeles"
    start_hour: "08"
    start_min: "30"
    duration: "380"
    time_zone: "-8"
    start_date: "2019-05-02"
    end_date: "2019-05-10"

- name: SET BASIC MAINT SCHEDULE w/ open end date
  fsm_maintenance:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "add"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/json_main_2.json"
    export_xml_to_file_path: "/root/xml_main_2.json"
    name: "testMaintAnsible2"
    description: "created by ansible test workbook"
    devices: "10.0.0.5"
    fire_incidents: False
    time_zone_id: "Americas/Los_Angeles"
    start_hour: "08"
    start_min: "30"
    duration: "380"
    time_zone: "-8"
    start_date: "2019-05-02"
    end_date_open: True

- name: SET BASIC MAINT SCHEDULE w/ open end date 2
  fsm_maintenance:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "add"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/json_main_3.json"
    export_xml_to_file_path: "/root/xml_main_3.json"
    name: "testMaintAnsible4"
    description: "created by ansible test workbook"
    groups: "Firewall"
    fire_incidents: False
    time_zone_id: "Americas/Los_Angeles"
    start_hour: "08"
    start_min: "30"
    duration: "380"
    time_zone: "-8"
    start_date: "2019-05-02"
    end_date_open: True


- name: SET BASIC MAINT SCHEDULE VIA INPUT FILE
  fsm_maintenance:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "add"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/json_main_4.json"
    export_xml_to_file_path: "/root/xml_main_4.json"
    input_xml_file: "/root/scheduleDef.xml"

- name: DELETE SCHEDULE THAT MATCHES AN XML FILE
  fsm_maintenance:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "delete"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/json_main_1.json"
    export_xml_to_file_path: "/root/xml_main_1.json"
    input_xml_file: "/root/scheduleDef.xml"

- name: DELETE BASED ON NAME
  fsm_maintenance:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "delete"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/json_main_2_del.json"
    export_xml_to_file_path: "/root/xml_main_2_del.json"
    name: "testMaintAnsible1"
    description: "created by ansible test workbook"
    devices: "10.0.0.5"
    fire_incidents: False
    time_zone_id: "Americas/Los_Angeles"
    start_hour: "08"
    start_min: "30"
    duration: "380"
    time_zone: "-8"
    start_date: "2019-05-02"
    end_date: "2019-05-10"

- name: SET BASIC MAINT SCHEDULE w/ open end date 2
  fsm_maintenance:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "delete"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/json_main_3_del.json"
    export_xml_to_file_path: "/root/xml_main_3_del.json"
    name: "testMaintAnsible4"
    description: "created by ansible test workbook"
    groups: "Firewall"
    fire_incidents: False
    time_zone_id: "Americas/Los_Angeles"
    start_hour: "08"
    start_min: "30"
    duration: "380"
    time_zone: "-8"
    start_date: "2019-05-02"
    end_date_open: True

- name: DELETE BASED ON NAME 2
  fsm_maintenance:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "delete"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/json_main_3_del.json"
    export_xml_to_file_path: "/root/xml_main_3_del.json"
    name: "testMaintAnsible2"
    description: "created by ansible test workbook"
    devices: "10.0.0.5"
    fire_incidents: False
    time_zone_id: "Americas/Los_Angeles"
    start_hour: "08"
    start_min: "30"
    duration: "380"
    time_zone: "-8"
    start_date: "2019-05-02"
    end_date_open: True
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.network.fortisiem.common import FSMEndpoints
from ansible.module_utils.network.fortisiem.common import FSMBaseException
from ansible.module_utils.network.fortisiem.common import DEFAULT_EXIT_MSG
from ansible.module_utils.network.fortisiem.fortisiem import FortiSIEMHandler


def main():
    argument_spec = dict(
        host=dict(required=True, type="str"),
        username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"])),
        password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True),
        ignore_ssl_errors=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_screen=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_file_path=dict(required=False, type="str"),
        export_xml_to_file_path=dict(required=False, type="str"),
        export_csv_to_file_path=dict(required=False, type="str"),
        input_xml_file=dict(required=False, type="str"),
        mode=dict(required=False, type="str", default="add", choices=["add", "delete"]),
        name=dict(required=False, type="str"),
        description=dict(required=False, type="str"),
        devices=dict(required=False, type="str"),
        groups=dict(required=False, type="str"),
        fire_incidents=dict(required=False, type="bool"),
        time_zone_id=dict(required=False, type="str"),
        start_hour=dict(required=False, type="str"),
        start_min=dict(required=False, type="str"),
        duration=dict(required=False, type="str"),
        time_zone=dict(required=False, type="str"),
        start_date=dict(required=False, type="str"),
        end_date=dict(required=False, type="str"),
        end_date_open=dict(required=False, type="bool"),

    )

    module = AnsibleModule(argument_spec, supports_check_mode=False)

    paramgram = {
        "host": module.params["host"],
        "username": module.params["username"],
        "password": module.params["password"],
        "export_json_to_screen": module.params["export_json_to_screen"],
        "export_json_to_file_path": module.params["export_json_to_file_path"],
        "export_xml_to_file_path": module.params["export_xml_to_file_path"],
        "export_csv_to_file_path": module.params["export_csv_to_file_path"],
        "ignore_ssl_errors": module.params["ignore_ssl_errors"],
        "input_xml_file": module.params["input_xml_file"],
        "mode": module.params["mode"],
        "name": module.params["name"],
        "description": module.params["description"],
        "devices": module.params["devices"],
        "groups": module.params["groups"],
        "fire_incidents": module.params["fire_incidents"],
        "time_zone_id": module.params["time_zone_id"],
        "start_hour": module.params["start_hour"],
        "start_min": module.params["start_min"],
        "duration": module.params["duration"],
        "time_zone": module.params["time_zone"],
        "start_date": module.params["start_date"],
        "end_date": module.params["end_date"],
        "end_date_open": module.params["end_date_open"],

        "uri": None,
        "input_xml": None,
    }

    if not paramgram["end_date_open"]:
        paramgram["end_date_open"] = False
    module.paramgram = paramgram

    # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
    fsm = None
    results = DEFAULT_EXIT_MSG
    try:
        fsm = FortiSIEMHandler(module)
    except BaseException as err:
        raise FSMBaseException("Couldn't load FortiSIEM Handler from mod_utils. Error: " + str(err))

    # EXECUTE THE MODULE OPERATION
    if paramgram["mode"] == "add":
        paramgram["uri"] = FSMEndpoints.SET_MAINTENANCE
        try:
            if paramgram["input_xml_file"]:
                paramgram["input_xml"] = fsm.get_file_contents(paramgram["input_xml_file"])
            else:
                paramgram["input_xml"] = fsm._xml.create_maint_payload()
            results = fsm.handle_simple_payload_request(paramgram["input_xml"])
        except BaseException as err:
            raise FSMBaseException(err)
    elif paramgram["mode"] == "delete":
        paramgram["uri"] = FSMEndpoints.DEL_MAINTENANCE
        try:
            if paramgram["input_xml_file"]:
                paramgram["input_xml"] = fsm.get_file_contents(paramgram["input_xml_file"])
            else:
                paramgram["input_xml"] = fsm._xml.create_maint_payload()
            results = fsm.handle_simple_payload_request(paramgram["input_xml"])
        except BaseException as err:
            raise FSMBaseException(err)

    # EXIT USING GOVERN_RESPONSE()
    fsm.govern_response(module=module, results=results, changed=False, good_codes=[200, 204, ],
                        ansible_facts=fsm.construct_ansible_facts(results["json_results"],
                                                                  module.params,
                                                                  paramgram))

    return module.exit_json(msg=results)


if __name__ == "__main__":
    main()

fsm_organizations

Metadata

Name: fsm_organizations

Description: Gets a short description of each device in the FortiSIEM CMDB and returns the data

Author(s): Luke Weighall (@lweighall)

Ansible Version Added/Required: 2.8

Dev Status: No status updates, yet. Contact Authors.

Parameters
export_json_to_file_path
  • Description: When populated, an attempt to write JSON dictionary to file is made.

    An error will be thrown if this fails.

  • Required: False

  • default: None

export_json_to_screen
  • Description: When enabled this will print the JSON results to screen.
  • Required: False
  • default: enable
  • choices: [‘enable’, ‘disable’]
export_xml_to_file_path
  • Description: When populated, an attempt to write XML to file is made.

    An error will be thrown if this fails.

  • Required: False

  • default: None

host
  • Description: The FortiSIEM’s FQDN or IP Address.
  • Required: True
ignore_ssl_errors
  • Description: When Enabled this will instruct the HTTP Libraries to ignore any ssl validation errors.
  • Required: False
  • default: enable
  • choices: [‘enable’, ‘disable’]
mode
  • Description: Tells module to get, update or delete organizations.
  • Required: False
  • default: get
  • choices: [‘add’, ‘get’, ‘update’]
org_admin_email
  • Description: Organization administration email. Either internal, or customer alias.
  • Required: False
org_admin_password
  • Description: Organization root admin password to be used.
  • Required: False
org_admin_username
  • Description: Organization root admin username to be created.
  • Required: False
org_collector_eps
  • Description: Organization collector allowed events per second.
  • Required: False
org_collector_name
  • Description: Organization collector name.
  • Required: False
org_collectors
  • Description: If specified, other org_collector_ options are ignored. List with JSON dicts format expected.

    Only name and eps are valid arguments for each dictionary within the list.

    See playbook examples

  • Required: False

org_description
  • Description: The description of the organization.
  • Required: False
org_display_name
  • Description: The full display name for the organization.
  • Required: False
org_eps
  • Description: Events per second limit for organization.
  • Required: False
org_exclude_ip_range
  • Description: Excluded IP range. Typically only used for Orgs without a collector.
  • Required: False
org_include_ip_range
  • Description: Included IP Range. Typically only used for Orgs without a collector.
  • Required: False
org_max_devices
  • Description: Max number of devices allowed for org.
  • Required: False
  • default: 0
org_name
  • Description: The short-hand camelCase (preferred) name of the organization
  • Required: False
password
  • Description: The password associated with the username account.
  • Required: False
username
  • Description: The username used to authenticate with the FortiManager.

    organization/username format. The Organization is important, and will only return data from specified Org.

  • Required: False

Functions
  • main
def main():
    argument_spec = dict(
        host=dict(required=True, type="str"),
        username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"])),
        password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True),
        ignore_ssl_errors=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_screen=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_file_path=dict(required=False, type="str"),
        export_xml_to_file_path=dict(required=False, type="str"),
        export_csv_to_file_path=dict(required=False, type="str"),

        mode=dict(required=False, type="str",
                  choices=["get", "update", "add"], default="get"),
        org_name=dict(required=False, type="str"),
        org_display_name=dict(required=False, type="str"),
        org_description=dict(required=False, type="str"),
        org_admin_username=dict(required=False, type="str"),
        org_admin_password=dict(required=False, type="str", no_log=True),
        org_admin_email=dict(required=False, type="str"),
        org_eps=dict(required=False, type="str"),
        org_max_devices=dict(required=False, type="int", default=0),
        org_include_ip_range=dict(required=False, type="str"),
        org_exclude_ip_range=dict(required=False, type="str"),
        org_collectors=dict(required=False, type="list"),
        org_collector_name=dict(required=False, type="str"),
        org_collector_eps=dict(required=False, type="str"),

    )

    required_if = [
        ['mode', 'add', ['org_admin_username', 'org_admin_password', 'org_admin_email',
                         'org_name', 'org_display_name', 'org_description']],
        ['mode', 'update', ['org_name']],
    ]

    module = AnsibleModule(argument_spec, supports_check_mode=False, required_if=required_if)

    paramgram = {
        "host": module.params["host"],
        "username": module.params["username"],
        "password": module.params["password"],
        "export_json_to_screen": module.params["export_json_to_screen"],
        "export_json_to_file_path": module.params["export_json_to_file_path"],
        "export_xml_to_file_path": module.params["export_xml_to_file_path"],
        "export_csv_to_file_path": module.params["export_csv_to_file_path"],
        "ignore_ssl_errors": module.params["ignore_ssl_errors"],

        "mode": module.params["mode"],
        "uri": None,
        "input_xml": None,

        "org_name": module.params["org_name"],
        "org_display_name": module.params["org_display_name"],
        "org_description": module.params["org_description"],
        "org_admin_username": module.params["org_admin_username"],
        "org_admin_password": module.params["org_admin_password"],
        "org_admin_email": module.params["org_admin_email"],
        "org_eps": module.params["org_eps"],
        "org_max_devices": module.params["org_max_devices"],
        "org_include_ip_range": module.params["org_include_ip_range"],
        "org_exclude_ip_range": module.params["org_exclude_ip_range"],
        "org_collectors": module.params["org_collectors"],
        "org_collector_name": module.params["org_collector_name"],
        "org_collector_eps": module.params["org_collector_eps"],

    }

    # DETERMINE THE MODE AND ADD THE CORRECT DATA TO THE PARAMGRAM
    if paramgram["mode"] == "get":
        paramgram["uri"] = FSMEndpoints.GET_ORGS
    elif paramgram["mode"] == "update":
        paramgram["uri"] = FSMEndpoints.UPDATE_ORGS
    elif paramgram["mode"] == "add":
        paramgram["uri"] = FSMEndpoints.ADD_ORGS

    if paramgram["uri"] is None:
        raise FSMBaseException("Base URI couldn't be constructed. Check options.")

    module.paramgram = paramgram

    # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
    fsm = None
    results = DEFAULT_EXIT_MSG
    try:
        fsm = FortiSIEMHandler(module)
    except BaseException as err:
        raise FSMBaseException("Couldn't load FortiSIEM Handler from mod_utils. Error: " + str(err))
    # EXECUTE THE MODULE OPERATION
    if paramgram["mode"] in ['get']:
        try:
            results = fsm.handle_simple_request()
        except BaseException as err:
            raise FSMBaseException(err)
    elif paramgram["mode"] in ['update', 'add']:
        try:
            # CREATE PAYLOAD
            paramgram["input_xml"] = fsm._xml.create_org_payload()
            results = fsm.handle_simple_payload_request(payload=paramgram["input_xml"])
        except BaseException as err:
            raise FSMBaseException(err)
    # EXIT USING GOVERN_RESPONSE()
    fsm.govern_response(module=module, results=results, changed=False, good_codes=[200, 204],
                        ansible_facts=fsm.construct_ansible_facts(results["json_results"],
                                                                  module.params,
                                                                  paramgram))

    return module.exit_json(msg=results)
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function

__metaclass__ = type

ANSIBLE_METADATA = {
    "metadata_version": "1.1",
    "status": ["preview"],
    "supported_by": "community"
}

DOCUMENTATION = '''
---
module: fsm_organizations
version_added: "2.8"
author: Luke Weighall (@lweighall)
short_description: Get a list of devices from the FortiSIEM CMDB
description:
  - Gets a short description of each device in the FortiSIEM CMDB and returns the data

options:
  host:
    description:
      - The FortiSIEM's FQDN or IP Address.
    required: true

  username:
    description:
      - The username used to authenticate with the FortiManager.
      - organization/username format. The Organization is important, and will only return data from specified Org.
    required: false

  password:
    description:
      - The password associated with the username account.
    required: false

  ignore_ssl_errors:
    description:
      - When Enabled this will instruct the HTTP Libraries to ignore any ssl validation errors.
    required: false
    default: "enable"
    choices: ["enable", "disable"]

  export_json_to_screen:
    description:
      - When enabled this will print the JSON results to screen.
    required: false
    default: "enable"
    choices: ["enable", "disable"]

  export_json_to_file_path:
    description:
      - When populated, an attempt to write JSON dictionary to file is made.
      - An error will be thrown if this fails.
    required: false
    default: None

  export_xml_to_file_path:
    description:
      - When populated, an attempt to write XML to file is made.
      - An error will be thrown if this fails.
    required: false
    default: None

  mode:
    description:
      - Tells module to get, update or delete organizations.
    required: false
    default: "get"
    choices: ["add", "get", "update"]

  org_name:
    description:
      - The short-hand camelCase (preferred) name of the organization
    required: false

  org_display_name:
    description:
      - The full display name for the organization.
    required: false

  org_description:
    description:
      - The description of the organization.
    required: false

  org_admin_username:
    description:
      - Organization root admin username to be created.
    required: false

  org_admin_password:
    description:
      - Organization root admin password to be used.
    required: false

  org_admin_email:
    description:
      - Organization administration email. Either internal, or customer alias.
    required: false

  org_eps:
    description:
      - Events per second limit for organization.
    required: false

  org_max_devices:
    description:
      - Max number of devices allowed for org.
    required: false
    default: 0

  org_include_ip_range:
    description:
      - Included IP Range. Typically only used for Orgs without a collector.
    required: false

  org_exclude_ip_range:
    description:
      - Excluded IP range. Typically only used for Orgs without a collector.
    required: false

  org_collectors:
    description:
      - If specified, other org_collector_ options are ignored. List with JSON dicts format expected.
      - Only name and eps are valid arguments for each dictionary within the list.
      - See playbook examples
    required: false

  org_collector_name:
    description:
      - Organization collector name.
    required: false

  org_collector_eps:
    description:
      - Organization collector allowed events per second.
    required: false


'''

EXAMPLES = '''
- name: GET LIST OF ORGS
  fsm_organizations:
    host: "10.0.0.15"
    username: "super/api_user"
    password: "Fortinet!1"
    ignore_ssl_errors: "enable"

- name: ADD AN ORG WITH COLLECTOR VIA PARAMETERS
  fsm_organizations:
    host: "10.7.220.61"
    username: "super/api_user"
    password: "Fortinet!1"
    ignore_ssl_errors: "enable"
    mode: "add"
    org_name: "ansibleOrg1"
    org_display_name: "Ansible Test Org 1"
    org_description: "Testing Ansible. Duh."
    org_admin_username: "ansibleTest1"
    org_admin_password: "admin*1"
    org_admin_email: "ansible@test1.com"
    org_eps: "500"
    org_include_ip_range: "192.168.10.1-192.168.10.50"
    org_exclude_ip_range: "192.168.10.51-192.168.10.255"
    org_collector_name: "ansibleOrg1Col1"
    org_collector_eps: "200"
    org_max_devices: 5

- name: ADD AN ORG WITH COLLECTOR VIA JSON
  fsm_organizations:
    host: "10.7.220.61"
    username: "super/api_user"
    password: "Fortinet!1"
    ignore_ssl_errors: "enable"
    mode: "add"
    org_name: "ansibleOrg2"
    org_display_name: "Ansible Test Org 2"
    org_description: "Testing Ansible. Duh. Again."
    org_admin_username: "ansibleTest2"
    org_admin_password: "admin*1"
    org_admin_email: "ansible@test2.com"
    org_eps: "500"
    org_include_ip_range: "192.168.20.1-192.168.20.50"
    org_exclude_ip_range: "192.168.20.51-192.168.20.255"
    org_collectors: [{'name': 'ansibleOrg2Col1', 'eps': '200'},{'name': 'ansibleOrg2Col2', 'eps': '200'}]

- name: UPDATE AN ORG WITH COLLECTOR VIA PARAMETERS
  fsm_organizations:
    host: "10.7.220.61"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "update"
    export_json_to_screen: "enable"
    org_name: "ansibleOrg1"
    org_display_name: "Ansible Test Org 1"
    org_description: "Testing Ansible. Duh. Updated."
    org_eps: "400"
    org_include_ip_range: "192.168.10.1-192.168.10.50"
    org_exclude_ip_range: "192.168.10.51-192.168.10.255"
    org_collector_name: "ansibleOrg1Col1"
    org_collector_eps: "100"
  ignore_errors: yes



- name: UPDATE AN ORG WITH COLLECTOR VIA JSON
  fsm_organizations:
    host: "10.7.220.61"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "update"
    org_name: "ansibleOrg2"
    org_display_name: "Ansible Test Org 2"
    org_description: "Testing Ansible. Duh. Again. Updated."
    org_eps: "400"
    org_include_ip_range: "192.168.20.1-192.168.20.50"
    org_exclude_ip_range: "192.168.20.51-192.168.20.255"
    org_collectors: [{'name': 'ansibleOrg2Col1', 'eps': '100'},{'name': 'ansibleOrg2Col2', 'eps': '100'}]
  ignore_errors: yes
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.network.fortisiem.common import FSMEndpoints
from ansible.module_utils.network.fortisiem.common import FSMBaseException
from ansible.module_utils.network.fortisiem.common import DEFAULT_EXIT_MSG
from ansible.module_utils.network.fortisiem.fortisiem import FortiSIEMHandler



def main():
    argument_spec = dict(
        host=dict(required=True, type="str"),
        username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"])),
        password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True),
        ignore_ssl_errors=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_screen=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_file_path=dict(required=False, type="str"),
        export_xml_to_file_path=dict(required=False, type="str"),
        export_csv_to_file_path=dict(required=False, type="str"),

        mode=dict(required=False, type="str",
                  choices=["get", "update", "add"], default="get"),
        org_name=dict(required=False, type="str"),
        org_display_name=dict(required=False, type="str"),
        org_description=dict(required=False, type="str"),
        org_admin_username=dict(required=False, type="str"),
        org_admin_password=dict(required=False, type="str", no_log=True),
        org_admin_email=dict(required=False, type="str"),
        org_eps=dict(required=False, type="str"),
        org_max_devices=dict(required=False, type="int", default=0),
        org_include_ip_range=dict(required=False, type="str"),
        org_exclude_ip_range=dict(required=False, type="str"),
        org_collectors=dict(required=False, type="list"),
        org_collector_name=dict(required=False, type="str"),
        org_collector_eps=dict(required=False, type="str"),

    )

    required_if = [
        ['mode', 'add', ['org_admin_username', 'org_admin_password', 'org_admin_email',
                         'org_name', 'org_display_name', 'org_description']],
        ['mode', 'update', ['org_name']],
    ]

    module = AnsibleModule(argument_spec, supports_check_mode=False, required_if=required_if)

    paramgram = {
        "host": module.params["host"],
        "username": module.params["username"],
        "password": module.params["password"],
        "export_json_to_screen": module.params["export_json_to_screen"],
        "export_json_to_file_path": module.params["export_json_to_file_path"],
        "export_xml_to_file_path": module.params["export_xml_to_file_path"],
        "export_csv_to_file_path": module.params["export_csv_to_file_path"],
        "ignore_ssl_errors": module.params["ignore_ssl_errors"],

        "mode": module.params["mode"],
        "uri": None,
        "input_xml": None,

        "org_name": module.params["org_name"],
        "org_display_name": module.params["org_display_name"],
        "org_description": module.params["org_description"],
        "org_admin_username": module.params["org_admin_username"],
        "org_admin_password": module.params["org_admin_password"],
        "org_admin_email": module.params["org_admin_email"],
        "org_eps": module.params["org_eps"],
        "org_max_devices": module.params["org_max_devices"],
        "org_include_ip_range": module.params["org_include_ip_range"],
        "org_exclude_ip_range": module.params["org_exclude_ip_range"],
        "org_collectors": module.params["org_collectors"],
        "org_collector_name": module.params["org_collector_name"],
        "org_collector_eps": module.params["org_collector_eps"],

    }

    # DETERMINE THE MODE AND ADD THE CORRECT DATA TO THE PARAMGRAM
    if paramgram["mode"] == "get":
        paramgram["uri"] = FSMEndpoints.GET_ORGS
    elif paramgram["mode"] == "update":
        paramgram["uri"] = FSMEndpoints.UPDATE_ORGS
    elif paramgram["mode"] == "add":
        paramgram["uri"] = FSMEndpoints.ADD_ORGS

    if paramgram["uri"] is None:
        raise FSMBaseException("Base URI couldn't be constructed. Check options.")

    module.paramgram = paramgram

    # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
    fsm = None
    results = DEFAULT_EXIT_MSG
    try:
        fsm = FortiSIEMHandler(module)
    except BaseException as err:
        raise FSMBaseException("Couldn't load FortiSIEM Handler from mod_utils. Error: " + str(err))
    # EXECUTE THE MODULE OPERATION
    if paramgram["mode"] in ['get']:
        try:
            results = fsm.handle_simple_request()
        except BaseException as err:
            raise FSMBaseException(err)
    elif paramgram["mode"] in ['update', 'add']:
        try:
            # CREATE PAYLOAD
            paramgram["input_xml"] = fsm._xml.create_org_payload()
            results = fsm.handle_simple_payload_request(payload=paramgram["input_xml"])
        except BaseException as err:
            raise FSMBaseException(err)
    # EXIT USING GOVERN_RESPONSE()
    fsm.govern_response(module=module, results=results, changed=False, good_codes=[200, 204],
                        ansible_facts=fsm.construct_ansible_facts(results["json_results"],
                                                                  module.params,
                                                                  paramgram))

    return module.exit_json(msg=results)


if __name__ == "__main__":
    main()

fsm_report_query

Metadata

Name: fsm_report_query

Description: Allows a user to submit report XML, or pick from a report in the library by name, and to get the data returned.

Author(s): Luke Weighall (@lweighall)

Ansible Version Added/Required: 2.8

Dev Status: No status updates, yet. Contact Authors.

Parameters
export_csv_to_file_path
  • Description: When populated, an attempt to write CSV to file is made.

    An error will be thrown if this fails.

  • Required: False

  • default: None

export_json_to_file_path
  • Description: When populated, an attempt to write JSON dictionary to file is made.

    An error will be thrown if this fails.

  • Required: False

  • default: None

export_json_to_screen
  • Description: When enabled this will print the JSON results to screen.
  • Required: False
  • default: enable
  • choices: [‘enable’, ‘disable’]
export_xml_to_file_path
  • Description: When populated, an attempt to write XML to file is made.

    An error will be thrown if this fails.

  • Required: False

  • default: None

host
  • Description: The FortiSIEM’s FQDN or IP Address.
  • Required: True
ignore_ssl_errors
  • Description: When Enabled this will instruct the HTTP Libraries to ignore any ssl validation errors.
  • Required: False
  • default: enable
  • choices: [‘enable’, ‘disable’]
password
  • Description: The password associated with the username account.
  • Required: False
report_absolute_begin_date
  • Description: Changes report time to begin date in MM/DD/YYYY format Overrides any time filters in XML file path.

    Mutually exclusive with report_relative_mins

  • Required: False

report_absolute_begin_time
  • Description: Changes report time to begin time in 24h military format Overrides any time filters in XML file path.

    Includes seconds, so there are six digits. First two are hours, second two are mins, third two are seconds.

    Also accepts seconds in six-digit military. i.e. 103030

  • Required: False

report_absolute_end_date
  • Description: Changes report time to end date in MM/DD/YYYY format Overrides any time filters in XML file path.
  • Required: False
report_absolute_end_time
  • Description: Changes report time to end time in 24h military format Overrides any time filters in XML file path.

    Includes seconds, so there are six digits. First two are hours, second two are mins, third two are seconds.

    Also accepts seconds in six-digit military. i.e. 103030

  • Required: False

report_file_path
  • Description: Specifies PATH to File containing report XML.
  • Required: False
report_name
  • Description: Exact name match of a report in the CMDB that has been saved.

    Ansible will fetch XML from FortiSIEM before running.

  • Required: False

report_relative_mins
  • Description: Number of minutes of history to include in current report. Overrides any time filters in XML file path.

    Mutually exclusive with report_absolute_ options.

  • Required: False

report_string
  • Description: Specifies ad-hoc xml to be used if typed manually in playbook.
  • Required: False
username
  • Description: The username used to authenticate with the FortiManager.

    organization/username format. The Organization is important, and will only return data from specified Org.

  • Required: False

Functions
  • main
def main():
    argument_spec = dict(
        host=dict(required=True, type="str"),
        username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"])),
        password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True),
        ignore_ssl_errors=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_screen=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_file_path=dict(required=False, type="str"),
        export_xml_to_file_path=dict(required=False, type="str"),
        export_csv_to_file_path=dict(required=False, type="str"),

        report_name=dict(required=False, type="str"),
        report_string=dict(required=False, type="str"),
        report_file_path=dict(required=False, type="str"),
        report_relative_mins=dict(required=False, type="int"),
        report_absolute_begin_date=dict(required=False, type="str"),
        report_absolute_begin_time=dict(required=False, type="str"),
        report_absolute_end_date=dict(required=False, type="str"),
        report_absolute_end_time=dict(required=False, type="str"),

    )

    mututally_exclusive = [['report_name', 'report_string', 'report_file_pat'],
                           ['report_relative_mins', 'report_absolute_begin_date'],
                           ['report_relative_mins', 'report_absolute_begin_time'],
                           ['report_relative_mins', 'report_absolute_end_date'],
                           ['report_relative_mins', 'report_absolute_end_time'],
                           ]

    module = AnsibleModule(argument_spec, supports_check_mode=False, mutually_exclusive=mututally_exclusive)

    paramgram = {
        "host": module.params["host"],
        "username": module.params["username"],
        "password": module.params["password"],
        "export_json_to_screen": module.params["export_json_to_screen"],
        "export_json_to_file_path": module.params["export_json_to_file_path"],
        "export_xml_to_file_path": module.params["export_xml_to_file_path"],
        "export_csv_to_file_path": module.params["export_csv_to_file_path"],
        "ignore_ssl_errors": module.params["ignore_ssl_errors"],

        "report_name": module.params["report_name"],
        "report_string": module.params["report_string"],
        "report_file_path": module.params["report_file_path"],
        "report_relative_mins": module.params["report_relative_mins"],
        "report_absolute_begin_date": module.params["report_absolute_begin_date"],
        "report_absolute_begin_time": module.params["report_absolute_begin_time"],
        "report_absolute_end_date": module.params["report_absolute_end_date"],
        "report_absolute_end_time": module.params["report_absolute_end_time"],
        "uri": FSMEndpoints.PUT_SUBMIT_REPORT,
        "input_xml": None,
        "queryId": None
    }

    module.paramgram = paramgram

    # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
    fsm = None
    results = DEFAULT_EXIT_MSG
    try:
        fsm = FortiSIEMHandler(module)
    except BaseException as err:
        raise FSMBaseException("Couldn't load FortiSIEM Handler from mod_utils. Error: " + str(err))

    if paramgram["report_string"]:
        paramgram["input_xml"] = paramgram["report_string"]
    if paramgram["report_file_path"]:
        paramgram["input_xml"] = fsm.get_file_contents(paramgram["report_file_path"])

    # IF REPORT TIME PARAMETERS HAVE BEEN SET, THEN PROCESS THOSE, AND EDIT THE REPORT XML
    if paramgram["report_relative_mins"]:
        new_xml = fsm.replace_fsm_report_timestamp_relative()
        paramgram["input_xml"] = new_xml
    elif paramgram["report_absolute_begin_date"] and paramgram["report_absolute_begin_time"] \
            and paramgram["report_absolute_end_date"] and paramgram["report_absolute_end_time"]:
        new_xml = fsm.replace_fsm_report_timestamp_absolute()
        paramgram["input_xml"] = new_xml

    # CHECK IF INPUT XML IS ACTUALLY VALID XML
    try:
        fsm._tools.validate_xml(paramgram["input_xml"])
    except BaseException as err:
        raise FSMBaseException("XML Report Provided was unable to be parsed. "
                               "Please double check source XML. Error: " + str(err))
    # EXECUTE MODULE OPERATION
    try:
        results = fsm.handle_report_submission()
    except BaseException as err:
        raise FSMBaseException(err)

    # EXIT USING GOVERN_RESPONSE()
    fsm.govern_response(module=module, results=results, changed=False,
                        ansible_facts=fsm.construct_ansible_facts(results["json_results"],
                                                                  module.params,
                                                                  paramgram))

    return module.exit_json(msg=results)
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function

__metaclass__ = type

ANSIBLE_METADATA = {
    "metadata_version": "1.1",
    "status": ["preview"],
    "supported_by": "community"
}

DOCUMENTATION = '''
---
module: fsm_report_query
version_added: "2.8"
author: Luke Weighall (@lweighall)
short_description: Allows the submission of reports and return of data
description:
  - Allows a user to submit report XML, or pick from a report in the library by name, and to get the data returned.

options:
  host:
    description:
      - The FortiSIEM's FQDN or IP Address.
    required: true

  username:
    description:
      - The username used to authenticate with the FortiManager.
      - organization/username format. The Organization is important, and will only return data from specified Org.
    required: false

  password:
    description:
      - The password associated with the username account.
    required: false

  ignore_ssl_errors:
    description:
      - When Enabled this will instruct the HTTP Libraries to ignore any ssl validation errors.
    required: false
    default: "enable"
    choices: ["enable", "disable"]

  export_json_to_screen:
    description:
      - When enabled this will print the JSON results to screen.
    required: false
    default: "enable"
    choices: ["enable", "disable"]

  export_json_to_file_path:
    description:
      - When populated, an attempt to write JSON dictionary to file is made.
      - An error will be thrown if this fails.
    required: false
    default: None

  export_xml_to_file_path:
    description:
      - When populated, an attempt to write XML to file is made.
      - An error will be thrown if this fails.
    required: false
    default: None

  export_csv_to_file_path:
    description:
      - When populated, an attempt to write CSV to file is made.
      - An error will be thrown if this fails.
    required: false
    default: None

  report_name:
    description:
      - Exact name match of a report in the CMDB that has been saved.
      - Ansible will fetch XML from FortiSIEM before running.
    required: false

  report_string:
    description:
      - Specifies ad-hoc xml to be used if typed manually in playbook.
    required: false

  report_file_path:
    description:
      - Specifies PATH to File containing report XML.
    required: false

  report_relative_mins:
    description:
      - Number of minutes of history to include in current report. Overrides any time filters in XML file path.
      - Mutually exclusive with report_absolute_ options.
    required: false

  report_absolute_begin_date:
    description:
      - Changes report time to begin date in MM/DD/YYYY format Overrides any time filters in XML file path.
      - Mutually exclusive with report_relative_mins
    required: false

  report_absolute_begin_time:
    description:
      - Changes report time to begin time in 24h military format Overrides any time filters in XML file path.
      - Includes seconds, so there are six digits. First two are hours, second two are mins, third two are seconds.
      - Also accepts seconds in six-digit military. i.e. 103030
    required: false

  report_absolute_end_date:
    description:
      - Changes report time to end date in MM/DD/YYYY format Overrides any time filters in XML file path.
    required: false

  report_absolute_end_time:
    description:
      - Changes report time to end time in 24h military format Overrides any time filters in XML file path.
      - Includes seconds, so there are six digits. First two are hours, second two are mins, third two are seconds.
      - Also accepts seconds in six-digit military. i.e. 103030
    required: false

'''

EXAMPLES = '''
- name: SUBMIT REPORT
  fsm_report_query:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    report_file_path: "/root/top_fortisiem_events_by_count.xml"
    export_json_to_file_path: "/root/report.json"
    export_xml_to_file_path: "/root/report.xml"
    export_csv_to_file_path: "/root/report.csv"

- name: GET REPORT WITH RELATIVE TIME DEFINED
  fsm_report_query:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    report_file_path: "/root/top_fortisiem_events_by_count.xml"
    report_relative_mins: "60"

- name: GET REPORT WITH ABSOLUTE TIME DEFINED
  fsm_report_query:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    report_file_path: "/root/top_fortisiem_events_by_count.xml"
    report_absolute_begin_date: "04/17/2019"
    report_absolute_begin_time: "060000"
    report_absolute_end_date: "04/17/2019"
    report_absolute_end_time: "070000"
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.network.fortisiem.common import FSMEndpoints
from ansible.module_utils.network.fortisiem.common import FSMBaseException
from ansible.module_utils.network.fortisiem.common import DEFAULT_EXIT_MSG
from ansible.module_utils.network.fortisiem.fortisiem import FortiSIEMHandler


def main():
    argument_spec = dict(
        host=dict(required=True, type="str"),
        username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"])),
        password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True),
        ignore_ssl_errors=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_screen=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_file_path=dict(required=False, type="str"),
        export_xml_to_file_path=dict(required=False, type="str"),
        export_csv_to_file_path=dict(required=False, type="str"),

        report_name=dict(required=False, type="str"),
        report_string=dict(required=False, type="str"),
        report_file_path=dict(required=False, type="str"),
        report_relative_mins=dict(required=False, type="int"),
        report_absolute_begin_date=dict(required=False, type="str"),
        report_absolute_begin_time=dict(required=False, type="str"),
        report_absolute_end_date=dict(required=False, type="str"),
        report_absolute_end_time=dict(required=False, type="str"),

    )

    mututally_exclusive = [['report_name', 'report_string', 'report_file_pat'],
                           ['report_relative_mins', 'report_absolute_begin_date'],
                           ['report_relative_mins', 'report_absolute_begin_time'],
                           ['report_relative_mins', 'report_absolute_end_date'],
                           ['report_relative_mins', 'report_absolute_end_time'],
                           ]

    module = AnsibleModule(argument_spec, supports_check_mode=False, mutually_exclusive=mututally_exclusive)

    paramgram = {
        "host": module.params["host"],
        "username": module.params["username"],
        "password": module.params["password"],
        "export_json_to_screen": module.params["export_json_to_screen"],
        "export_json_to_file_path": module.params["export_json_to_file_path"],
        "export_xml_to_file_path": module.params["export_xml_to_file_path"],
        "export_csv_to_file_path": module.params["export_csv_to_file_path"],
        "ignore_ssl_errors": module.params["ignore_ssl_errors"],

        "report_name": module.params["report_name"],
        "report_string": module.params["report_string"],
        "report_file_path": module.params["report_file_path"],
        "report_relative_mins": module.params["report_relative_mins"],
        "report_absolute_begin_date": module.params["report_absolute_begin_date"],
        "report_absolute_begin_time": module.params["report_absolute_begin_time"],
        "report_absolute_end_date": module.params["report_absolute_end_date"],
        "report_absolute_end_time": module.params["report_absolute_end_time"],
        "uri": FSMEndpoints.PUT_SUBMIT_REPORT,
        "input_xml": None,
        "queryId": None
    }

    module.paramgram = paramgram

    # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
    fsm = None
    results = DEFAULT_EXIT_MSG
    try:
        fsm = FortiSIEMHandler(module)
    except BaseException as err:
        raise FSMBaseException("Couldn't load FortiSIEM Handler from mod_utils. Error: " + str(err))

    if paramgram["report_string"]:
        paramgram["input_xml"] = paramgram["report_string"]
    if paramgram["report_file_path"]:
        paramgram["input_xml"] = fsm.get_file_contents(paramgram["report_file_path"])

    # IF REPORT TIME PARAMETERS HAVE BEEN SET, THEN PROCESS THOSE, AND EDIT THE REPORT XML
    if paramgram["report_relative_mins"]:
        new_xml = fsm.replace_fsm_report_timestamp_relative()
        paramgram["input_xml"] = new_xml
    elif paramgram["report_absolute_begin_date"] and paramgram["report_absolute_begin_time"] \
            and paramgram["report_absolute_end_date"] and paramgram["report_absolute_end_time"]:
        new_xml = fsm.replace_fsm_report_timestamp_absolute()
        paramgram["input_xml"] = new_xml

    # CHECK IF INPUT XML IS ACTUALLY VALID XML
    try:
        fsm._tools.validate_xml(paramgram["input_xml"])
    except BaseException as err:
        raise FSMBaseException("XML Report Provided was unable to be parsed. "
                               "Please double check source XML. Error: " + str(err))
    # EXECUTE MODULE OPERATION
    try:
        results = fsm.handle_report_submission()
    except BaseException as err:
        raise FSMBaseException(err)

    # EXIT USING GOVERN_RESPONSE()
    fsm.govern_response(module=module, results=results, changed=False,
                        ansible_facts=fsm.construct_ansible_facts(results["json_results"],
                                                                  module.params,
                                                                  paramgram))

    return module.exit_json(msg=results)


if __name__ == "__main__":
    main()

fsm_send_syslog

Metadata

Name: fsm_send_syslog

Description: Used to send events/logs/errors to FortiSIEM for any purpose. Can be used to send alerts from non-connected systems, or from any ansible playbook.

Author(s): Luke Weighall (@lweighall)

Ansible Version Added/Required: 2.8

Dev Status: No status updates, yet. Contact Authors.

Parameters
ignore_ssl_errors
  • Description: When Enabled this will instruct the HTTP Libraries to ignore any ssl validation errors.

    Also will ignore any errors when network_protocol = TCP

  • Required: False

  • default: enable

  • choices: [‘enable’, ‘disable’]

network_port
  • Description: Handles which port to send the log on, TCP or UDP. Default 514
  • Required: False
  • default: 514
network_protocol
  • Description: Handles how the syslog is transmitted. TCP or UDP, with or without TLS 1.2.
  • Required: False
  • default: udp
  • choices: [‘udp’, ‘tcp’, ‘tcp-tls1.2’]
syslog_facility
  • Description: The facility of the syslog.
  • Required: False
  • default: USER
  • choices: [‘KERN’, ‘USER’, ‘MAIL’, ‘DAEMON’, ‘AUTH’, ‘SYSLOG’, ‘LPR’, ‘NEWS’, ‘UUCP’, ‘CRON’, ‘AUTHPRIV’, ‘FTP’, ‘LOCAL0’, ‘LOCAL1’, ‘LOCAL2’, ‘LOCAL3’, ‘LOCAL4’, ‘LOCAL5’, ‘LOCAL6’, ‘LOCAL7’]
syslog_header
  • Description: If defined, will be used as the syslog header after the priority <##> (we specify that for you)

    If left empty, we generate a header for you.

  • Required: False

syslog_host
  • Description: The FortiSIEM’s FQDN or IP Address.
  • Required: True
syslog_level
  • Description: The level of the syslog.
  • Required: False
  • default: INFO
  • choices: [‘EMERG’, ‘ALERT’, ‘CRIT’, ‘ERR’, ‘WARNING’, ‘NOTICE’, ‘INFO’, ‘DEBUG’]
syslog_message
  • Description: The actual message to send.
  • Required: True
Functions
  • main
def main():
    argument_spec = dict(
        syslog_host=dict(required=True, type="str"),
        ignore_ssl_errors=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),

        network_protocol=dict(required=False, type="str", default="udp",
                              choices=["udp", "tcp", "tcp-tls1.2"]),
        network_port=dict(required=False, type="int", default=0),
        syslog_message=dict(required=False, type="str"),
        syslog_header=dict(required=False, type="str", default=None),
        syslog_facility=dict(required=False, type="str", default="USER", choices=['KERN', 'USER', 'MAIL',
                                                                                  'DAEMON', 'AUTH', 'SYSLOG', 'LPR',
                                                                                  'NEWS', 'UUCP', 'CRON', 'AUTHPRIV',
                                                                                  'FTP', 'LOCAL0', 'LOCAL1', 'LOCAL2',
                                                                                  'LOCAL3', 'LOCAL4', 'LOCAL5',
                                                                                  'LOCAL6', 'LOCAL7']),
        syslog_level=dict(required=False, type="str", default="INFO", choices=['EMERG', 'ALERT', 'CRIT', 'ERR',
                                                                               'WARNING', 'NOTICE',
                                                                               'INFO', 'DEBUG']),

    )
    module = AnsibleModule(argument_spec, supports_check_mode=False)

    paramgram = {
        "syslog_host": module.params["syslog_host"],
        "ignore_ssl_errors": module.params["ignore_ssl_errors"],

        "network_protocol": module.params["network_protocol"],
        "network_port": module.params["network_port"],
        "syslog_message": module.params["syslog_message"],
        "syslog_header": module.params["syslog_header"],
        "syslog_facility": module.params["syslog_facility"],
        "syslog_level": module.params["syslog_level"],
    }

    # SET THE APPROPRIATE PORT IF NOT SUPPLIED
    if paramgram["network_port"] == 0:
        if paramgram["network_protocol"] == "udp":
            paramgram["network_port"] = 514
        if paramgram["network_protocol"] == "tcp":
            paramgram["network_port"] = 1470
        if paramgram["network_protocol"] == "tcp-tls1.2":
            paramgram["network_port"] = 6514

    # GET THE PROPER VALUES FROM FACILITY AND LEVELS
    try:
        facility_search = "SyslogFacility." + str(paramgram["syslog_facility"].upper())
        paramgram["syslog_facility"] = eval(facility_search)
    except BaseException as err:
        raise FSMBaseException(msg="An error occured converted Syslog Facility to an integer. Error: " + str(err))

    try:
        level_search = "SyslogLevel." + str(paramgram["syslog_level"].upper())
        paramgram["syslog_level"] = eval(level_search)
    except BaseException as err:
        raise FSMBaseException(msg="An error occured converted Syslog Facility to an integer. Error: " + str(err))

    module.paramgram = paramgram

    # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
    fsm = None
    try:
        fsm = FortiSIEMHandler(module)
    except BaseException as err:
        raise FSMBaseException("Couldn't load FortiSIEM Handler from mod_utils. Error: " + str(err))

    if not paramgram["syslog_header"]:
        paramgram["syslog_header"] = str(fsm._tools.get_current_datetime() + " ansible_module:fsm_send_syslog")
        module.paramgram = paramgram

    # EXECUTE THE MODULE OPERATION
    results = DEFAULT_EXIT_MSG
    try:
        results = fsm.handle_syslog_request()
    except BaseException as err:
        raise FSMBaseException(err)

    return module.exit_json(msg=str(results["message"]), results=str(results["status"]))
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function

__metaclass__ = type

ANSIBLE_METADATA = {
    "metadata_version": "1.1",
    "status": ["preview"],
    "supported_by": "community"
}

DOCUMENTATION = '''
---
module: fsm_send_syslog
version_added: "2.8"
author: Luke Weighall (@lweighall)
short_description: Sends a text string to FortiSIEM as a Syslog
description:
  - Used to send events/logs/errors to FortiSIEM for any purpose.
  - Can be used to send alerts from non-connected systems, or from any ansible playbook.

options:
  syslog_host:
    description:
      - The FortiSIEM's FQDN or IP Address.
    required: true

  ignore_ssl_errors:
    description:
      - When Enabled this will instruct the HTTP Libraries to ignore any ssl validation errors.
      - Also will ignore any errors when network_protocol = TCP
    required: false
    default: "enable"
    choices: ["enable", "disable"]

  network_protocol:
    description:
      - Handles how the syslog is transmitted. TCP or UDP, with or without TLS 1.2.
    required: false
    default: "udp"
    choices: ["udp", "tcp", "tcp-tls1.2"]

  network_port:
    description:
      - Handles which port to send the log on, TCP or UDP. Default 514
    required: false
    default: 514

  syslog_message:
    description:
      - The actual message to send.
    required: true

  syslog_header:
    description:
      - If defined, will be used as the syslog header after the priority <##> (we specify that for you)
      - If left empty, we generate a header for you.
    required: false

  syslog_facility:
    description:
      - The facility of the syslog.
    default: "USER"
    required: false
    choices: ['KERN', 'USER', 'MAIL', 'DAEMON', 'AUTH', 'SYSLOG',
              'LPR', 'NEWS', 'UUCP', 'CRON', 'AUTHPRIV', 'FTP',
              'LOCAL0', 'LOCAL1', 'LOCAL2', 'LOCAL3',
              'LOCAL4', 'LOCAL5', 'LOCAL6', 'LOCAL7']

  syslog_level:
    description:
      - The level of the syslog.
    default: "INFO"
    required: false
    choices: [ 'EMERG', 'ALERT', 'CRIT', 'ERR', 'WARNING', 'NOTICE', 'INFO', 'DEBUG' ]

'''

EXAMPLES = '''
- name: SEND UDP/514 SYSLOG WITH AUTO HEADER
  fsm_send_syslog:
    host: "10.0.0.15"
    ignore_ssl_errors: "enable"
    syslog_message: "This is a test syslog from Ansible!"

- name: SEND UDP/514 SYSLOG WITH AUTO HEADER
  fsm_send_syslog:
    syslog_host: "10.7.220.61"
    ignore_ssl_errors: "enable"
    syslog_message: "This is a test syslog from Ansible!"

- name: SEND UDP/514 SYSLOG CUSTOM HEADER
  fsm_send_syslog:
    syslog_host: "10.7.220.61"
    ignore_ssl_errors: "enable"
    syslog_message: "This is a test syslog from Ansible!"
    syslog_header: "This is a TEST HEADER :"

- name: SEND TCP/1470 SYSLOG WITH CUSTOM HEADER
  fsm_send_syslog:
    syslog_host: "10.7.220.61"
    ignore_ssl_errors: "enable"
    network_port: 1470
    network_protocol: "tcp"
    syslog_message: "This is a test syslog from Ansible!"
    syslog_header: "This is a TEST HEADER TCP PORT 1470 :"

- name: SEND TCP/6514 TLS SYSLOG WITH CUSTOM HEADER
  fsm_send_syslog:
    syslog_host: "10.7.220.61"
    ignore_ssl_errors: "enable"
    network_port: 6514
    network_protocol: "tcp-tls1.2"
    syslog_message: "This is a test syslog from Ansible!"
    syslog_header: "This is a TEST HEADER TCP TLS PORT 6514 :"

- name: SEND UDP/514 SYSLOG WITH AUTO HEADER AND DIFF FACILITY AND LEVEL
  fsm_send_syslog:
    syslog_host: "10.7.220.61"
    ignore_ssl_errors: "enable"
    syslog_facility: "AUTH"
    syslog_level: "CRIT"
    syslog_message: "This is a test syslog from Ansible! WITH CRIT AND AUTH AS LEVELS AND FACILITY."
'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.fortisiem.common import FSMBaseException
from ansible.module_utils.network.fortisiem.common import DEFAULT_EXIT_MSG
from ansible.module_utils.network.fortisiem.common import SyslogFacility
from ansible.module_utils.network.fortisiem.common import SyslogLevel
from ansible.module_utils.network.fortisiem.fortisiem import FortiSIEMHandler


def main():
    argument_spec = dict(
        syslog_host=dict(required=True, type="str"),
        ignore_ssl_errors=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),

        network_protocol=dict(required=False, type="str", default="udp",
                              choices=["udp", "tcp", "tcp-tls1.2"]),
        network_port=dict(required=False, type="int", default=0),
        syslog_message=dict(required=False, type="str"),
        syslog_header=dict(required=False, type="str", default=None),
        syslog_facility=dict(required=False, type="str", default="USER", choices=['KERN', 'USER', 'MAIL',
                                                                                  'DAEMON', 'AUTH', 'SYSLOG', 'LPR',
                                                                                  'NEWS', 'UUCP', 'CRON', 'AUTHPRIV',
                                                                                  'FTP', 'LOCAL0', 'LOCAL1', 'LOCAL2',
                                                                                  'LOCAL3', 'LOCAL4', 'LOCAL5',
                                                                                  'LOCAL6', 'LOCAL7']),
        syslog_level=dict(required=False, type="str", default="INFO", choices=['EMERG', 'ALERT', 'CRIT', 'ERR',
                                                                               'WARNING', 'NOTICE',
                                                                               'INFO', 'DEBUG']),

    )
    module = AnsibleModule(argument_spec, supports_check_mode=False)

    paramgram = {
        "syslog_host": module.params["syslog_host"],
        "ignore_ssl_errors": module.params["ignore_ssl_errors"],

        "network_protocol": module.params["network_protocol"],
        "network_port": module.params["network_port"],
        "syslog_message": module.params["syslog_message"],
        "syslog_header": module.params["syslog_header"],
        "syslog_facility": module.params["syslog_facility"],
        "syslog_level": module.params["syslog_level"],
    }

    # SET THE APPROPRIATE PORT IF NOT SUPPLIED
    if paramgram["network_port"] == 0:
        if paramgram["network_protocol"] == "udp":
            paramgram["network_port"] = 514
        if paramgram["network_protocol"] == "tcp":
            paramgram["network_port"] = 1470
        if paramgram["network_protocol"] == "tcp-tls1.2":
            paramgram["network_port"] = 6514

    # GET THE PROPER VALUES FROM FACILITY AND LEVELS
    try:
        facility_search = "SyslogFacility." + str(paramgram["syslog_facility"].upper())
        paramgram["syslog_facility"] = eval(facility_search)
    except BaseException as err:
        raise FSMBaseException(msg="An error occured converted Syslog Facility to an integer. Error: " + str(err))

    try:
        level_search = "SyslogLevel." + str(paramgram["syslog_level"].upper())
        paramgram["syslog_level"] = eval(level_search)
    except BaseException as err:
        raise FSMBaseException(msg="An error occured converted Syslog Facility to an integer. Error: " + str(err))

    module.paramgram = paramgram

    # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
    fsm = None
    try:
        fsm = FortiSIEMHandler(module)
    except BaseException as err:
        raise FSMBaseException("Couldn't load FortiSIEM Handler from mod_utils. Error: " + str(err))

    if not paramgram["syslog_header"]:
        paramgram["syslog_header"] = str(fsm._tools.get_current_datetime() + " ansible_module:fsm_send_syslog")
        module.paramgram = paramgram

    # EXECUTE THE MODULE OPERATION
    results = DEFAULT_EXIT_MSG
    try:
        results = fsm.handle_syslog_request()
    except BaseException as err:
        raise FSMBaseException(err)

    return module.exit_json(msg=str(results["message"]), results=str(results["status"]))


if __name__ == "__main__":
    main()

fsm_verify_device_ip

Metadata

Name: fsm_verify_device_ip

Description: Allows a user to submit an IP address, and will return CMDB status, log status, and more. A small report regarding its logs, and monitors, are returned.

Author(s): Luke Weighall (@lweighall)

Ansible Version Added/Required: 2.8

Dev Status: No status updates, yet. Contact Authors.

Parameters
append_results_to_file
  • Description: File path you want to keep appending test results to, specifically the IP, score, and verified status
  • Required: False
export_csv_to_file_path
  • Description: When populated, an attempt to write CSV to file is made.

    An error will be thrown if this fails.

  • Required: False

  • default: None

export_json_to_file_path
  • Description: When populated, an attempt to write JSON dictionary to file is made.

    An error will be thrown if this fails.

  • Required: False

  • default: None

export_json_to_screen
  • Description: When enabled this will print the JSON results to screen.
  • Required: False
  • default: enable
  • choices: [‘enable’, ‘disable’]
export_xml_to_file_path
  • Description: When populated, an attempt to write XML to file is made.

    An error will be thrown if this fails.

  • Required: False

  • default: None

host
  • Description: The FortiSIEM’s FQDN or IP Address.
  • Required: True
ignore_ssl_errors
  • Description: When Enabled this will instruct the HTTP Libraries to ignore any ssl validation errors.
  • Required: False
  • default: enable
  • choices: [‘enable’, ‘disable’]
ip_list_file_path
  • Description: A line break-separated list of IP addresses or host names to check, stored in a file.

    Defines file path

  • Required: False

ip_list_to_verify
  • Description: A LIST of ip addresses or host names to verify in the FortiSIEM system.

    i.e. [‘10.0.0.5’, ‘10.0.0.254’]

  • Required: False

ip_to_verify
  • Description: The IP Address you would like to verify is “in” the FortiSIEM system.
  • Required: True
password
  • Description: The password associated with the username account.
  • Required: False
username
  • Description: The username used to authenticate with the FortiManager.

    organization/username format. The Organization is important, and will only return data from specified Org.

  • Required: False

Functions
  • fsm_verify_single_device
def fsm_verify_single_device(fsm, paramgram):
    """
    Function runs a list of queries, and formats the results, and then judges the device based on a number
    of factors. The result is a score, basic status, and data-entities included.

    Only works on a single IP at a time. Must be put into an external loop for a list.

    :param fsm: the FSMHandlerObject class object created in this module
    :param paramgram: the paramgram generated by the module.

    :return: dict
    """
    # LOAD UP THE XML REQUIRED AND REPLACE TOKENS
    paramgram["input_xml"] = FSMXMLGenerators.RPT_ALL_DEVICES_EVENT_TYPE_COUNTS.replace('<IP_TO_VERIFY>',
                                                                                        str(paramgram["ip_to_verify"]))

    # QUERY FOR EVENTS
    events = None
    try:
        events = fsm.handle_report_submission()
    except BaseException:
        pass

    # QUERY FOR SINGLE CMDB STATUS
    paramgram["input_xml"] = None
    paramgram["uri"] = FSMEndpoints.GET_CMDB_DETAILED_SINGLE + paramgram["ip_to_verify"] + "&loadDepend=true"
    cmdb = None
    try:
        cmdb = fsm.handle_simple_request()
    except BaseException:
        pass

    # QUERY FOR MONITORS
    paramgram["uri"] = FSMEndpoints.GET_MONITORED_DEVICES
    monitors = None
    try:
        monitors = fsm.handle_simple_request()
        monitors = fsm._tools.get_monitors_info_for_specific_ip(monitors, paramgram["ip_to_verify"])
    except BaseException:
        pass

    # CONCAT ALL THREE RESULTS INTO A SINGLE RESULTS DICT
    results = fsm.format_verify_judge_device_results(paramgram["ip_to_verify"], cmdb, events, monitors)

    return results
  • main
def main():
    argument_spec = dict(
        host=dict(required=True, type="str"),
        username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"])),
        password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True),
        ignore_ssl_errors=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_screen=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_file_path=dict(required=False, type="str"),
        export_xml_to_file_path=dict(required=False, type="str"),
        export_csv_to_file_path=dict(required=False, type="str"),

        ip_to_verify=dict(required=False, type="str"),
        ip_list_to_verify=dict(required=False, type="list"),
        ip_list_file_path=dict(required=False, type="str"),
        append_results_to_file=dict(required=False, type="str")
    )

    mutually_exclusive = ['ip_to_verify', 'ip_list_to_verify', 'ip_list_file_path']

    module = AnsibleModule(argument_spec, supports_check_mode=False, mutually_exclusive=mutually_exclusive, )

    paramgram = {
        "host": module.params["host"],
        "username": module.params["username"],
        "password": module.params["password"],
        "export_json_to_screen": module.params["export_json_to_screen"],
        "export_json_to_file_path": module.params["export_json_to_file_path"],
        "export_xml_to_file_path": module.params["export_xml_to_file_path"],
        "export_csv_to_file_path": module.params["export_csv_to_file_path"],
        "ignore_ssl_errors": module.params["ignore_ssl_errors"],

        "ip_to_verify": module.params["ip_to_verify"],
        "ip_list_to_verify": module.params["ip_list_to_verify"],
        "ip_list_file_path": module.params["ip_list_file_path"],
        "append_results_to_file": module.params["append_results_to_file"],
        "uri": FSMEndpoints.PUT_SUBMIT_REPORT,
        "input_xml": None,
        "queryId": None
    }

    module.paramgram = paramgram

    # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
    fsm = None
    results = DEFAULT_EXIT_MSG
    results_list = list()
    try:
        fsm = FortiSIEMHandler(module)
    except BaseException as err:
        raise FSMBaseException("Couldn't load FortiSIEM Handler from mod_utils. Error: " + str(err))

    if paramgram["ip_to_verify"]:
        results = fsm_verify_single_device(fsm, paramgram)

    if paramgram["ip_list_file_path"] or paramgram["ip_list_to_verify"]:
        if paramgram["ip_list_to_verify"]:
            if isinstance(paramgram["ip_list_to_verify"], list):
                for ip in paramgram["ip_list_to_verify"]:
                    if ip != "" and ip is not None:
                        paramgram["ip_to_verify"] = str(ip)
                        results_add = fsm_verify_single_device(fsm, paramgram)
                        results_list.append(results_add)

        if paramgram["ip_list_file_path"]:
            results_list = list()
            ip_list = fsm.get_file_contents(paramgram["ip_list_file_path"])
            parsed_ip_list = ip_list.split("\n")
            for ip in parsed_ip_list:
                if ip != "" and ip is not None:
                    paramgram["ip_to_verify"] = str(ip)
                    results_add = fsm_verify_single_device(fsm, paramgram)
                    results_list.append(results_add)

        results = {
            "rc": 200,
            "json_results": {"all_results": results_list},
            "xml_results": {"all_results": results_list},
        }

    # WRITE TO THE FILE IF SPECIFIED
    try:
        if paramgram["append_results_to_file"]:
            try:
                if results["json_results"]["all_results"]:
                    for result in results["json_results"]["all_results"]:
                        fsm._tools.append_file_with_device_results(result, paramgram["append_results_to_file"])
            except BaseException:
                try:
                    fsm._tools.append_file_with_device_results(results,
                                                               paramgram["append_results_to_file"])
                except BaseException as err:
                    raise FSMBaseException(msg="An issue happened writing the results to a file. Error: " + str(err))
    except BaseException as err:
        raise FSMBaseException(msg="An issue happened writing the results to a file. Error: " + str(err))

    # EXIT USING GOVERN_RESPONSE()
    fsm.govern_response(module=module, results=results, changed=False,
                        ansible_facts=fsm.construct_ansible_facts(results["json_results"],
                                                                  module.params,
                                                                  paramgram))

    return module.exit_json(msg=results)
Module Source Code
#!/usr/bin/python
#
# This file is part of Ansible
#
# Ansible 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.
#
# Ansible 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 <http://www.gnu.org/licenses/>.
#

from __future__ import absolute_import, division, print_function

__metaclass__ = type

ANSIBLE_METADATA = {
    "metadata_version": "1.1",
    "status": ["preview"],
    "supported_by": "community"
}

DOCUMENTATION = '''
---
module: fsm_verify_device_ip
version_added: "2.8"
author: Luke Weighall (@lweighall)
short_description: Checks for the existence of a device in the FortiSIEM System.
description:
  - Allows a user to submit an IP address, and will return CMDB status, log status, and more.
  - A small report regarding its logs, and monitors, are returned.

options:
  host:
    description:
      - The FortiSIEM's FQDN or IP Address.
    required: true

  username:
    description:
      - The username used to authenticate with the FortiManager.
      - organization/username format. The Organization is important, and will only return data from specified Org.
    required: false

  password:
    description:
      - The password associated with the username account.
    required: false

  ignore_ssl_errors:
    description:
      - When Enabled this will instruct the HTTP Libraries to ignore any ssl validation errors.
    required: false
    default: "enable"
    choices: ["enable", "disable"]

  export_json_to_screen:
    description:
      - When enabled this will print the JSON results to screen.
    required: false
    default: "enable"
    choices: ["enable", "disable"]

  export_json_to_file_path:
    description:
      - When populated, an attempt to write JSON dictionary to file is made.
      - An error will be thrown if this fails.
    required: false
    default: None

  export_xml_to_file_path:
    description:
      - When populated, an attempt to write XML to file is made.
      - An error will be thrown if this fails.
    required: false
    default: None

  export_csv_to_file_path:
    description:
      - When populated, an attempt to write CSV to file is made.
      - An error will be thrown if this fails.
    required: false
    default: None

  ip_to_verify:
    description:
      - The IP Address you would like to verify is "in" the FortiSIEM system.
    required: true

  ip_list_to_verify:
    description:
      - A LIST of ip addresses or host names to verify in the FortiSIEM system.
      - i.e. ['10.0.0.5', '10.0.0.254']
    required: false
    type: list

  ip_list_file_path:
    description:
      - A line break-separated list of IP addresses or host names to check, stored in a file.
      - Defines file path
    required: false

  append_results_to_file:
    description:
      - File path you want to keep appending test results to, specifically the IP, score, and verified status
    required: false
'''

EXAMPLES = '''
- name: VERIFY A DEVICE
  fsm_verify_device_ip:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    ip_to_verify: "10.0.0.5"
    export_json_to_file_path: "/root/deviceExists.json"
    append_results_to_file: "/root/verification.csv"

- name: TEST VERIFY A DEVICE THAT DOESN'T EXIST
  fsm_verify_device_ip:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    ip_to_verify: "10.0.0.45"
    export_json_to_file_path: "/root/deviceNoExist.json"
    append_results_to_file: "/root/verification.csv"
    export_json_to_screen: "enable"

- name: VERIFY A DEVICE FROM A LIST
  fsm_verify_device_ip:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    ip_list_to_verify: ["10.0.0.5", "10.0.0.10", "10.0.0.254"]
    export_json_to_file_path: "/root/deviceExistsList.json"
    append_results_to_file: "/root/verificationList.csv"

- name: VERIFY A DEVICE LIST FROM FILE
  fsm_verify_device_ip:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    ip_list_file_path: "/root/verify_list.txt"
    export_json_to_file_path: "/root/deviceExists.json"
    append_results_to_file: "/root/verificationList.csv"

'''

RETURN = """
api_result:
  description: full API response, includes status code and message
  returned: always
  type: str
"""

from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.network.fortisiem.common import FSMEndpoints
from ansible.module_utils.network.fortisiem.common import FSMBaseException
from ansible.module_utils.network.fortisiem.common import DEFAULT_EXIT_MSG
from ansible.module_utils.network.fortisiem.fortisiem import FortiSIEMHandler
from ansible.module_utils.network.fortisiem.fsm_xml_generators import FSMXMLGenerators


def fsm_verify_single_device(fsm, paramgram):
    """
    Function runs a list of queries, and formats the results, and then judges the device based on a number
    of factors. The result is a score, basic status, and data-entities included.

    Only works on a single IP at a time. Must be put into an external loop for a list.

    :param fsm: the FSMHandlerObject class object created in this module
    :param paramgram: the paramgram generated by the module.

    :return: dict
    """
    # LOAD UP THE XML REQUIRED AND REPLACE TOKENS
    paramgram["input_xml"] = FSMXMLGenerators.RPT_ALL_DEVICES_EVENT_TYPE_COUNTS.replace('<IP_TO_VERIFY>',
                                                                                        str(paramgram["ip_to_verify"]))

    # QUERY FOR EVENTS
    events = None
    try:
        events = fsm.handle_report_submission()
    except BaseException:
        pass

    # QUERY FOR SINGLE CMDB STATUS
    paramgram["input_xml"] = None
    paramgram["uri"] = FSMEndpoints.GET_CMDB_DETAILED_SINGLE + paramgram["ip_to_verify"] + "&loadDepend=true"
    cmdb = None
    try:
        cmdb = fsm.handle_simple_request()
    except BaseException:
        pass

    # QUERY FOR MONITORS
    paramgram["uri"] = FSMEndpoints.GET_MONITORED_DEVICES
    monitors = None
    try:
        monitors = fsm.handle_simple_request()
        monitors = fsm._tools.get_monitors_info_for_specific_ip(monitors, paramgram["ip_to_verify"])
    except BaseException:
        pass

    # CONCAT ALL THREE RESULTS INTO A SINGLE RESULTS DICT
    results = fsm.format_verify_judge_device_results(paramgram["ip_to_verify"], cmdb, events, monitors)

    return results


def main():
    argument_spec = dict(
        host=dict(required=True, type="str"),
        username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"])),
        password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True),
        ignore_ssl_errors=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_screen=dict(required=False, type="str", choices=["enable", "disable"], default="enable"),
        export_json_to_file_path=dict(required=False, type="str"),
        export_xml_to_file_path=dict(required=False, type="str"),
        export_csv_to_file_path=dict(required=False, type="str"),

        ip_to_verify=dict(required=False, type="str"),
        ip_list_to_verify=dict(required=False, type="list"),
        ip_list_file_path=dict(required=False, type="str"),
        append_results_to_file=dict(required=False, type="str")
    )

    mutually_exclusive = ['ip_to_verify', 'ip_list_to_verify', 'ip_list_file_path']

    module = AnsibleModule(argument_spec, supports_check_mode=False, mutually_exclusive=mutually_exclusive, )

    paramgram = {
        "host": module.params["host"],
        "username": module.params["username"],
        "password": module.params["password"],
        "export_json_to_screen": module.params["export_json_to_screen"],
        "export_json_to_file_path": module.params["export_json_to_file_path"],
        "export_xml_to_file_path": module.params["export_xml_to_file_path"],
        "export_csv_to_file_path": module.params["export_csv_to_file_path"],
        "ignore_ssl_errors": module.params["ignore_ssl_errors"],

        "ip_to_verify": module.params["ip_to_verify"],
        "ip_list_to_verify": module.params["ip_list_to_verify"],
        "ip_list_file_path": module.params["ip_list_file_path"],
        "append_results_to_file": module.params["append_results_to_file"],
        "uri": FSMEndpoints.PUT_SUBMIT_REPORT,
        "input_xml": None,
        "queryId": None
    }

    module.paramgram = paramgram

    # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
    fsm = None
    results = DEFAULT_EXIT_MSG
    results_list = list()
    try:
        fsm = FortiSIEMHandler(module)
    except BaseException as err:
        raise FSMBaseException("Couldn't load FortiSIEM Handler from mod_utils. Error: " + str(err))

    if paramgram["ip_to_verify"]:
        results = fsm_verify_single_device(fsm, paramgram)

    if paramgram["ip_list_file_path"] or paramgram["ip_list_to_verify"]:
        if paramgram["ip_list_to_verify"]:
            if isinstance(paramgram["ip_list_to_verify"], list):
                for ip in paramgram["ip_list_to_verify"]:
                    if ip != "" and ip is not None:
                        paramgram["ip_to_verify"] = str(ip)
                        results_add = fsm_verify_single_device(fsm, paramgram)
                        results_list.append(results_add)

        if paramgram["ip_list_file_path"]:
            results_list = list()
            ip_list = fsm.get_file_contents(paramgram["ip_list_file_path"])
            parsed_ip_list = ip_list.split("\n")
            for ip in parsed_ip_list:
                if ip != "" and ip is not None:
                    paramgram["ip_to_verify"] = str(ip)
                    results_add = fsm_verify_single_device(fsm, paramgram)
                    results_list.append(results_add)

        results = {
            "rc": 200,
            "json_results": {"all_results": results_list},
            "xml_results": {"all_results": results_list},
        }

    # WRITE TO THE FILE IF SPECIFIED
    try:
        if paramgram["append_results_to_file"]:
            try:
                if results["json_results"]["all_results"]:
                    for result in results["json_results"]["all_results"]:
                        fsm._tools.append_file_with_device_results(result, paramgram["append_results_to_file"])
            except BaseException:
                try:
                    fsm._tools.append_file_with_device_results(results,
                                                               paramgram["append_results_to_file"])
                except BaseException as err:
                    raise FSMBaseException(msg="An issue happened writing the results to a file. Error: " + str(err))
    except BaseException as err:
        raise FSMBaseException(msg="An issue happened writing the results to a file. Error: " + str(err))

    # EXIT USING GOVERN_RESPONSE()
    fsm.govern_response(module=module, results=results, changed=False,
                        ansible_facts=fsm.construct_ansible_facts(results["json_results"],
                                                                  module.params,
                                                                  paramgram))

    return module.exit_json(msg=results)


if __name__ == "__main__":
    main()

Playbook Examples

fsm_cmdb_devices

Playbook Task Examples
- name: GET SIMPLE DEVICE LIST FROM CMDB
  fsm_cmdb_devices:
    host: "10.0.0.15"
    username: "super/api_user"
    password: "Fortinet!1"
    ignore_ssl_errors: "enable"
    mode: "short_all"

- name: GET SIMPLE DEVICE LIST FROM CMDB IP RANGE
  fsm_cmdb_devices:
    host: "10.0.0.15"
    username: "super/api_user"
    password: "Fortinet!1"
    ignore_ssl_errors: "enable"
    mode: "ip_range"
    ip_range: "10.0.0.100-10.0.0.120"

- name: GET DETAILED INFO ON ONE DEVICE
  fsm_cmdb_devices:
    host: "10.0.0.15"
    username: "super/api_user"
    password: "Fortinet!1"
    ignore_ssl_errors: "enable"
    mode: "detailed_single"
    ip: "10.0.0.5"
Playbook File Examples
fsm_get_cmdb_devices_simple.yml
- name: GET CMDB DEVICES
  hosts: FortiSIEM
  connection: local
  gather_facts: False

  tasks:
    - name: GET SIMPLE DEVICE LIST FROM CMDB
      fsm_cmdb_devices:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "short_all"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/simple_cmdb_list.json"
        export_xml_to_file_path: "/root/simple_cmdb_list.xml"

    - name: GET SIMPLE DEVICE LIST FROM CMDB IP RANGE
      fsm_cmdb_devices:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "ip_range"
        ip_range: "10.0.0.100-10.0.0.120"

    - name: GET DETAILED INFO ON ONE DEVICE
      fsm_cmdb_devices:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "detailed_single"
        ip: "10.0.0.5"
fsm_msp_get_cmdb_devices_simple.yml
- name: GET MSP CMDB DEVICES
  hosts: FortiSIEM_MSP
  connection: local
  gather_facts: False

  tasks:
    - name: GET MSP SIMPLE DEVICE LIST FROM CMDB
      fsm_cmdb_devices:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "short_all"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/msp_testOrg_simpleDeviceList.json"
        export_xml_to_file_path: "/root/msp_testOrg_xml_simpleDeviceList.xml"


    - name: GET MSP SIMPLE DEVICE LIST FROM CMDB IP RANGE
      fsm_cmdb_devices:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "ip_range"
        ip_range: "10.0.0.1-10.0.0.255"

    - name: GET MSP DETAILED INFO ON ONE DEVICE
      fsm_cmdb_devices:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "detailed_single"
        ip: "10.7.220.34"

fsm_credentials

Playbook Task Examples
- name: ADD AN SSH CREDENTIAL
  fsm_credentials:
    host: "10.0.0.15"
    username: "super/api_user"
    password: "Fortinet!1"
    ignore_ssl_errors: "enable"
    cred_username: "fortinet"
    cred_password: "fortinet123!"
    access_protocol: "ssh"
    friendly_name: "AnsibleTestSSHCred"
    mode: "add"

- name: ADD AN SSH CREDENTIAL FOR ELEVATED DEVICE
  fsm_credentials:
    host: "10.0.0.15"
    username: "super/api_user"
    password: "Fortinet!1"
    ignore_ssl_errors: "enable"
    cred_username: "fortinet"
    cred_password: "fortinet123!"
    super_username: "fortinet_super"
    super_password: "fortinet321!"
    access_protocol: "ssh"
    friendly_name: "AnsibleTestCiscoCred"
    mode: "add"
    ip_range: "10.0.254.1-10.0.254.255"

- name: ADD AN VM_SDK CREDENTIAL
  fsm_credentials:
    host: "10.0.0.15"
    username: "super/api_user"
    password: "Fortinet!1"
    ignore_ssl_errors: "enable"
    cred_username: "fortinet"
    cred_password: "fortinet123!"
    access_protocol: "vm_sdk"
    friendly_name: "AnsibleTestVMSDKCred"
    mode: "add"

- name: MSP UPDATE AN SSH CREDENTIAL
  fsm_credentials:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    cred_username: "fortinet"
    cred_password: "fortinet123!123"
    access_protocol: "ssh"
    description: "AnsibleTestSSHCredUPDATE"
    mode: "update"
    friendly_name: "AnsibleTestSSHCred"
    ip_range: "10.7.220.100"
Playbook File Examples
fsm_add_access_methods.yml
- name: ADD ACCESS METHODS
  hosts: FortiSIEM
  connection: local
  gather_facts: False

  tasks:
  - name: ADD AN SSH CREDENTIAL FROM FILE
    fsm_credentials:
      host: "{{ inventory_hostname }}"
      username: "{{ username }}"
      password: "{{ password }}"
      ignore_ssl_errors: "enable"
      input_xml_file: "creds2.xml"
      mode: "add"

  - name: ADD AN VM_SDK CREDENTIAL
    fsm_credentials:
      host: "{{ inventory_hostname }}"
      username: "{{ username }}"
      password: "{{ password }}"
      ignore_ssl_errors: "enable"
      cred_username: "fortinet"
      cred_password: "fortinet123!"
      access_protocol: "vm_sdk"
      friendly_name: "AnsibleTestVMSDKCred"
      description: "Created by api_user, and Ansible."
      mode: "add"

  - name: ADD AN SSH CREDENTIAL FOR ELEVATED DEVICE
    fsm_credentials:
      host: "{{ inventory_hostname }}"
      username: "{{ username }}"
      password: "{{ password }}"
      ignore_ssl_errors: "enable"
      cred_username: "fortinet"
      cred_password: "fortinet123!"
      super_password: "fortinet321!"
      access_protocol: "ssh"
      friendly_name: "AnsibleTestCiscoCred"
      description: "Created by api_user, and Ansible."
      mode: "add"

  - name: ADD AN FTP CREDENTIAL
    fsm_credentials:
      host: "{{ inventory_hostname }}"
      username: "{{ username }}"
      password: "{{ password }}"
      ignore_ssl_errors: "enable"
      cred_username: "fortinet_ftp"
      cred_password: "fortinet123!"
      access_protocol: "ftp"
      friendly_name: "AnsibleTestFTPCred"
      description: "Created by api_user, and Ansible."
      mode: "add"

  - name: ADD AN FTP OVER SLL CREDENTIAL
    fsm_credentials:
      host: "{{ inventory_hostname }}"
      username: "{{ username }}"
      password: "{{ password }}"
      ignore_ssl_errors: "enable"
      cred_username: "fortinet_ftp"
      cred_password: "fortinet123!"
      access_protocol: "ftp_over_ssl"
      friendly_name: "AnsibleTestFTPSSLCred"
      description: "Created by api_user, and Ansible."
      mode: "add"

  - name: ADD AN IMAP CREDENTIAL
    fsm_credentials:
      host: "{{ inventory_hostname }}"
      username: "{{ username }}"
      password: "{{ password }}"
      ignore_ssl_errors: "enable"
      cred_username: "fortinet_imap"
      cred_password: "fortinet123!"
      access_protocol: "imap"
      friendly_name: "AnsibleTestIMAPCred"
      description: "Created by api_user, and Ansible."
      mode: "add"


  - name: ADD AN IMAP OVER SSL CREDENTIAL
    fsm_credentials:
      host: "{{ inventory_hostname }}"
      username: "{{ username }}"
      password: "{{ password }}"
      ignore_ssl_errors: "enable"
      cred_username: "fortinet_imapssl"
      cred_password: "fortinet123!"
      access_protocol: "imap_over_ssl"
      friendly_name: "AnsibleTestIMAPSSLCred"
      description: "Created by api_user, and Ansible."
      mode: "add"

  - name: ADD AN JDBC CREDENTIAL
    fsm_credentials:
      host: "{{ inventory_hostname }}"
      username: "{{ username }}"
      password: "{{ password }}"
      ignore_ssl_errors: "enable"
      cred_username: "fortinet_jdbc"
      cred_password: "fortinet123!"
      access_protocol: "jdbc"
      friendly_name: "AnsibleTestJDBCCred"
      description: "Created by api_user, and Ansible."
      mode: "add"

  - name: ADD AN JMX CREDENTIAL
    fsm_credentials:
      host: "{{ inventory_hostname }}"
      username: "{{ username }}"
      password: "{{ password }}"
      ignore_ssl_errors: "enable"
      cred_username: "fortinet_jmx"
      cred_password: "fortinet123!"
      access_protocol: "jmx"
      friendly_name: "AnsibleTestJMXCred"
      description: "Created by api_user, and Ansible."
      mode: "add"

  - name: ADD AN POP3 CREDENTIAL
    fsm_credentials:
      host: "{{ inventory_hostname }}"
      username: "{{ username }}"
      password: "{{ password }}"
      ignore_ssl_errors: "enable"
      cred_username: "fortinet_pop3"
      cred_password: "fortinet123!"
      access_protocol: "pop3"
      friendly_name: "AnsibleTestPOP3Cred"
      description: "Created by api_user, and Ansible."
      mode: "add"

  - name: ADD AN POP3 OVER SSL CREDENTIAL
    fsm_credentials:
      host: "{{ inventory_hostname }}"
      username: "{{ username }}"
      password: "{{ password }}"
      ignore_ssl_errors: "enable"
      cred_username: "fortinet_pop3ssl"
      cred_password: "fortinet123!"
      access_protocol: "pop3_over_ssl"
      friendly_name: "AnsibleTestPOP3SSLCred"
      description: "Created by api_user, and Ansible."
      mode: "add"

  - name: ADD AN smtp CREDENTIAL
    fsm_credentials:
      host: "{{ inventory_hostname }}"
      username: "{{ username }}"
      password: "{{ password }}"
      ignore_ssl_errors: "enable"
      cred_username: "fortinet_smtp"
      cred_password: "fortinet123!"
      access_protocol: "smtp"
      friendly_name: "AnsibleTestSMTPCred"
      description: "Created by api_user, and Ansible."
      mode: "add"

  - name: ADD AN smtp_over_ssl CREDENTIAL
    fsm_credentials:
      host: "{{ inventory_hostname }}"
      username: "{{ username }}"
      password: "{{ password }}"
      ignore_ssl_errors: "enable"
      cred_username: "fortinet_smtp_over_ssl"
      cred_password: "fortinet123!"
      access_protocol: "smtp_over_ssl"
      friendly_name: "AnsibleTestsmtp_over_sslCred"
      description: "Created by api_user, and Ansible."
      mode: "add"

  - name: ADD AN smtp_over_tls CREDENTIAL
    fsm_credentials:
      host: "{{ inventory_hostname }}"
      username: "{{ username }}"
      password: "{{ password }}"
      ignore_ssl_errors: "enable"
      cred_username: "fortinet_smtp_over_tls"
      cred_password: "fortinet123!"
      access_protocol: "smtp_over_tls"
      friendly_name: "AnsibleTestsmtp_over_tlsCred"
      description: "Created by api_user, and Ansible."
      mode: "add"

  - name: ADD AN FTP CREDENTIAL
    fsm_credentials:
      host: "{{ inventory_hostname }}"
      username: "{{ username }}"
      password: "{{ password }}"
      ignore_ssl_errors: "enable"
      cred_username: "fortinet_ftp"
      cred_password: "fortinet123!"
      access_protocol: "ftp"
      friendly_name: "AnsibleTestFTPCred"
      description: "Created by api_user, and Ansible."
      mode: "add"

  - name: ADD AN telnet CREDENTIAL
    fsm_credentials:
      host: "{{ inventory_hostname }}"
      username: "{{ username }}"
      password: "{{ password }}"
      ignore_ssl_errors: "enable"
      cred_username: "fortinet_telnet"
      cred_password: "fortinet123!"
      access_protocol: "telnet"
      friendly_name: "AnsibleTesttelnetred"
      description: "Created by api_user, and Ansible."
      mode: "add"
fsm_msp_update_access_methods.yml
- name: MSP UPDATE ACCESS METHODS
  hosts: FortiSIEM_MSP
  connection: local
  gather_facts: False

  tasks:
  - name: MSP UPDATE AN SSH CREDENTIAL
    fsm_credentials:
      host: "{{ inventory_hostname }}"
      username: "{{ username }}"
      password: "{{ password }}"
      ignore_ssl_errors: "enable"
      cred_username: "fortinet"
      cred_password: "fortinet123!123"
      access_protocol: "ssh"
      description: "AnsibleTestSSHCredUPDATE"
      mode: "update"
      friendly_name: "AnsibleTestSSHCred"
      ip_range: "10.7.220.100"

  - name: MSP UPDATE AN SSH CREDENTIAL TEST ORG
    fsm_credentials:
      host: "{{ inventory_hostname }}"
      username: "adfs/api_user"
      password: "{{ password }}"
      ignore_ssl_errors: "enable"
      cred_username: "fortinet"
      cred_password: "fortinet123!123"
      access_protocol: "ssh"
      description: "AnsibleTestSSHCredUPDATE"
      mode: "update"
      friendly_name: "AnsibleTestSSHCred"
      ip_range: "10.7.220.100"
fsm_get_access_methods.yml
- name: GET ACCESS METHODS
  hosts: FortiSIEM
  connection: local
  gather_facts: False

  tasks:
  - name: GET ALL CREDENTIALS
    fsm_credentials:
      host: "{{ inventory_hostname }}"
      username: "{{ username }}"
      password: "{{ password }}"
      ignore_ssl_errors: "enable"
      mode: "get"
creds2.xml
       <accessConfigs>
    <accessMethods>
        <accessMethod>
            <name>AnsibleTestSSHCred</name>
            <accessProtocol>SSH</accessProtocol>
            <description/>
            <pwdType>Manual</pwdType>
            <baseDN/>
            <pullInterval>5</pullInterval>
            <credential>
                <password>fortinet</password>
                <principal>fortinet</principal>
                <suPassword/>
            </credential>
            <deviceType>
                <model>Generic</model>
                <vendor>Generic</vendor>
                <version>ANY</version>
            </deviceType>
        </accessMethod>
    </accessMethods>
    <ipAccessMappings>
        <ipAccessMapping>
            <ipRange>10.0.0.5</ipRange>
        </ipAccessMapping>
    </ipAccessMappings>
</accessConfigs>
fsm_msp_get_access_methods.yml
- name: MSP GET ACCESS METHODS
  hosts: FortiSIEM_MSP
  connection: local
  gather_facts: False

  tasks:
  - name: MSP GET ALL CREDENTIALS
    fsm_credentials:
      host: "{{ inventory_hostname }}"
      username: "{{ username }}"
      password: "{{ password }}"
      ignore_ssl_errors: "enable"
      mode: "get"
creds3_output_msp_dual_collector.xml
       <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<accessConfigs>
    <accessMethods>
        <accessMethod creationTime="1557441071533" custId="2056" entityVersion="0" id="2305600"
                      lastModified="1557441071533" ownerId="500151" xmlId="AccessMethod@2305600">
            <accessProtocol>FTP</accessProtocol>
            <baseDN/>
            <caAddress>false</caAddress>
            <description/>
            <name>test123</name>
            <port>21</port>
            <pullInterval>5</pullInterval>
            <pwdType>Manual</pwdType>
            <useLDAP>false</useLDAP>
            <credential creationTime="1557441071534" custId="2056" entityVersion="0" id="2305650"
                        lastModified="1557441071534" ownerId="0" xmlId="Credential@2305650">
                <password>AES$83173CC2D07E45B1548CD9F0F4592C2B</password>
                <principal>test</principal>
                <suPassword/>
            </credential>
            <deviceType creationTime="1555436989024" custId="0" entityVersion="1" id="794651"
                        lastModified="1556344621972" ownerId="0" xmlId="DeviceType@794651">
                <type>Appliance</type>
                <eventParsed>false</eventParsed>
                <jobWeight>10</jobWeight>
                <model>Generic</model>
                <objectGroup>PH_SYS_DEVICE_GENERIC</objectGroup>
                <priority>0</priority>
                <sysDefined>true</sysDefined>
                <vendor>Generic</vendor>
                <version>ANY</version>
            </deviceType>
        </accessMethod>
    </accessMethods>
    <ipAccessMappings>
        <ipAccessMapping creationTime="1557441080093" custId="2056" entityVersion="0" id="2305700"
                         lastModified="1557441080093" ownerId="0" xmlId="IpAccessMapping@2305700">
            <collectorId>10034</collectorId>
            <accessMethodId>2305600</accessMethodId>
            <ipRange>10.1.1.1</ipRange>
        </ipAccessMapping>
        <ipAccessMapping creationTime="1557441088108" custId="2056" entityVersion="0" id="2305701"
                         lastModified="1557441088108" ownerId="0" xmlId="IpAccessMapping@2305701">
            <collectorId>10035</collectorId>
            <accessMethodId>2305600</accessMethodId>
            <ipRange>10.0.0.2</ipRange>
        </ipAccessMapping>
    </ipAccessMappings>
</accessConfigs>
creds.xml
       <accessConfigs>
    <accessMethods>
        <accessMethod>
            <accessProtocol>MS_WMI</accessProtocol>
            <baseDN/>
            <description/>
            <name>MS-WMI-Domain_ABC</name>
            <port/>
            <pwdType>Manual</pwdType>
            <pullInterval>5</pullInterval>
            <credential>
                <password>abc</password>
                <principal>ABC/user123</principal>
                <suPassword/>
            </credential>
            <deviceType >
                <accessProtocols>MS_RPC,MS_WMI,LDAP</accessProtocols>
                <model>Windows</model>
                <vendor>Microsoft</vendor>
                <version>ANY</version>
            </deviceType>
        </accessMethod>
    </accessMethods>
    <ipAccessMappings>
        <ipAccessMapping>
            <ipRange>1.1.1.1</ipRange>
        </ipAccessMapping>
    </ipAccessMappings>
</accessConfigs>
fsm_msp_add_access_methods.yml
- name: MSP ADD ACCESS METHODS
  hosts: FortiSIEM_MSP
  connection: local
  gather_facts: False

  tasks:
  - name: MSP ADD AN SSH CREDENTIAL
    fsm_credentials:
      host: "{{ inventory_hostname }}"
      username: "{{ username }}"
      password: "{{ password }}"
      ignore_ssl_errors: "enable"
      cred_username: "fortinet"
      cred_password: "fortinet123!"
      access_protocol: "ssh"
      description: "AnsibleTestSSHCred"
      mode: "add"
      friendly_name: "AnsibleTestSSHCred"

  - name: MSP ADD AN SSH CREDENTIAL TEST ORG
    fsm_credentials:
      host: "{{ inventory_hostname }}"
      username: "adfs/api_user"
      password: "{{ password }}"
      ignore_ssl_errors: "enable"
      cred_username: "fortinet"
      cred_password: "fortinet123!"
      access_protocol: "ssh"
      description: "AnsibleTestSSHCred"
      mode: "add"
      friendly_name: "AnsibleTestSSHCred"

fsm_custom_query

Playbook Task Examples
- name: SIMPLE CUSTOM QUERY FOR ORGANIZATIONS
  fsm_custom_query:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "get"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/custom_query1.json"
    export_xml_to_file_path: "/root/custom_query1.xml"
    uri: "/phoenix/rest/config/Domain"
Playbook File Examples
fsm_custom_query1.yml
- name: CUSTOM QUERIES
  hosts: FortiSIEM
  connection: local
  gather_facts: False

  tasks:
    - name: SIMPLE CUSTOM QUERY TO CMDB
      fsm_custom_query:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "get"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/custom_query1.json"
        export_xml_to_file_path: "/root/custom_query1.xml"
        uri: "/phoenix/rest/config/Domain"

fsm_device_monitors

Playbook Task Examples
- name: GET SIMPLE MONITOR LIST FROM CMDB
  fsm_device_monitors:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "short_all"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/monitors_out1.json"
    export_xml_to_file_path: "/root/monitors_out1.xml"

- name: GET SIMPLE MONITOR LIST FROM CMDB IP RANGE
  fsm_device_monitors:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "ip_range"
    ip_range: "10.0.0.5-10.0.0.15"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/monitors_out2.json"
    export_xml_to_file_path: "/root/monitors_out2.xml"

- name: GET DETAILED MONITOR INFO ON ONE DEVICE
  fsm_device_monitors:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "detailed_single"
    ip: "10.0.0.5"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/monitors_out3.json"
    export_xml_to_file_path: "/root/monitors_out3.xml"
Playbook File Examples
enable_monitors.xml
       <configureMonitoring>
    <systemMonitors>
        <systemMonitor ip = "10.0.0.5" method = "SNMP" type = "CPU Util" enable = "true" interval = "120"/>
        <systemMonitor ip = "10.0.0.5" method = "VMSDK" type = "VMware Hardware Status" enable = "true" interval = "120"/>
    </systemMonitors>
    <eventPullingObjs>
        <eventPullingObj ip="10.0.0.10" method="VM_SDK" enable="true"/>
        <eventPullingObj ip="10.0.0.138" method="MS_WMI" enable="true"/>
    </eventPullingObjs>
</configureMonitoring>
disable_monitors.xml
       <configureMonitoring>
    <systemMonitors>
        <systemMonitor ip = "10.0.0.5" method = "SNMP" type = "CPU Util" enable = "false" interval = "120"/>
        <systemMonitor ip = "10.0.0.5" method = "VMSDK" type = "VMware Hardware Status" enable = "false" interval = "120"/>
    </systemMonitors>
    <eventPullingObjs>
        <eventPullingObj ip="10.0.0.10" method="VM_SDK" enable="false"/>
        <eventPullingObj ip="10.0.0.138" method="MS_WMI" enable="false"/>
    </eventPullingObjs>
</configureMonitoring>
fsm_get_monitors.yml
- name: GET DEVICE MONITORS
  hosts: FortiSIEM
  connection: local
  gather_facts: False

  tasks:
    - name: GET SIMPLE MONITOR LIST FROM CMDB
      fsm_device_monitors:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "short_all"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/monitors_out1.json"
        export_xml_to_file_path: "/root/monitors_out1.xml"

    - name: GET SIMPLE MONITOR LIST FROM CMDB IP RANGE
      fsm_device_monitors:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "ip_range"
        ip_range: "10.0.0.5-10.0.0.15"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/monitors_out2.json"
        export_xml_to_file_path: "/root/monitors_out2.xml"

    - name: GET DETAILED MONITOR INFO ON ONE DEVICE
      fsm_device_monitors:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "detailed_single"
        ip: "10.0.0.5"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/monitors_out3.json"
        export_xml_to_file_path: "/root/monitors_out3.xml"
fsm_update_monitors.yml
- name: GET DEVICE MONITORS
  hosts: FortiSIEM
  connection: local
  gather_facts: False

  tasks:
    - name: DISABLE MONITORS
      fsm_device_monitors:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "update"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/disable_monitors.json"
        export_xml_to_file_path: "/root/disable_monitors.xml"
        update_xml_file: "/root/git/dev_queue/examples/fsm_device_monitors/disable_monitors.xml"

#    - name: ENABLE MONITORS
#      fsm_device_monitors:
#        host: "{{ inventory_hostname }}"
#        username: "{{ username }}"
#        password: "{{ password }}"
#        ignore_ssl_errors: "enable"
#        mode: "update"
#        export_json_to_screen: "enable"
#        export_json_to_file_path: "/root/enable_monitors.json"
#        export_xml_to_file_path: "/root/enable_monitors.xml"
#        update_xml_file: "/root/git/dev_queue/examples/fsm_device_monitors/enable_monitors.xml"

fsm_discovery

Playbook Task Examples
- name: SUBMIT RANGE SCAN FOR SINGLE DEVICE
  fsm_discovery:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/range_scan.json"
    export_xml_to_file_path: "/root/range_scan.xml"
    type: "RangeScan"
    include_range: "10.0.0.254"

- name: SUBMIT RANGE SCAN FOR SINGLE DEVICE AND WAIT FOR FINISH WITH MANY OPTIONS
  fsm_discovery:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/range_scan2.json"
    export_xml_to_file_path: "/root/range_scan2.xml"
    type: "RangeScan"
    include_range: "10.0.0.5-10.0.0.20"
    wait_to_finish: True
    only_ping: False
    vm_off: True
    unmanaged: True
    delta: True
    name_resolution_dns_first: False
    winexe_based: True
    vm_templates: True
    discover_routes: True
    monitor_win_events: False
    monitor_win_patches: False
    monitor_installed_sw: False

- name: SUBMIT RANGE SCAN FOR SINGLE DEVICE AND WAIT FOR FINISH WITH NO PING
  fsm_discovery:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/json_test_out.json"
    export_xml_to_file_path: "/root/xml_test_out.xml"
    type: "RangeScan"
    include_range: "10.0.0.5-10.0.0.50"
    wait_to_finish: True
    no_ping: True


- name: SUBMIT RANGE SCAN FOR RANGE OF DEVICES
  fsm_discovery:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/json_test_out.json"
    export_xml_to_file_path: "/root/xml_test_out.xml"
    type: "RangeScan"
    include_range: "10.0.0.1-10.0.0.10"
    exclude_range: "10.0.0.5-10.0.0.6"

- name: SUBMIT SMART SCAN
  fsm_discovery:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/json_test_out.json"
    export_xml_to_file_path: "/root/xml_test_out.xml"
    type: "SmartScan"
    root_ip: "10.0.0.254"

- name: SUBMIT L2SCAN
  fsm_discovery:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/json_test_out.json"
    export_xml_to_file_path: "/root/xml_test_out.xml"
    type: "L2Scan"
    include_range: "10.0.0.1-10.0.0.254"
Playbook File Examples
fsm_discovery_add.yml
- name: SUBMIT DISCOVERY JOBS
  hosts: FortiSIEM
  connection: local
  gather_facts: False

  tasks:
    - name: SUBMIT RANGE SCAN FOR SINGLE DEVICE
      fsm_discovery:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/range_scan.json"
        export_xml_to_file_path: "/root/range_scan.xml"
        type: "RangeScan"
        include_range: "10.0.0.254"

    - name: SUBMIT RANGE SCAN FOR SINGLE DEVICE AND WAIT FOR FINISH WITH MANY OPTIONS
      fsm_discovery:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/range1_scan_opt.json"
        export_xml_to_file_path: "/root/range1_scan_opt.xml"
        type: "RangeScan"
        include_range: "10.0.0.5-10.0.0.20"
        wait_to_finish: True
        only_ping: False
        vm_off: True
        unmanaged: True
        delta: True
        name_resolution_dns_first: False
        winexe_based: True
        vm_templates: True
        discover_routes: True
        monitor_win_events: False
        monitor_win_patches: False
        monitor_installed_sw: False

    - name: SUBMIT RANGE SCAN FOR SINGLE DEVICE AND WAIT FOR FINISH WITH NO PING
      fsm_discovery:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/range_scan_no_ping.json"
        export_xml_to_file_path: "/root/range_scan_no_ping.xml"
        type: "RangeScan"
        include_range: "10.0.0.5-10.0.0.50"
        wait_to_finish: True
        no_ping: True


    - name: SUBMIT RANGE SCAN FOR RANGE OF DEVICES
      fsm_discovery:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/range_scan_range.json"
        export_xml_to_file_path: "/root/range_scan_range.xml"
        type: "RangeScan"
        include_range: "10.0.0.1-10.0.0.10"
        exclude_range: "10.0.0.5-10.0.0.6"

    - name: SUBMIT SMART SCAN
      fsm_discovery:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/smart_scan_01.json"
        export_xml_to_file_path: "/root/smart_scan_01.xml"
        type: "SmartScan"
        root_ip: "10.0.0.254"

    - name: SUBMIT L2SCAN
      fsm_discovery:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/l2scan.json"
        export_xml_to_file_path: "/root/l2scan.xml"
        type: "L2Scan"
        include_range: "10.0.0.1-10.0.0.254"
fsm_discovery_status.yml
- name: STATUS DISCOVERY JOBS
  hosts: FortiSIEM
  connection: local
  gather_facts: False

  tasks:
    - name: GET STATUS FOR A DISCOVERY
      fsm_discovery:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/disco_status.json"
        export_xml_to_file_path: "/root/disco_status.xml"
        type: "status"
        task_id: "2508033"

fsm_maintenance

Playbook Task Examples
- name: SET BASIC MAINT SCHEDULE
   fsm_maintenance:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "add"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/json_main_1.json"
    export_xml_to_file_path: "/root/xml_main_1.json"
    name: "testMaintAnsible1"
    description: "created by ansible test workbook"
    devices: "10.0.0.5"
    fire_incidents: False
    time_zone_id: "Americas/Los_Angeles"
    start_hour: "08"
    start_min: "30"
    duration: "380"
    time_zone: "-8"
    start_date: "2019-05-02"
    end_date: "2019-05-10"

- name: SET BASIC MAINT SCHEDULE w/ open end date
  fsm_maintenance:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "add"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/json_main_2.json"
    export_xml_to_file_path: "/root/xml_main_2.json"
    name: "testMaintAnsible2"
    description: "created by ansible test workbook"
    devices: "10.0.0.5"
    fire_incidents: False
    time_zone_id: "Americas/Los_Angeles"
    start_hour: "08"
    start_min: "30"
    duration: "380"
    time_zone: "-8"
    start_date: "2019-05-02"
    end_date_open: True

- name: SET BASIC MAINT SCHEDULE w/ open end date 2
  fsm_maintenance:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "add"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/json_main_3.json"
    export_xml_to_file_path: "/root/xml_main_3.json"
    name: "testMaintAnsible4"
    description: "created by ansible test workbook"
    groups: "Firewall"
    fire_incidents: False
    time_zone_id: "Americas/Los_Angeles"
    start_hour: "08"
    start_min: "30"
    duration: "380"
    time_zone: "-8"
    start_date: "2019-05-02"
    end_date_open: True


- name: SET BASIC MAINT SCHEDULE VIA INPUT FILE
  fsm_maintenance:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "add"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/json_main_4.json"
    export_xml_to_file_path: "/root/xml_main_4.json"
    input_xml_file: "/root/scheduleDef.xml"

- name: DELETE SCHEDULE THAT MATCHES AN XML FILE
  fsm_maintenance:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "delete"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/json_main_1.json"
    export_xml_to_file_path: "/root/xml_main_1.json"
    input_xml_file: "/root/scheduleDef.xml"

- name: DELETE BASED ON NAME
  fsm_maintenance:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "delete"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/json_main_2_del.json"
    export_xml_to_file_path: "/root/xml_main_2_del.json"
    name: "testMaintAnsible1"
    description: "created by ansible test workbook"
    devices: "10.0.0.5"
    fire_incidents: False
    time_zone_id: "Americas/Los_Angeles"
    start_hour: "08"
    start_min: "30"
    duration: "380"
    time_zone: "-8"
    start_date: "2019-05-02"
    end_date: "2019-05-10"

- name: SET BASIC MAINT SCHEDULE w/ open end date 2
  fsm_maintenance:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "delete"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/json_main_3_del.json"
    export_xml_to_file_path: "/root/xml_main_3_del.json"
    name: "testMaintAnsible4"
    description: "created by ansible test workbook"
    groups: "Firewall"
    fire_incidents: False
    time_zone_id: "Americas/Los_Angeles"
    start_hour: "08"
    start_min: "30"
    duration: "380"
    time_zone: "-8"
    start_date: "2019-05-02"
    end_date_open: True

- name: DELETE BASED ON NAME 2
  fsm_maintenance:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "delete"
    export_json_to_screen: "enable"
    export_json_to_file_path: "/root/json_main_3_del.json"
    export_xml_to_file_path: "/root/xml_main_3_del.json"
    name: "testMaintAnsible2"
    description: "created by ansible test workbook"
    devices: "10.0.0.5"
    fire_incidents: False
    time_zone_id: "Americas/Los_Angeles"
    start_hour: "08"
    start_min: "30"
    duration: "380"
    time_zone: "-8"
    start_date: "2019-05-02"
    end_date_open: True
Playbook File Examples
fsm_maintenance_del.yml
- name: SET MAINTENENCE SCHEDULES
  hosts: FortiSIEM
  connection: local
  gather_facts: False

  tasks:
    - name: DELETE SCHEDULE THAT MATCHES AN XML FILE
      fsm_maintenance:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "delete"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/json_main_1.json"
        export_xml_to_file_path: "/root/xml_main_1.xml"
        input_xml_file: "/root/scheduleDef.xml"

    - name: DELETE BASED ON NAME
      fsm_maintenance:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "delete"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/json_main_2_del.json"
        export_xml_to_file_path: "/root/xml_main_2_del.xml"
        name: "testMaintAnsible1"
        description: "created by ansible test workbook"
        devices: "10.0.0.5"
        fire_incidents: False
        time_zone_id: "Americas/Los_Angeles"
        start_hour: "08"
        start_min: "30"
        duration: "380"
        time_zone: "-8"
        start_date: "2019-05-02"
        end_date: "2019-05-10"

    - name: SET BASIC MAINT SCHEDULE w/ open end date 2
      fsm_maintenance:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "delete"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/json_main_3_del.json"
        export_xml_to_file_path: "/root/xml_main_3_del.xml"
        name: "testMaintAnsible4"
        description: "created by ansible test workbook"
        groups: "Firewall"
        fire_incidents: False
        time_zone_id: "Americas/Los_Angeles"
        start_hour: "08"
        start_min: "30"
        duration: "380"
        time_zone: "-8"
        start_date: "2019-05-02"
        end_date_open: True

    - name: DELETE BASED ON NAME 2
      fsm_maintenance:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "delete"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/json_main_3_del.json"
        export_xml_to_file_path: "/root/xml_main_3_del.xml"
        name: "testMaintAnsible2"
        description: "created by ansible test workbook"
        devices: "10.0.0.5"
        fire_incidents: False
        time_zone_id: "Americas/Los_Angeles"
        start_hour: "08"
        start_min: "30"
        duration: "380"
        time_zone: "-8"
        start_date: "2019-05-02"
        end_date_open: True
fsm_maintenance_add.yml
- name: SET MAINTENENCE SCHEDULES
  hosts: FortiSIEM
  connection: local
  gather_facts: False

  tasks:
    - name: SET BASIC MAINT SCHEDULE
      fsm_maintenance:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "add"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/json_main_1.json"
        export_xml_to_file_path: "/root/xml_main_1.xml"
        name: "testMaintAnsible1"
        description: "created by ansible test workbook"
        devices: "10.0.0.5"
        fire_incidents: False
        time_zone_id: "Americas/Los_Angeles"
        start_hour: "08"
        start_min: "30"
        duration: "380"
        time_zone: "-8"
        start_date: "2019-05-02"
        end_date: "2019-05-10"

    - name: SET BASIC MAINT SCHEDULE w/ open end date
      fsm_maintenance:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "add"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/json_main_2.json"
        export_xml_to_file_path: "/root/xml_main_2.xml"
        name: "testMaintAnsible2"
        description: "created by ansible test workbook"
        devices: "10.0.0.5"
        fire_incidents: False
        time_zone_id: "Americas/Los_Angeles"
        start_hour: "08"
        start_min: "30"
        duration: "380"
        time_zone: "-8"
        start_date: "2019-05-02"
        end_date_open: True

    - name: SET BASIC MAINT SCHEDULE w/ open end date 2
      fsm_maintenance:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "add"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/json_main_3.json"
        export_xml_to_file_path: "/root/xml_main_3.xml"
        name: "testMaintAnsible4"
        description: "created by ansible test workbook"
        groups: "Firewall"
        fire_incidents: False
        time_zone_id: "Americas/Los_Angeles"
        start_hour: "08"
        start_min: "30"
        duration: "380"
        time_zone: "-8"
        start_date: "2019-05-02"
        end_date_open: True


    - name: SET BASIC MAINT SCHEDULE VIA INPUT FILE
      fsm_maintenance:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "add"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/json_main_4.json"
        export_xml_to_file_path: "/root/xml_main_4.xml"
        input_xml_file: "/root/scheduleDef.xml"

fsm_organizations

Playbook Task Examples
- name: GET LIST OF ORGS
  fsm_organizations:
    host: "10.0.0.15"
    username: "super/api_user"
    password: "Fortinet!1"
    ignore_ssl_errors: "enable"

- name: ADD AN ORG WITH COLLECTOR VIA PARAMETERS
  fsm_organizations:
    host: "10.7.220.61"
    username: "super/api_user"
    password: "Fortinet!1"
    ignore_ssl_errors: "enable"
    mode: "add"
    org_name: "ansibleOrg1"
    org_display_name: "Ansible Test Org 1"
    org_description: "Testing Ansible. Duh."
    org_admin_username: "ansibleTest1"
    org_admin_password: "admin*1"
    org_admin_email: "ansible@test1.com"
    org_eps: "500"
    org_include_ip_range: "192.168.10.1-192.168.10.50"
    org_exclude_ip_range: "192.168.10.51-192.168.10.255"
    org_collector_name: "ansibleOrg1Col1"
    org_collector_eps: "200"
    org_max_devices: 5

- name: ADD AN ORG WITH COLLECTOR VIA JSON
  fsm_organizations:
    host: "10.7.220.61"
    username: "super/api_user"
    password: "Fortinet!1"
    ignore_ssl_errors: "enable"
    mode: "add"
    org_name: "ansibleOrg2"
    org_display_name: "Ansible Test Org 2"
    org_description: "Testing Ansible. Duh. Again."
    org_admin_username: "ansibleTest2"
    org_admin_password: "admin*1"
    org_admin_email: "ansible@test2.com"
    org_eps: "500"
    org_include_ip_range: "192.168.20.1-192.168.20.50"
    org_exclude_ip_range: "192.168.20.51-192.168.20.255"
    org_collectors: [{'name': 'ansibleOrg2Col1', 'eps': '200'},{'name': 'ansibleOrg2Col2', 'eps': '200'}]

- name: UPDATE AN ORG WITH COLLECTOR VIA PARAMETERS
  fsm_organizations:
    host: "10.7.220.61"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "update"
    export_json_to_screen: "enable"
    org_name: "ansibleOrg1"
    org_display_name: "Ansible Test Org 1"
    org_description: "Testing Ansible. Duh. Updated."
    org_eps: "400"
    org_include_ip_range: "192.168.10.1-192.168.10.50"
    org_exclude_ip_range: "192.168.10.51-192.168.10.255"
    org_collector_name: "ansibleOrg1Col1"
    org_collector_eps: "100"
  ignore_errors: yes



- name: UPDATE AN ORG WITH COLLECTOR VIA JSON
  fsm_organizations:
    host: "10.7.220.61"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    mode: "update"
    org_name: "ansibleOrg2"
    org_display_name: "Ansible Test Org 2"
    org_description: "Testing Ansible. Duh. Again. Updated."
    org_eps: "400"
    org_include_ip_range: "192.168.20.1-192.168.20.50"
    org_exclude_ip_range: "192.168.20.51-192.168.20.255"
    org_collectors: [{'name': 'ansibleOrg2Col1', 'eps': '100'},{'name': 'ansibleOrg2Col2', 'eps': '100'}]
  ignore_errors: yes
Playbook File Examples
fsm_get_organizations.yml
- name: GET LIST OF ORGS
  hosts: FortiSIEM
  connection: local
  gather_facts: False

  tasks:
    - name: GET SIMPLE DEVICE LIST OF ORGS
      fsm_organizations:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "get"
fsm_add_orgs.yml
- name: ADD MSP ORGS
  hosts: FortiSIEM_MSP
  connection: local
  gather_facts: False

  tasks:
    - name: ADD AN ORG WITH COLLECTOR VIA PARAMETERS
      fsm_organizations:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "add"
        org_name: "ansibleOrg1"
        org_display_name: "Ansible Test Org 1"
        org_description: "Testing Ansible. Duh."
        org_admin_username: "ansibleTest1"
        org_admin_password: "admin*1"
        org_admin_email: "ansible@test1.com"
        org_eps: "500"
        org_include_ip_range: "192.168.10.1-192.168.10.50"
        org_exclude_ip_range: "192.168.10.51-192.168.10.255"
        org_collector_name: "ansibleOrg1Col1"
        org_collector_eps: "200"

    - name: ADD AN ORG WITH COLLECTOR VIA JSON
      fsm_organizations:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "add"
        org_name: "ansibleOrg2"
        org_display_name: "Ansible Test Org 2"
        org_description: "Testing Ansible. Duh. Again."
        org_admin_username: "ansibleTest2"
        org_admin_password: "admin*1"
        org_admin_email: "ansible@test2.com"
        org_eps: "500"
        org_include_ip_range: "192.168.20.1-192.168.20.50"
        org_exclude_ip_range: "192.168.20.51-192.168.20.255"
        org_collectors: [{'name': 'ansibleOrg2Col1', 'eps': '200'},{'name': 'ansibleOrg2Col2', 'eps': '200'}]
fsm_update_orgs.yml
- name: ADD ORGS
  hosts: FortiSIEM_MSP
  connection: local
  gather_facts: False

  tasks:
    - name: ADD AN ORG WITH COLLECTOR VIA PARAMETERS
      fsm_organizations:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "update"
        export_json_to_screen: "enable"
        org_name: "ansibleOrg1"
        org_display_name: "Ansible Test Org 1"
        org_description: "Testing Ansible. Duh. Updated."
        org_eps: "400"
        org_include_ip_range: "192.168.10.1-192.168.10.50"
        org_exclude_ip_range: "192.168.10.51-192.168.10.255"
        org_collector_name: "ansibleOrg1Col1"
        org_collector_eps: "100"
      ignore_errors: yes



    - name: ADD AN ORG WITH COLLECTOR VIA JSON
      fsm_organizations:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "update"
        org_name: "ansibleOrg2"
        org_display_name: "Ansible Test Org 2"
        org_description: "Testing Ansible. Duh. Again. Updated."
        org_eps: "400"
        org_include_ip_range: "192.168.20.1-192.168.20.50"
        org_exclude_ip_range: "192.168.20.51-192.168.20.255"
        org_collectors: [{'name': 'ansibleOrg2Col1', 'eps': '100'},{'name': 'ansibleOrg2Col2', 'eps': '100'}]
      ignore_errors: yes
fsm_msp_get_organizations.yml
- name: GET LIST OF ORGS
  hosts: FortiSIEM_MSP
  connection: local
  gather_facts: False

  tasks:
    - name: GET SIMPLE DEVICE LIST OF ORGS
      fsm_organizations:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "get"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/msp_json_test_out_orgs.json"
        export_xml_to_file_path: "/root/msp_xml_test_out_orgs.xml"



    - name: ADD AN ORG WITH COLLECTOR VIA PARAMETERS
      fsm_organizations:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        mode: "add"
        org_name: "ansibleOrg1"
        org_display_name: "Ansible Test Org 1"
        org_description: "Testing Ansible. Duh."
        org_admin_username: "ansibleTest1"
        org_admin_password: "admin*1"
        org_admin_email: "ansible@test1.com"
        org_eps: "500"
        org_include_ip_range: "192.168.10.1-192.168.10.50"
        org_exclude_ip_range: "192.168.10.51-192.168.10.255"
        org_collector_name: "ansibleOrg1Col1"
        org_collector_eps: "200"

fsm_report_query

Playbook Task Examples
- name: SUBMIT REPORT
  fsm_report_query:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    report_file_path: "/root/top_fortisiem_events_by_count.xml"
    export_json_to_file_path: "/root/report.json"
    export_xml_to_file_path: "/root/report.xml"
    export_csv_to_file_path: "/root/report.csv"

- name: GET REPORT WITH RELATIVE TIME DEFINED
  fsm_report_query:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    report_file_path: "/root/top_fortisiem_events_by_count.xml"
    report_relative_mins: "60"

- name: GET REPORT WITH ABSOLUTE TIME DEFINED
  fsm_report_query:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    report_file_path: "/root/top_fortisiem_events_by_count.xml"
    report_absolute_begin_date: "04/17/2019"
    report_absolute_begin_time: "060000"
    report_absolute_end_date: "04/17/2019"
    report_absolute_end_time: "070000"
Playbook File Examples
fsm_submit_large_report.yml
- name: GET RESULTS FROM REPORT
  hosts: FortiSIEM
  connection: local
  gather_facts: False

  tasks:
    - name: SUBMIT LARGE REPORT
      fsm_report_query:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        report_file_path: "/root/all_fw_events.xml"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/large_report.json"
        export_xml_to_file_path: "/root/Large_report.xml"
        export_csv_to_file_path: "/root/large_report.csv"
top_fortisiem_events_by_count.xml
       <?xml version="1.0" encoding="UTF-8"?>
<Reports>
    <Report baseline="" rsSync="">
        <Name>Top FortiSIEM Events By Count</Name>
        <Description>Ranks the events by the number of times they have occurred in a given time period.</Description>
        <CustomerScope groupByEachCustomer="false">
        </CustomerScope>
        <SelectClause>
            <AttrList>eventType,COUNT(*)</AttrList>
        </SelectClause>
        <OrderByClause>
            <AttrList>COUNT(*) DESC</AttrList>
        </OrderByClause>
        <PatternClause window="3600">
            <SubPattern id="1164394" name="Filter_OVERALL_STATUS">
                <GroupByAttr>eventType</GroupByAttr>
            </SubPattern>
        </PatternClause>
        <userRoles>
            <roles custId="0">1169250</roles>
        </userRoles>
        <SyncOrgs/>
    </Report>
</Reports>
fsm_incident_report.yml
- name: GET RESULTS FROM REPORT
  hosts: FortiSIEM
  connection: local
  gather_facts: False

  tasks:
    - name: GET AN INCIDENT REPORT DIFFERENT MORE DETAIL
      fsm_report_query:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        report_file_path: "top-devices-and-incidents.xml"
        report_absolute_begin_date: "04/13/2019"
        report_absolute_begin_time: "060000"
        report_absolute_end_date: "04/18/2019"
        report_absolute_end_time: "150000"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/incident_report.json"
        export_xml_to_file_path: "/root/incident_report.xml"
fsm_submit_timed_report.yml
- name: GET RESULTS FROM REPORT
  hosts: FortiSIEM
  connection: local
  gather_facts: False

  tasks:
    - name: GET REPORT WITH RELATIVE TIME DEFINED
      fsm_report_query:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        report_file_path: "/root/top_fortisiem_events_by_count.xml"
        report_relative_mins: "60"

    - name: GET REPORT WITH ABSOLUTE TIME DEFINED
      fsm_report_query:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        report_file_path: "/root/top_fortisiem_events_by_count.xml"
        report_absolute_begin_date: "04/17/2019"
        report_absolute_begin_time: "060000"
        report_absolute_end_date: "04/17/2019"
        report_absolute_end_time: "070000"
fsm_msp_submit_large_report.yml
- name: GET RESULTS FROM REPORT
  hosts: FortiSIEM_MSP
  connection: local
  gather_facts: False

  tasks:
    - name: MSP SUBMIT LARGE REPORT
      fsm_report_query:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        report_file_path: "/root/all_fw_events.xml"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/msp_large_report.json"
        export_xml_to_file_path: "/root/msp_large_report.xml"
        export_csv_to_file_path: "/root/msp_large_report.csv"
fsm_msp_submit_report.yml
- name: GET RESULTS FROM REPORT
  hosts: FortiSIEM_MSP
  connection: local
  gather_facts: False

  tasks:
    - name: MSP SUBMIT REPORT
      fsm_report_query:
        host: "{{ inventory_hostname }}"
        username: "testOrg/api_user"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        report_file_path: "/root/msp-report.xml"
        export_json_to_screen: "enable"
        export_json_to_file_path: "/root/msp_report.json"
        export_xml_to_file_path: "/root/msp__report.xml"
all_fw_events.xml
       <?xml version="1.0" encoding="UTF-8"?><Reports><Report baseline="" rsSync=""><Name>Get_All_firewall_events_last_15m</Name><Description>Get_All_firewall_events_last_15m - 03:13:07 PM Apr 09 2019</Description><CustomerScope groupByEachCustomer="true">
<Include>1</Include>
<Exclude/>
</CustomerScope><SelectClause>
<AttrList>phRecvTime,reptDevIpAddr,eventType,eventName,rawEventMsg</AttrList>
</SelectClause><PatternClause>
<SubPattern id="2414751" name="">
<SingleEvtConstr>(reptDevIpAddr = 10.0.0.254) AND (phCustId IN (1))</SingleEvtConstr>
</SubPattern>
</PatternClause><userRoles>
<roles custId="1">1698800</roles>
</userRoles><SyncOrgs/><ReportInterval>
<Low>1554839835</Low>
<High>1554840734</High>
</ReportInterval></Report></Reports>
fsm_submit_report.yml
- name: GET RESULTS FROM REPORT
  hosts: FortiSIEM
  connection: local
  gather_facts: False

  tasks:
    - name: SUBMIT REPORT
      fsm_report_query:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        ignore_ssl_errors: "enable"
        report_file_path: "/root/top_fortisiem_events_by_count.xml"
        export_json_to_file_path: "/root/report.json"
        export_xml_to_file_path: "/root/report.xml"
        export_csv_to_file_path: "/root/report.csv"

fsm_send_syslog

Playbook Task Examples
- name: SEND UDP/514 SYSLOG WITH AUTO HEADER
  fsm_send_syslog:
    host: "10.0.0.15"
    ignore_ssl_errors: "enable"
    syslog_message: "This is a test syslog from Ansible!"

- name: SEND UDP/514 SYSLOG WITH AUTO HEADER
  fsm_send_syslog:
    syslog_host: "10.7.220.61"
    ignore_ssl_errors: "enable"
    syslog_message: "This is a test syslog from Ansible!"

- name: SEND UDP/514 SYSLOG CUSTOM HEADER
  fsm_send_syslog:
    syslog_host: "10.7.220.61"
    ignore_ssl_errors: "enable"
    syslog_message: "This is a test syslog from Ansible!"
    syslog_header: "This is a TEST HEADER :"

- name: SEND TCP/1470 SYSLOG WITH CUSTOM HEADER
  fsm_send_syslog:
    syslog_host: "10.7.220.61"
    ignore_ssl_errors: "enable"
    network_port: 1470
    network_protocol: "tcp"
    syslog_message: "This is a test syslog from Ansible!"
    syslog_header: "This is a TEST HEADER TCP PORT 1470 :"

- name: SEND TCP/6514 TLS SYSLOG WITH CUSTOM HEADER
  fsm_send_syslog:
    syslog_host: "10.7.220.61"
    ignore_ssl_errors: "enable"
    network_port: 6514
    network_protocol: "tcp-tls1.2"
    syslog_message: "This is a test syslog from Ansible!"
    syslog_header: "This is a TEST HEADER TCP TLS PORT 6514 :"

- name: SEND UDP/514 SYSLOG WITH AUTO HEADER AND DIFF FACILITY AND LEVEL
  fsm_send_syslog:
    syslog_host: "10.7.220.61"
    ignore_ssl_errors: "enable"
    syslog_facility: "AUTH"
    syslog_level: "CRIT"
    syslog_message: "This is a test syslog from Ansible! WITH CRIT AND AUTH AS LEVELS AND FACILITY."
Playbook File Examples
fsm_send_syslogs.yml
- name: SEND SYSLOGS
  hosts: FortiSIEM
  connection: local
  gather_facts: False

  tasks:
    - name: SEND UDP/514 SYSLOG WITH AUTO HEADER
      fsm_send_syslog:
        syslog_host: "{{ inventory_hostname }}"
        ignore_ssl_errors: "enable"
        syslog_message: "This is a test syslog from Ansible!"

    - name: SEND UDP/514 SYSLOG WITH AUTO HEADER AND DIFF FACILITY AND LEVEL
      fsm_send_syslog:
        syslog_host: "{{ inventory_hostname }}"
        ignore_ssl_errors: "enable"
        syslog_facility: "AUTH"
        syslog_level: "CRIT"
        syslog_message: "This is a test syslog from Ansible! WITH CRIT AND AUTH AS LEVELS AND FACILITY."

    - name: SEND UDP/514 SYSLOG WITH AUTO HEADER
      fsm_send_syslog:
        syslog_host: "{{ inventory_hostname }}"
        ignore_ssl_errors: "enable"
        syslog_message: "This is a test syslog from Ansible!"

    - name: SEND UDP/514 SYSLOG CUSTOM HEADER
      fsm_send_syslog:
        syslog_host: "{{ inventory_hostname }}"
        ignore_ssl_errors: "enable"
        syslog_message: "This is a test syslog from Ansible!"
        syslog_header: "This is a TEST HEADER :"

    - name: SEND TCP/1470 SYSLOG WITH CUSTOM HEADER
      fsm_send_syslog:
        syslog_host: "{{ inventory_hostname }}"
        ignore_ssl_errors: "enable"
        network_port: 1470
        network_protocol: "tcp"
        syslog_message: "This is a test syslog from Ansible!"
        syslog_header: "This is a TEST HEADER TCP PORT 1470 :"

    - name: SEND TCP/6514 TLS SYSLOG WITH CUSTOM HEADER
      fsm_send_syslog:
        syslog_host: "{{ inventory_hostname }}"
        ignore_ssl_errors: "enable"
        network_port: 6514
        network_protocol: "tcp-tls1.2"
        syslog_message: "This is a test syslog from Ansible!"
        syslog_header: "This is a TEST HEADER TCP TLS PORT 6514 :"

fsm_verify_device_ip

Playbook Task Examples
- name: VERIFY A DEVICE
  fsm_verify_device_ip:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    ip_to_verify: "10.0.0.5"
    export_json_to_file_path: "/root/deviceExists.json"
    append_results_to_file: "/root/verification.csv"

- name: TEST VERIFY A DEVICE THAT DOESN'T EXIST
  fsm_verify_device_ip:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    ip_to_verify: "10.0.0.45"
    export_json_to_file_path: "/root/deviceNoExist.json"
    append_results_to_file: "/root/verification.csv"
    export_json_to_screen: "enable"

- name: VERIFY A DEVICE FROM A LIST
  fsm_verify_device_ip:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    ip_list_to_verify: ["10.0.0.5", "10.0.0.10", "10.0.0.254"]
    export_json_to_file_path: "/root/deviceExistsList.json"
    append_results_to_file: "/root/verificationList.csv"

- name: VERIFY A DEVICE LIST FROM FILE
  fsm_verify_device_ip:
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    ignore_ssl_errors: "enable"
    ip_list_file_path: "/root/verify_list.txt"
    export_json_to_file_path: "/root/deviceExists.json"
    append_results_to_file: "/root/verificationList.csv"
Playbook File Examples

%%PB_FILE_EXAMPLE_TOKEN%%