awx/awx_collection/plugins/modules/notification_template.py
Ethem Cem Özkan 37ad690d09
Add AWS SNS notification support for webhook (#15184)
Support for AWS SNS notifications. SNS is a widespread service that is used to integrate with other AWS services(EG lambdas). This support would unlock use cases like triggering lambda functions, especially when AWX is deployed on EKS.

Decisions:

Data Structure
- I preferred using the same structure as Webhook for message body data because it contains all job details. For now, I directly linked to Webhook to avoid duplication, but I am open to suggestions.

AWS authentication
- To support non-AWS native environments, I added configuration options for AWS secret key, ID, and session tokens. When entered, these values are supplied to the underlining boto3 SNS client. If not entered, it falls back to the default authentication chain to support the native AWS environment. Properly configured EKS pods are created with temporary credentials that the default authentication chain can pick automatically.

---------

Signed-off-by: Ethem Cem Ozkan <ethemcem.ozkan@gmail.com>
2024-06-02 02:48:56 +00:00

300 lines
9.7 KiB
Python

#!/usr/bin/python
# coding: utf-8 -*-
# (c) 2018, Samuel Carpentier <samuelcarpentier0@gmail.ca>
# 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 = '''
---
module: notification_template
author: "Samuel Carpentier (@samcarpentier)"
short_description: create, update, or destroy Automation Platform Controller notification.
description:
- Create, update, or destroy Automation Platform Controller notifications. See
U(https://www.ansible.com/tower) for an overview.
options:
name:
description:
- The name of the notification.
type: str
required: True
new_name:
description:
- Setting this option will change the existing name (looked up via the name field.
type: str
copy_from:
description:
- Name or id to copy the notification from.
- This will copy an existing notification and change any parameters supplied.
- The new notification name will be the one provided in the name parameter.
- The organization parameter is not used in this, to facilitate copy from one organization to another.
- Provide the id or use the lookup plugin to provide the id if multiple notifications share the same name.
type: str
description:
description:
- The description of the notification.
type: str
organization:
description:
- The organization name, ID, or named URL the notification belongs to.
type: str
notification_type:
description:
- The type of notification to be sent.
choices:
- 'awssns'
- 'email'
- 'grafana'
- 'irc'
- 'mattermost'
- 'pagerduty'
- 'rocketchat'
- 'slack'
- 'twilio'
- 'webhook'
type: str
notification_configuration:
description:
- The notification configuration file. Note providing this field would disable all notification-configuration-related fields.
- username (the mail server username)
- sender (the sender email address)
- recipients (the recipients email addresses)
- use_tls (the TLS trigger)
- host (the mail server host)
- use_ssl (the SSL trigger)
- password (the mail server password)
- port (the mail server port)
- channels (the destination Slack channels)
- token (the access token)
- account_token (the Twillio account token)
- from_number (the source phone number)
- to_numbers (the destination phone numbers)
- account_sid (the Twillio account SID)
- subdomain (the PagerDuty subdomain)
- service_key (the PagerDuty service/integration API key)
- client_name (the PagerDuty client identifier)
- message_from (the label to be shown with the notification)
- color (the notification color)
- notify (the notify channel trigger)
- url (the target URL)
- headers (the HTTP headers as JSON string)
- server (the IRC server address)
- nickname (the IRC nickname)
- targets (the destination channels or users)
type: dict
messages:
description:
- Optional custom messages for notification template.
type: dict
state:
description:
- Desired state of the resource.
default: "present"
choices: ["present", "absent", "exists"]
type: str
extends_documentation_fragment: awx.awx.auth
'''
EXAMPLES = '''
- name: Add Slack notification with custom messages
notification_template:
name: slack notification
organization: Default
notification_type: slack
notification_configuration:
channels:
- general
token: cefda9e2be1f21d11cdd9452f5b7f97fda977f42
messages:
started:
message: "{{ '{{ job_friendly_name }}{{ job.id }} started' }}"
success:
message: "{{ '{{ job_friendly_name }} completed in {{ job.elapsed }} seconds' }}"
error:
message: "{{ '{{ job_friendly_name }} FAILED! Please look at {{ job.url }}' }}"
state: present
controller_config_file: "~/tower_cli.cfg"
- name: Add webhook notification
notification_template:
name: webhook notification
notification_type: webhook
notification_configuration:
url: http://www.example.com/hook
headers:
X-Custom-Header: value123
state: present
controller_config_file: "~/tower_cli.cfg"
- name: Add email notification
notification_template:
name: email notification
notification_type: email
notification_configuration:
username: user
password: s3cr3t
sender: controller@example.com
recipients:
- user1@example.com
host: smtp.example.com
port: 25
use_tls: no
use_ssl: no
state: present
controller_config_file: "~/tower_cli.cfg"
- name: Add twilio notification
notification_template:
name: twilio notification
notification_type: twilio
notification_configuration:
account_token: a_token
account_sid: a_sid
from_number: '+15551112222'
to_numbers:
- '+15553334444'
state: present
controller_config_file: "~/tower_cli.cfg"
- name: Add PagerDuty notification
notification_template:
name: pagerduty notification
notification_type: pagerduty
notification_configuration:
token: a_token
subdomain: sub
client_name: client
service_key: a_key
state: present
controller_config_file: "~/tower_cli.cfg"
- name: Add IRC notification
notification_template:
name: irc notification
notification_type: irc
notification_configuration:
nickname: controller
password: s3cr3t
targets:
- user1
port: 8080
server: irc.example.com
use_ssl: no
state: present
controller_config_file: "~/tower_cli.cfg"
- name: Delete notification
notification_template:
name: old notification
state: absent
controller_config_file: "~/tower_cli.cfg"
- name: Copy webhook notification
notification_template:
name: foo notification
copy_from: email notification
organization: Foo
'''
RETURN = ''' # '''
from ..module_utils.controller_api import ControllerAPIModule
def main():
# Any additional arguments that are not fields of the item can be added here
argument_spec = dict(
name=dict(required=True),
new_name=dict(),
copy_from=dict(),
description=dict(),
organization=dict(),
notification_type=dict(choices=['awssns', 'email', 'grafana', 'irc', 'mattermost', 'pagerduty', 'rocketchat', 'slack', 'twilio', 'webhook']),
notification_configuration=dict(type='dict'),
messages=dict(type='dict'),
state=dict(choices=['present', 'absent', 'exists'], default='present'),
)
# Create a module for ourselves
module = ControllerAPIModule(argument_spec=argument_spec)
# Extract our parameters
name = module.params.get('name')
new_name = module.params.get('new_name')
copy_from = module.params.get('copy_from')
description = module.params.get('description')
organization = module.params.get('organization')
notification_type = module.params.get('notification_type')
notification_configuration = module.params.get('notification_configuration')
messages = module.params.get('messages')
state = module.params.get('state')
# Attempt to look up the related items the user specified (these will fail the module if not found)
organization_id = None
if organization:
organization_id = module.resolve_name_to_id('organizations', organization)
# Attempt to look up an existing item based on the provided data
existing_item = module.get_one(
'notification_templates',
name_or_id=name,
check_exists=(state == 'exists'),
**{
'data': {
'organization': organization_id,
}
}
)
# Attempt to look up credential to copy based on the provided name
if copy_from:
# a new existing item is formed when copying and is returned.
existing_item = module.copy_item(
existing_item,
copy_from,
name,
endpoint='notification_templates',
item_type='notification_template',
copy_lookup_data={},
)
if state == 'absent':
# If the state was absent we can let the module delete it if needed, the module will handle exiting from this
module.delete_if_needed(existing_item)
final_notification_configuration = {}
if notification_configuration is not None:
final_notification_configuration.update(notification_configuration)
# Create the data that gets sent for create and update
new_fields = {}
if final_notification_configuration:
new_fields['notification_configuration'] = final_notification_configuration
new_fields['name'] = new_name if new_name else (module.get_item_name(existing_item) if existing_item else name)
if description is not None:
new_fields['description'] = description
if organization is not None:
new_fields['organization'] = organization_id
if notification_type is not None:
new_fields['notification_type'] = notification_type
if messages is not None:
new_fields['messages'] = messages
# If the state was present and we can let the module build or update the existing item, this will return on its own
module.create_or_update_if_needed(existing_item, new_fields, endpoint='notification_templates', item_type='notification_template', associations={})
if __name__ == '__main__':
main()