Trigger webhooks with events.
Project description
Events
eventhooks
triggers webhooks for web services:
POST
web 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
aws
extra:pip install eventhooks[aws]
- Needs to be installed with
eventhooks
publishes to AMQP exchanges:
- AMQP (using
pika
).- Needs to be installed with
pika
extra: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
POST
request to a given URL. - Sends
json
data.
- 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
smtplib
and requires host, port, user and password. - User and password are provided in the following format:
user:password
(see example below). - With port
25
, settls=False
to skip authentication.
- Uses
AwsSesEmailHook
- Needs to be installed with
aws
extra:pip install eventhooks[aws]
- Uses
boto3
and 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
pika
and requires host, user and password. - The default
vhost
is/
. - 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.
TLS
is used by default and can be disabled usingtls=False
when initialising theSimpleEmailHook
.- If no email subject is configured using the environment variable
SUBJECT
, thename
of theSimpleEmailHook
will 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
, thename
of theAwsSesEmailHook
will 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
data
argument 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 thelatest
docker image based onmaster
of 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:
WebHook
DockerCloudWebHook
MattermostWebHook
SimpleEmailHook
AwsSesEmailHook
RabbitMqHook
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
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 |