Package: eventhooks
Eventseventhookstriggers webhooks for web services:POSTweb hookMattermostDockerhubeventhookssends emails:Simple emails (requires host, port, user and password)With or without TLS.AWS SES emails (usingboto3, requires AWS credentials)Needs to be installed withawsextra:pip install eventhooks[aws]eventhookspublishes to AMQP exchanges:AMQP (usingpika).Needs to be installed withpikaextra:pip install eventhooks[pika]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 atUnderstanding realms.IdeaThe idea ofeventhooksis 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.ConfigurationFor a more detailed configuration see further below.There is a simple web hook:WeHook:Usesrequests.Does aPOSTrequest to a given URL.Sendsjsondata.There are two,more specific web hooks that require more detailed configuration like setting tokens in the URL:MattermostWebHookBuilds on top ofWebHook, requires a mattermost<token>.Uses URL format:<host>/hooks/<token>DockerCloudWebHookBuilds on top ofWebHook, requires a docker hub<source>and<trigger>.Uses URL format:https://hub.docker.com/api/build/v1/source/<source>/trigger/<trigger>/call/There are two email hooks:SimpleEmailHookUsessmtpliband requires host, port, user and password.User and password are provided in the following format:user:password(see example below).With port25, settls=Falseto skip authentication.AwsSesEmailHookNeeds to be installed withawsextra:pip install eventhooks[aws]Usesboto3and 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 variableAWS_DEFAULT_REGION="eu-east-1".There is a AMQP (e.g. RabbitMQ) hook:RabbitMqHookUsespikaand requires host, user and password.The defaultvhostis/.The default configuration sends messages directly to queueexample_queue.Note:There is a eventhook factory, that makes a more dynamic configuration possible. For more details, seeUsing the eventhook factory.Web hooksWebHook configurationAWebHookcan be configured like this:fromeventhooks.eventhooksimportWebHookhit_alarm_endpoint=WebHook(name="",url="some.server.com",)# In case of some event:threshold=80hit_alarm_endpoint.trigger(data={"event":hit_alarm_endpoint.name,"message":f"Reached '{80}'.","area":"outside"})MattermosWebtHook configurationAMattermostWebHookcan be configured like this:fromeventhooks.eventhooksimportMattermostWebHookinform_about_job_status=MattermostWebHook(name="job_A_last_step",host="mattermost.server.com",token="<token>",)# In case of some event:job_finished=Trueinform_about_job_status.trigger(data={"event":inform_about_job_status.name,"message":f"Job completed: '{job_finished}'."})DockerCloudWebHook configurationADockerCloudWebHookcan be configured like this:fromeventhooks.eventhooksimportDockerCloudWebHookdockercloud_trigger=DockerCloudWebHook(name="dockercloud_event",source_branch="master",source_type="Branch",source="<source>",trigger="<trigger>",)# In case of some event:found_new_tag=Trueiffound_new_tag:dockercloud_trigger.trigger()Email hooksSimpleEmailHook configurationASimpleEmailHookcan be configured without TLS:fromeventhooks.eventhooksimportSimpleEmailHookfailed_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 simplyfailed_service_mail.trigger(data=",".join(failed_services))ASimpleEmailHookcan be configured with TLS:fromeventhooks.eventhooksimportSimpleEmailHooksimple_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 variabledescriptiondefault valueEVENT_MAIL_HOSTEmail server host."email-smtp.us-west-2.amazonaws.com"EVENT_MAIL_PORTEmail server port.587Note: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 variableSUBJECT, 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 configurationNote:For this to work properly set the environemnt variableAWS_DEFAULT_REGION=us-east-1. Replace the AWS region to use by the one appropriate to your use case.TheAwsSesEmailHookcan be configured like this:fromeventhooks.eventhooksimportAwsSesEmailHookaws_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 variableSUBJECT, 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 bodyLike 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 theSimpleEmailHookas well asAwsSesEmailHook.Note:Thedataargument is used as the email's body text.Note- The hook acceptsstranddictas 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):fromtypingimportUniondeftrigger(data:Union[dict,str]):...# Set the email body with the 'data' argument.email.body_text=dataemail.send_mail()...RabbitMqHook configurationTheRabbitMqHookcan be configured like this:fromeventhooks.eventhooksimportRabbitMqHookrabbitmq_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 realmsRealms 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 thetrigger()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 tomaster: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.fromeventhooks.eventhooksimportDockerCloudWebHookfromeventhooks.eventhooksimportSimpleEmailHooklatest_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 tomaster, you would end up triggering the events defined for new tags as well.# Loop over the list of events.deftrigger_events(data:str=""):foreventinevents: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'strigger()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.fromeventhooks.eventhooksimportDockerCloudWebHookfromeventhooks.eventhooksimportSimpleEmailHooklatest_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 tomasteris found, you would pass the configured realmGITHUB_MASTERas well. The 2 events preserved for new github repository tags are ignored - They do not support the given realmGITHUB_MASTER, onlyGITHUB_TAG.# Loop over the list of events and pass realms.deftrigger_events(data:str="",realm=None):foreventinevents:event.trigger(data=data,realm=realm)trigger_events(data={"msg":"Push to master found."},realm="GITHUB_MASTER")Using the eventhook factoryInstead of configuring events as show above, theevent_hepercan be used to return an already configured event.Thetypein the event's configuration needs to be one of:WebHookDockerCloudWebHookMattermostWebHookSimpleEmailHookAwsSesEmailHookRabbitMqHookfrom 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)LoggingBelow is a small example of how to set a common log format when using theeventhooksmodule.
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