File: //lib/python3.9/site-packages/ansible_collections/cisco/meraki/plugins/modules/meraki_webhook.py
# -*- coding: utf-8 -*-
# Copyright: (c) 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_webhook
short_description: Manage webhooks configured in the Meraki cloud
description:
- Configure and query information about webhooks within the Meraki cloud.
notes:
- Some of the options are likely only used for developers within Meraki.
options:
state:
description:
- Specifies whether object should be queried, created/modified, or removed.
choices: [absent, present, query]
default: query
type: str
net_name:
description:
- Name of network which configuration is applied to.
aliases: [network]
type: str
net_id:
description:
- ID of network which configuration is applied to.
type: str
name:
description:
- Name of webhook.
type: str
shared_secret:
description:
- Secret password to use when accessing webhook.
type: str
url:
description:
- URL to access when calling webhook.
type: str
webhook_id:
description:
- Unique ID of webhook.
type: str
payload_template_name:
description:
- The name of the payload template
type: str
payload_template_id:
description:
- The ID of the payload template. Overrides payload_template_name if passed too.
type: str
test:
description:
- Indicates whether to test or query status.
type: str
choices: [test]
test_id:
description:
- ID of webhook test query.
type: str
author:
- Kevin Breit (@kbreit)
extends_documentation_fragment: cisco.meraki.meraki
"""
EXAMPLES = r"""
- name: Create webhook
meraki_webhook:
auth_key: abc123
state: present
org_name: YourOrg
net_name: YourNet
name: Test_Hook
url: https://webhook.url/
shared_secret: shhhdonttellanyone
payload_template_name: 'Slack (included)'
delegate_to: localhost
- name: Query one webhook
meraki_webhook:
auth_key: abc123
state: query
org_name: YourOrg
net_name: YourNet
name: Test_Hook
delegate_to: localhost
- name: Query all webhooks
meraki_webhook:
auth_key: abc123
state: query
org_name: YourOrg
net_name: YourNet
delegate_to: localhost
- name: Delete webhook
meraki_webhook:
auth_key: abc123
state: absent
org_name: YourOrg
net_name: YourNet
name: Test_Hook
delegate_to: localhost
- name: Test webhook
meraki_webhook:
auth_key: abc123
state: present
org_name: YourOrg
net_name: YourNet
test: test
url: https://webhook.url/abc123
delegate_to: localhost
- name: Get webhook status
meraki_webhook:
auth_key: abc123
state: present
org_name: YourOrg
net_name: YourNet
test: status
test_id: abc123531234
delegate_to: localhost
"""
RETURN = r"""
data:
description: List of administrators.
returned: success
type: complex
contains:
id:
description: Unique ID of webhook.
returned: success
type: str
sample: aHR0cHM6Ly93ZWJob22LnvpdGUvOGViNWI3NmYtYjE2Ny00Y2I4LTlmYzQtND32Mj3F5NzIaMjQ0
name:
description: Descriptive name of webhook.
returned: success
type: str
sample: Test_Hook
networkId:
description: ID of network containing webhook object.
returned: success
type: str
sample: N_12345
shared_secret:
description: Password for webhook.
returned: success
type: str
sample: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER
url:
description: URL of webhook endpoint.
returned: success
type: str
sample: https://webhook.url/abc123
status:
description: Status of webhook test.
returned: success, when testing webhook
type: str
sample: enqueued
payloadTemplate:
description: The payload template used when posting data to the HTTP server.
returned: success
type: str
sample:
payloadTemplateId: wpt_00001
name: Meraki (included)
"""
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_webhook_id(name, webhooks):
for webhook in webhooks:
if name == webhook["name"]:
return webhook["id"]
return None
def get_all_webhooks(meraki, net_id):
path = meraki.construct_path("get_all", net_id=net_id)
response = meraki.request(path, method="GET")
if meraki.status == 200:
return response
def sanitize_no_log_values(meraki):
try:
meraki.result["diff"]["before"][
"shared_secret"
] = "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER"
except KeyError:
pass
try:
for i in meraki.result['data']:
i[
"shared_secret"
] = "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER"
except (KeyError, TypeError):
pass
try:
meraki.result["data"]["shared_secret"] = "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER"
except (KeyError, TypeError):
pass
def get_webhook_payload_templates(meraki, net_id):
path = meraki.construct_path("get_payload_templates", net_id=net_id)
response = meraki.request(path, "GET")
if meraki.status != 200:
meraki.fail_json(msg="Unable to get webhook payload templates")
return response
def get_webhook_payload_template_id(meraki, templates, name):
for template in templates:
if template["name"] == name:
return template["payloadTemplateId"]
meraki.fail_json(msg="No payload template found with the name {0}".format(name))
def main():
# define the available arguments/parameters that a user can pass to
# the module
argument_spec = meraki_argument_spec()
argument_spec.update(
state=dict(type="str", choices=["absent", "present", "query"], default="query"),
net_name=dict(type="str", aliases=["network"]),
net_id=dict(type="str"),
name=dict(type="str"),
url=dict(type="str"),
shared_secret=dict(type="str", no_log=True),
webhook_id=dict(type="str"),
test=dict(type="str", choices=["test"]),
test_id=dict(type="str"),
payload_template_name=dict(type="str"),
payload_template_id=dict(type="str"),
)
# 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="webhooks")
meraki.params["follow_redirects"] = "all"
query_url = {"webhooks": "/networks/{net_id}/webhooks/httpServers"}
query_one_url = {"webhooks": "/networks/{net_id}/webhooks/httpServers/{hookid}"}
create_url = {"webhooks": "/networks/{net_id}/webhooks/httpServers"}
update_url = {"webhooks": "/networks/{net_id}/webhooks/httpServers/{hookid}"}
delete_url = {"webhooks": "/networks/{net_id}/webhooks/httpServers/{hookid}"}
test_url = {"webhooks": "/networks/{net_id}/webhooks/webhookTests"}
test_status_url = {"webhooks": "/networks/{net_id}/webhooks/webhookTests/{testid}"}
query_payload_templates = {
"webhooks": "/networks/{net_id}/webhooks/payloadTemplates"
}
meraki.url_catalog["get_all"].update(query_url)
meraki.url_catalog["get_one"].update(query_one_url)
meraki.url_catalog["create"] = create_url
meraki.url_catalog["update"] = update_url
meraki.url_catalog["delete"] = delete_url
meraki.url_catalog["test"] = test_url
meraki.url_catalog["test_status"] = test_status_url
meraki.url_catalog["get_payload_templates"] = query_payload_templates
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)
templates = get_webhook_payload_templates(meraki, net_id)
payload_template_id = meraki.params["payload_template_id"]
if (
payload_template_id is None
and meraki.params["payload_template_name"] is not None
):
payload_template_id = get_webhook_payload_template_id(
meraki, templates, name=meraki.params["payload_template_name"]
)
webhook_id = meraki.params["webhook_id"]
webhooks = None
if webhook_id is None and meraki.params["name"]:
webhooks = get_all_webhooks(meraki, net_id)
webhook_id = get_webhook_id(meraki.params["name"], webhooks)
if meraki.params["state"] == "present" and meraki.params["test"] is None:
payload = {
"name": meraki.params["name"],
"url": meraki.params["url"],
}
if meraki.params["shared_secret"] is not None:
payload["sharedSecret"] = meraki.params["shared_secret"]
if payload_template_id is not None:
payload["payloadTemplate"] = {"payloadTemplateId": payload_template_id}
if meraki.params["state"] == "query":
if webhook_id is not None: # Query a single webhook
path = meraki.construct_path(
"get_one", net_id=net_id, custom={"hookid": webhook_id}
)
response = meraki.request(path, method="GET")
if meraki.status == 200:
meraki.result["data"] = response
sanitize_no_log_values(meraki)
meraki.exit_json(**meraki.result)
elif meraki.params["test_id"] is not None:
path = meraki.construct_path(
"test_status",
net_id=net_id,
custom={"testid": meraki.params["test_id"]},
)
response = meraki.request(path, method="GET")
if meraki.status == 200:
meraki.result["data"] = response
sanitize_no_log_values(meraki)
meraki.exit_json(**meraki.result)
else:
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.fail_json(msg=meraki.result)
sanitize_no_log_values(meraki)
meraki.exit_json(**meraki.result)
elif meraki.params["state"] == "present":
if meraki.params["test"] == "test":
payload = {"url": meraki.params["url"]}
path = meraki.construct_path("test", net_id=net_id)
response = meraki.request(path, method="POST", payload=json.dumps(payload))
if meraki.status == 201:
meraki.result["data"] = response
meraki.exit_json(**meraki.result)
if webhook_id is None: # New webhook needs to be created
if meraki.check_mode is True:
meraki.result["data"] = payload
meraki.result["data"]["networkId"] = net_id
meraki.result["changed"] = True
meraki.exit_json(**meraki.result)
path = meraki.construct_path("create", net_id=net_id)
response = meraki.request(path, method="POST", payload=json.dumps(payload))
if meraki.status == 201:
meraki.result["data"] = response
meraki.result["changed"] = True
else: # Need to update
path = meraki.construct_path(
"get_one", net_id=net_id, custom={"hookid": webhook_id}
)
original = meraki.request(path, method="GET")
if meraki.is_update_required(original, payload):
if meraki.check_mode is True:
meraki.generate_diff(original, payload)
sanitize_no_log_values(meraki)
original.update(payload)
meraki.result["data"] = original
meraki.result["changed"] = True
meraki.exit_json(**meraki.result)
path = meraki.construct_path(
"update", net_id=net_id, custom={"hookid": webhook_id}
)
response = meraki.request(
path, method="PUT", payload=json.dumps(payload)
)
if meraki.status == 200:
# Not all fields are included so it needs to be checked to avoid comparing same thing
if meraki.is_update_required(original, response):
meraki.generate_diff(original, response)
sanitize_no_log_values(meraki)
meraki.result["data"] = response
meraki.result["changed"] = True
else:
meraki.result["data"] = original
elif meraki.params["state"] == "absent":
if webhook_id is None: # Make sure it is downloaded
if webhooks is None:
webhooks = get_all_webhooks(meraki, net_id)
webhook_id = get_webhook_id(meraki.params["name"], webhooks)
if webhook_id is None:
meraki.fail_json(
msg="There is no webhook with the name {0}".format(
meraki.params["name"]
)
)
if webhook_id: # Test to see if it exists
if meraki.module.check_mode is True:
meraki.result["data"] = None
meraki.result["changed"] = True
meraki.exit_json(**meraki.result)
path = meraki.construct_path(
"delete", net_id=net_id, custom={"hookid": webhook_id}
)
response = meraki.request(path, method="DELETE")
if meraki.status == 204:
meraki.result["data"] = response
meraki.result["changed"] = True
# 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()