File: //usr/lib/python3.9/site-packages/ansible_collections/cisco/meraki/plugins/modules/meraki_alert.py
# -*- coding: utf-8 -*-
# Copyright: (c) 2018, 2019 Kevin Breit (@kbreit) <[email protected]>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.1",
"status": ["preview"],
"supported_by": "community",
}
DOCUMENTATION = r"""
---
module: meraki_alert
version_added: "2.1.0"
short_description: Manage alerts in the Meraki cloud
description:
- Allows for creation, management, and visibility into alert settings within Meraki.
options:
state:
description:
- Create or modify an alert.
choices: [ present, query ]
default: present
type: str
net_name:
description:
- Name of a network.
aliases: [ name, network ]
type: str
net_id:
description:
- ID number of a network.
type: str
default_destinations:
description:
- Properties for destinations when alert specific destinations aren't specified.
type: dict
suboptions:
all_admins:
description:
- If true, all network admins will receive emails.
type: bool
snmp:
description:
- If true, then an SNMP trap will be sent if there is an SNMP trap server configured for this network.
type: bool
emails:
description:
- A list of emails that will recieve the alert(s).
type: list
elements: str
http_server_ids:
description:
- A list of HTTP server IDs to send a Webhook to.
type: list
elements: str
alerts:
description:
- Alert-specific configuration for each type.
type: list
elements: dict
suboptions:
alert_type:
description:
- The type of alert.
type: str
enabled:
description:
- A boolean depicting if the alert is turned on or off.
type: bool
filters:
description:
- A hash of specific configuration data for the alert. Only filters specific to the alert will be updated.
- No validation checks occur against C(filters).
type: raw
default: {}
alert_destinations:
description:
- A hash of destinations for this specific alert.
type: dict
suboptions:
all_admins:
description:
- If true, all network admins will receive emails.
type: bool
snmp:
description:
- If true, then an SNMP trap will be sent if there is an SNMP trap server configured for this network.
type: bool
emails:
description:
- A list of emails that will recieve the alert(s).
type: list
elements: str
http_server_ids:
description:
- A list of HTTP server IDs to send a Webhook to.
type: list
elements: str
author:
- Kevin Breit (@kbreit)
extends_documentation_fragment: cisco.meraki.meraki
"""
EXAMPLES = r"""
- name: Update settings
meraki_alert:
auth_key: abc123
org_name: YourOrg
net_name: YourNet
state: present
default_destinations:
emails:
- 'youremail@yourcorp'
- 'youremail2@yourcorp'
all_admins: yes
snmp: no
alerts:
- alert_type: "gatewayDown"
enabled: yes
filters:
timeout: 60
alert_destinations:
emails:
- 'youremail@yourcorp'
- 'youremail2@yourcorp'
all_admins: yes
snmp: no
- alert_type: "usageAlert"
enabled: yes
filters:
period: 1200
threshold: 104857600
alert_destinations:
emails:
- 'youremail@yourcorp'
- 'youremail2@yourcorp'
all_admins: yes
snmp: no
- name: Query all settings
meraki_alert:
auth_key: abc123
org_name: YourOrg
net_name: YourNet
state: query
delegate_to: localhost
"""
RETURN = r"""
data:
description: Information about the created or manipulated object.
returned: info
type: complex
contains:
default_destinations:
description: Properties for destinations when alert specific destinations aren't specified.
returned: success
type: complex
contains:
all_admins:
description: If true, all network admins will receive emails.
type: bool
sample: true
returned: success
snmp:
description: If true, then an SNMP trap will be sent if there is an SNMP trap server configured for this network.
type: bool
sample: true
returned: success
emails:
description: A list of emails that will recieve the alert(s).
type: list
returned: success
http_server_ids:
description: A list of HTTP server IDs to send a Webhook to.
type: list
returned: success
alerts:
description: Alert-specific configuration for each type.
type: complex
contains:
alert_type:
description: The type of alert.
type: str
returned: success
enabled:
description: A boolean depicting if the alert is turned on or off.
type: bool
returned: success
filters:
description:
- A hash of specific configuration data for the alert. Only filters specific to the alert will be updated.
- No validation checks occur against C(filters).
type: complex
returned: success
alert_destinations:
description: A hash of destinations for this specific alert.
type: complex
contains:
all_admins:
description: If true, all network admins will receive emails.
type: bool
returned: success
snmp:
description: If true, then an SNMP trap will be sent if there is an SNMP trap server configured for this network.
type: bool
returned: success
emails:
description: A list of emails that will recieve the alert(s).
type: list
returned: success
http_server_ids:
description: A list of HTTP server IDs to send a Webhook to.
type: list
returned: success
"""
import copy
from ansible.module_utils.basic import AnsibleModule, json
from ansible_collections.cisco.meraki.plugins.module_utils.network.meraki.meraki import (
MerakiModule,
meraki_argument_spec,
)
def get_alert_by_type(type, meraki):
for alert in meraki.params["alerts"]:
if alert["alert_type"] == type:
return alert
return None
def construct_payload(meraki, current):
payload = {}
if meraki.params["default_destinations"] is not None:
payload["defaultDestinations"] = {}
if meraki.params["default_destinations"]["all_admins"] is not None:
payload["defaultDestinations"]["allAdmins"] = meraki.params["default_destinations"]["all_admins"]
if meraki.params["default_destinations"]["snmp"] is not None:
payload["defaultDestinations"]["snmp"] = meraki.params["default_destinations"]["snmp"]
if meraki.params["default_destinations"]["emails"] is not None:
payload["defaultDestinations"]["emails"] = meraki.params["default_destinations"]["emails"]
if len(payload["defaultDestinations"]["emails"]) > 0 and payload["defaultDestinations"]["emails"][0] == "None":
# Ansible is setting the first item to be "None" so we need to clear this
# This happens when an empty list is provided to clear emails
del payload["defaultDestinations"]["emails"][0]
if meraki.params["default_destinations"]["http_server_ids"] is not None:
payload["defaultDestinations"]["httpServerIds"] = meraki.params["default_destinations"]["http_server_ids"]
if len(payload["defaultDestinations"]["httpServerIds"]) > 0 and payload["defaultDestinations"]["httpServerIds"][0] == "None":
# Ansible is setting the first item to be "None" so we need to clear this
# This happens when an empty list is provided to clear server IDs
del payload["defaultDestinations"]["httpServerIds"][0]
if meraki.params["alerts"] is not None:
payload["alerts"] = []
# All data should be resubmitted, otherwise it will clear the alert
# Also, the order matters so it should go in the same order as current
modified_types = [type["alert_type"] for type in meraki.params["alerts"]]
# for alert in meraki.params["alerts"]:
for current_alert in current["alerts"]:
if current_alert["type"] not in modified_types:
payload["alerts"].append(current_alert)
else:
alert = get_alert_by_type(current_alert["type"], meraki)
alert_temp = {"type": None}
if alert["alert_type"] is not None:
alert_temp["type"] = alert["alert_type"]
if alert["enabled"] is not None:
alert_temp["enabled"] = alert["enabled"]
if alert["filters"] is not None:
alert_temp["filters"] = alert["filters"]
if alert["alert_destinations"] is not None:
alert_temp["alertDestinations"] = dict()
if alert["alert_destinations"]["all_admins"] is not None:
alert_temp["alertDestinations"]["allAdmins"] = alert["alert_destinations"]["all_admins"]
if alert["alert_destinations"]["snmp"] is not None:
alert_temp["alertDestinations"]["snmp"] = alert["alert_destinations"]["snmp"]
if alert["alert_destinations"]["emails"] is not None:
alert_temp["alertDestinations"]["emails"] = alert["alert_destinations"]["emails"]
if len(alert_temp["alertDestinations"]["emails"]) > 0 and alert_temp["alertDestinations"]["emails"][0] == "None":
# Ansible is setting the first item to be "None" so we need to clear this
# This happens when an empty list is provided to clear emails
del alert_temp["defaultDestinations"]["emails"][0]
if alert["alert_destinations"]["http_server_ids"] is not None:
alert_temp["alertDestinations"]["httpServerIds"] = alert["alert_destinations"]["http_server_ids"]
if len(alert_temp["alertDestinations"]["httpServerIds"]) > 0 and alert_temp["alertDestinations"]["httpServerIds"][0] == "None":
# Ansible is setting the first item to be "None" so we need to clear this
# This happens when an empty list is provided to clear server IDs
del alert_temp["defaultDestinations"]["httpServerIds"][0]
payload["alerts"].append(alert_temp)
return payload
def main():
# define the available arguments/parameters that a user can pass to
# the module
destinations_arg_spec = dict(
all_admins=dict(type="bool"),
snmp=dict(type="bool"),
emails=dict(type="list", elements="str"),
http_server_ids=dict(type="list", elements="str"),
)
alerts_arg_spec = dict(
alert_type=dict(type="str"),
enabled=dict(type="bool"),
alert_destinations=dict(
type="dict", default=None, options=destinations_arg_spec
),
filters=dict(type="raw", default={}),
)
argument_spec = meraki_argument_spec()
argument_spec.update(
net_id=dict(type="str"),
net_name=dict(type="str", aliases=["name", "network"]),
state=dict(type="str", choices=["present", "query"], default="present"),
default_destinations=dict(
type="dict", default=None, options=destinations_arg_spec
),
alerts=dict(type="list", elements="dict", options=alerts_arg_spec),
)
# the AnsibleModule object will be our abstraction working with Ansible
# this includes instantiation, a couple of common attr would be the
# args/params passed to the execution, as well as if the module
# supports check mode
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
meraki = MerakiModule(module, function="alert")
module.params["follow_redirects"] = "all"
query_urls = {"alert": "/networks/{net_id}/alerts/settings"}
update_urls = {"alert": "/networks/{net_id}/alerts/settings"}
meraki.url_catalog["get_all"].update(query_urls)
meraki.url_catalog["update"] = update_urls
# manipulate or modify the state as needed (this is going to be the
# part where your module will do what it needs to do)
org_id = meraki.params["org_id"]
if org_id is None:
org_id = meraki.get_org_id(meraki.params["org_name"])
net_id = meraki.params["net_id"]
if net_id is None:
nets = meraki.get_nets(org_id=org_id)
net_id = meraki.get_net_id(net_name=meraki.params["net_name"], data=nets)
if meraki.params["state"] == "query":
path = meraki.construct_path("get_all", net_id=net_id)
response = meraki.request(path, method="GET")
if meraki.status == 200:
meraki.result["data"] = response
meraki.exit_json(**meraki.result)
elif meraki.params["state"] == "present":
path = meraki.construct_path("get_all", net_id=net_id)
original = meraki.request(path, method="GET")
payload = construct_payload(meraki, original)
if meraki.is_update_required(original, payload):
if meraki.check_mode is True:
meraki.generate_diff(original, payload)
meraki.result["data"] = payload
meraki.result["changed"] = True
meraki.exit_json(**meraki.result)
path = meraki.construct_path("update", net_id=net_id)
response = meraki.request(path, method="PUT", payload=json.dumps(payload))
if meraki.status == 200:
meraki.generate_diff(original, payload)
meraki.result["data"] = response
meraki.result["changed"] = True
meraki.exit_json(**meraki.result)
else:
meraki.result["data"] = original
meraki.exit_json(**meraki.result)
# in the event of a successful module execution, you will want to
# simple AnsibleModule.exit_json(), passing the key/value results
meraki.exit_json(**meraki.result)
if __name__ == "__main__":
main()