#!/usr/bin/python # -*- coding: utf-8 -*- # Copyright: (c) 2018, 2019 Kevin Breit (@kbreit) # 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 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: - type: "gatewayDown" enabled: yes filters: timeout: 60 alert_destinations: emails: - 'youremail@yourcorp' - 'youremail2@yourcorp' all_admins: yes snmp: no - 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: 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 construct_payload(meraki, original): payload = copy.deepcopy(original) if meraki.params['default_destinations'] is not None: payload['defaultDestinations'].update(meraki.params['default_destinations']) payload['defaultDestinations']['allAdmins'] = meraki.params['default_destinations']['all_admins'] del payload['defaultDestinations']['all_admins'] del payload['defaultDestinations']['http_server_ids'] if meraki.params['alerts'] is not None: for alert in meraki.params['alerts']: alert.update(meraki.convert_snake_to_camel(alert)) del alert['alert_destinations'] for alert_want in meraki.params['alerts']: for alert_have in payload['alerts']: if alert_want['alert_type'] == alert_have['type']: alert_have.update(alert_want) del alert_have['alert_type'] del alert_have['alertType'] 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', default=[]), ) 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) # meraki.fail_json(msg="Compare", original=original, payload=payload) # meraki.fail_json(msg=payload) 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()