Trigger webhooks with events.
Project description
Events
eventhooks triggers webhooks for web services:
POSTweb hook- Mattermost
- Dockerhub
eventhooks sends emails:
- Simple emails (requires host, port, user and password)
- With or without TLS.
- AWS SES emails (using
boto3, requires AWS credentials)- Needs to be installed with
awsextra:pip install eventhooks[aws]
- Needs to be installed with
eventhooks publishes to AMQP exchanges:
- AMQP (using
pika).- Needs to be installed with
pikaextra:pip install eventhooks[pika]
- Needs to be installed with
- Install all dependencies:
pip install eventhooks[pika,aws]
Note:
Of course, events could do a lot more. If you have an idea, please just create an issue and describe it.
Additionally, events can be configured with relams. Realms provide a context to an event and restrict the event action by caller origin. Have a look at Understanding realms.
Idea
The idea of eventhooks is to have a single library that helps accomplishing certain tasks in case of certain events. The triggers can be anything, in fact - They entirely depend on you.
Examples:
- Send an email in case of a failed servcie on your server.
- Additinoally, push the log of the failed service onto an AMQP exchange.
- Trigger a Dockerhub build of one of your docker images in case a new push to a dependent project happened.
- Have a Mattermost bot send the notification about a finished job to your team members.
- Add the finished job onto a specific statistics queue on RabbtMQ.
Configuration
For a more detailed configuration see further below.
There is a simple web hook:
WeHook:- Uses
requests. - Does a
POSTrequest to a given URL. - Sends
jsondata.
- Uses
There are two,more specific web hooks that require more detailed configuration like setting tokens in the URL:
MattermostWebHook- Builds on top of
WebHook, requires a mattermost<token>. - Uses URL format:
<host>/hooks/<token>
- Builds on top of
DockerCloudWebHook- Builds on top of
WebHook, requires a docker hub<source>and<trigger>. - Uses URL format:
https://hub.docker.com/api/build/v1/source/<source>/trigger/<trigger>/call/
- Builds on top of
There are two email hooks:
SimpleEmailHook- Uses
smtpliband requires host, port, user and password. - User and password are provided in the following format:
user:password(see example below). - With port
25, settls=Falseto skip authentication.
- Uses
AwsSesEmailHook- Needs to be installed with
awsextra:pip install eventhooks[aws] - Uses
boto3and requires AWS credentials (AWS access key ID and AWS secret access key). - If not configured otherwise, please set the required AWS region using the environment variable
AWS_DEFAULT_REGION="eu-east-1".
- Needs to be installed with
There is a AMQP (e.g. RabbitMQ) hook:
RabbitMqHook- Uses
pikaand requires host, user and password. - The default
vhostis/. - The default configuration sends messages directly to queue
example_queue.
- Uses
Note:
- There is a eventhook factory, that makes a more dynamic configuration possible. For more details, see Using the eventhook factory.
Web hooks
WebHook configuration
A WebHook can be configured like this:
from eventhooks.eventhooks import WebHook
hit_alarm_endpoint = WebHook(
name="",
url="some.server.com",
)
# In case of some event:
threshold = 80
hit_alarm_endpoint.trigger(data={"event": hit_alarm_endpoint.name, "message": f"Reached '{80}'.", "area": "outside"})
MattermosWebtHook configuration
A MattermostWebHook can be configured like this:
from eventhooks.eventhooks import MattermostWebHook
inform_about_job_status = MattermostWebHook(
name="job_A_last_step",
host="mattermost.server.com",
token="<token>",
)
# In case of some event:
job_finished = True
inform_about_job_status.trigger(data={"event": inform_about_job_status.name, "message": f"Job completed: '{job_finished}'."})
DockerCloudWebHook configuration
A DockerCloudWebHook can be configured like this:
from eventhooks.eventhooks import DockerCloudWebHook
dockercloud_trigger = DockerCloudWebHook(
name="dockercloud_event",
source_branch="master",
source_type="Branch",
source="<source>",
trigger="<trigger>",
)
# In case of some event:
found_new_tag = True
if found_new_tag:
dockercloud_trigger.trigger()
Email hooks
SimpleEmailHook configuration
A SimpleEmailHook can be configured without TLS:
from eventhooks.eventhooks import SimpleEmailHook
failed_service_mail = SimpleEmailHook(
name="failed_service_checker",
host="localhost",
port=25,
sender="someone@somwhere.com",
sender_name="someone",
recipients="mew@xyz.com, you@xyz.com",
tls=False,
)
# In case of some event:
# The event name ('failed_service_mail.name') will be used as email subject.
failed_services = ["mongodb.service", "nginx.service", "cron.service"]
email_body = {
"name": failed_service_mail.name,
"failed_services": failed_services,
}
failed_service_mail.trigger(data=email_body)
# or simply
failed_service_mail.trigger(data=",".join(failed_services))
A SimpleEmailHook can be configured with TLS:
from eventhooks.eventhooks import SimpleEmailHook
simple_email_trigger = SimpleEmailHook(
name="aws_simple_email_event",
host="email-smtp.eu-west-1.amazonaws.com",
port=587,
credentials="user:password",
sender="someone@somwhere.com",
sender_name="someone",
recipients=["mew@xyz.com", "you@xyz.com"],
)
Some general email connection settings can be configured using environment variables:
| environment variable | description | default value |
|---|---|---|
EVENT_MAIL_HOST |
Email server host. | "email-smtp.us-west-2.amazonaws.com" |
EVENT_MAIL_PORT |
Email server port. | 587 |
Note:
- So far emails are sent in plain text only, no option for HTML.
TLSis used by default and can be disabled usingtls=Falsewhen initialising theSimpleEmailHook.- If no email subject is configured using the environment variable
SUBJECT, thenameof theSimpleEmailHookwill be used as the email's subject by default. Of course this can be changed later on:
# Set the email's subject.
simple_email_trigger.email.subject = "Something else."
AwsSesEmailHook configuration
Note:
- For this to work properly set the environemnt variable
AWS_DEFAULT_REGION=us-east-1. Replace the AWS region to use by the one appropriate to your use case.
The AwsSesEmailHook can be configured like this:
from eventhooks.eventhooks import AwsSesEmailHook
aws_ses_email_trigger = AwsSesEmailHook(
name="aws_ses_email_event",
sender="someone@somwhere.com",
sender_name="someone",
recipients=["me@peer.xyz"],
)
Note:
- So far emails are sent in plain text only, no option for HTML.
- If no email subject is configured using the environment variable
SUBJECT, thenameof theAwsSesEmailHookwill be used as the email's subject by default. Of course this can be changed later on:
# Set the email's subject.
aws_ses_email_trigger.email.subject = "Something else."
Email body
Like mentioned earlier (See example configurations above), every event is essentially triggered like this:
event.trigger(data="Found new tag for repo <some_github_repo>.")
This is also true for the SimpleEmailHook as well as AwsSesEmailHook.
Note:
- The
dataargument is used as the email's body text.
Note - The hook accepts str and dict as body text:
event.trigger(data="Some string")(str)event.trigger(data={"error": "Weird error.", "cause": "Human factor."})(dict)- In this case, the JSON is indented.
Internally it works like this (simplified):
from typing import Union
def trigger(data: Union[dict,str]):
...
# Set the email body with the 'data' argument.
email.body_text = data
email.send_mail()
...
RabbitMqHook configuration
The RabbitMqHook can be configured like this:
from eventhooks.eventhooks import RabbitMqHook
rabbitmq_trigger = RabbitMqHook(
name="failed_services_event",
host="rabbitmq.company.com",
user="username",
password="secur3_!Password!",
exchange="amqp.topic",
routing_key='company.dep2.failed_services.serverA',
)
Understanding realms
Realms provide a context to an event and restrict the event action by caller origin.
- A realm can be a simple string, which is set on initialization of an event.
- Specifying a realm with an event, requires the realm to be passed with the
trigger()to actually trigger the event. - Not defining any realms will ignore the feature entirely.
Example: All the examples given above have been defined without using realms. Now, let's imagine, you have built a project that watches a github repository:
- In case of new pushes to
master:- Trigger a dockerhub build.
- In case of a new tag:
- Trigger a dockerhub build.
- Notify team members by mail.
You can now define 3 events:
DockerCloudHook(as can be seen above) to trigger the build of thelatestdocker image based onmasterof the github repository you watch.DockerCloudHook(as can be seen above) to trigger the build of a tagged docker image based on new tags of the github repository you watch.SimpleEmailHook(as can be seen above) in case of new tags in the github repository.
from eventhooks.eventhooks import DockerCloudWebHook
from eventhooks.eventhooks import SimpleEmailHook
latest_build= DockerCloudWebHook(
...,
)
tag_build= DockerCloudWebHook(
...,
)
email_team = SimpleEmailHook(
...,
recipients=["developers@company.com", "head_of_devs@company.com"],
)
events = [latest_build, tag_build, email_team]
If you now just looped over the list of events in case of a new push to master, you would end up triggering the events defined for new tags as well.
# Loop over the list of events.
def trigger_events(data: str=""):
for event in events:
event.trigger(data=data)
trigger_events(data={"msg": "Push to master found."})
This is not what we want,
When using realms, the realm passed to an event's trigger() method is compared against the realms given on initialization. Only if the given realm is found in the list of realms the event is actually triggered.
from eventhooks.eventhooks import DockerCloudWebHook
from eventhooks.eventhooks import SimpleEmailHook
latest_build= DockerCloudWebHook(
...,
realms = ["GITHUB_MASTER"],
)
tag_build= DockerCloudWebHook(
...,
realms = ["GITHUB_TAG"],
)
email_team = SimpleEmailHook(
...,
recipients=["developers@company.com", "head_of_devs@company.com"],
realms = ["GITHUB_TAG"],
)
events = [latest_build, tag_build, email_team]
Now, when a new push to master is found, you would pass the configured realm GITHUB_MASTER as well. The 2 events preserved for new github repository tags are ignored - They do not support the given realm GITHUB_MASTER, only GITHUB_TAG.
# Loop over the list of events and pass realms.
def trigger_events(data: str="", realm=None):
for event in events:
event.trigger(data=data, realm=realm)
trigger_events(data={"msg": "Push to master found."}, realm="GITHUB_MASTER")
Using the eventhook factory
Instead of configuring events as show above, the event_heper can be used to return an already configured event.
The type in the event's configuration needs to be one of:
WebHookDockerCloudWebHookMattermostWebHookSimpleEmailHookAwsSesEmailHookRabbitMqHook
from eventhooks import event_helper
event_config = {
"type": "SimpleEmailHook",
"sender" mail@company.com,
"sender_name": "maintenance",
"recipients": ["devs@company.com"],
"realms": ["log_contains_key"],
}
event = event_helper.eventhook_factory("event_name", event_config)
Logging
Below is a small example of how to set a common log format when using the eventhooks module.
The idea is to have a common log format throughout your entire application.
import logging
import sys
import eventhooks.eventhooks
from eventhooks.mail import aws_ses
from eventhooks.mail import simple
# Your app logger.
logger = logging.getLogger("TestApp")
logger.setLevel(logging.DEBUG)
# A 'StreamHandler' printing to the terminal.
ch = logging.StreamHandler(sys.stdout)
ch.setFormatter(logging.Formatter("%(asctime)a - %(name)s [%(levelname)s] [%(lineno)s]: %(message)s"))
ch.setLevel(logging.DEBUG)
logger.addHandler(ch)
logger.propagate = False
# The 'eventhooks' logger.
logger_ = logging.getLogger("EventHooks")
logger_.addHandler(ch)
logger_.propagate = False
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file eventhooks-0.3.2.tar.gz.
File metadata
- Download URL: eventhooks-0.3.2.tar.gz
- Upload date:
- Size: 17.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.3.0 pkginfo/1.7.0 requests/2.25.1 setuptools/53.0.0 requests-toolbelt/0.9.1 tqdm/4.56.0 CPython/3.8.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
41f44fa1abd9f242f5203603d74fcbbe84a50c2e63c00dd1e5b867db9d4e783b
|
|
| MD5 |
d1189af651a396d4144013ae0a93e2bf
|
|
| BLAKE2b-256 |
5bb3210385dc0d718dde7e965abcd4b8a2cd1a7d11382654a1f6f4cf93ec07f9
|
File details
Details for the file eventhooks-0.3.2-py3-none-any.whl.
File metadata
- Download URL: eventhooks-0.3.2-py3-none-any.whl
- Upload date:
- Size: 14.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.3.0 pkginfo/1.7.0 requests/2.25.1 setuptools/53.0.0 requests-toolbelt/0.9.1 tqdm/4.56.0 CPython/3.8.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
270e0f69e87e377c356cb7ae2a8a95fdb75c559042b2160f1d27b2617e42ef2d
|
|
| MD5 |
43d55d86d4cc7537fd97c78d491b8cbd
|
|
| BLAKE2b-256 |
bca8fe4ec4598502cf571937d7911db6a99d60b507893a51157160b20d5408de
|