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()