Lambda to the Rescue - CodePipeline State Change Notifications in Slack

CodePipeline is AWS' answer to all your CI/CD orchestration needs. While you can add a manual approval action to a pipeline to get notified when a new version awaits approval, there's no built-in notification mechanism for pipeline failures or successes. So, how do you know when a pipeline build has finished or failed without watching the pipeline's console all the time?

The task at hand is perfect for a Lambda function. Our requirements are straightforward, we want to get notified whenever a pipeline starts, fails or succeeds. Even if a couple of pipelines run more or less all the time, there's no need to spin up a VM or a container to "watch" the pipelines and report on their state changes. A typical pattern to implement a cron-like behavior is to use CloudWatch Events to trigger a Lambda function periodically. However, this does not sound like the proper approach to check on various pipelines and their current state. CodePipeline emits a bunch of CloudWatch Events itself which is perfect for our use case. In total there are three different types of events emitted each dealing with a particular part of a pipeline's inner workings. The three are:

CodePipeline Pipeline Execution State Change
CodePipeline Stage Execution State Change
CodePipeline Action Execution State Change

The CodePipeline Pipeline Execution State Change fits our needs perfectly since it deals with state changes on a pipeline level. We can use this event to trigger a Lambda function which notifies us about the change in the pipeline's state.

Our solution comes along pretty nicely so far. What about the notification part? We could, of course, send a notification to an SNS topic which distributes an email to every subscriber. Fair enough. How about a Slack integration? With a proper setup, we could push pipeline notifications directly into a channel and notify our team without sending out more emails. Slack offers a simple WebHook integration to accomplish precisely what we want. We just need the endpoint URL for our Slack, a Lambda function and the adequately formatted API payload to get something like the following straight into a Slack channel.

Pipeline started notification

Implementation

The solution we are going to build is now sketched out, and we can get started. The complete code can be found here. The remainder of the post highlights some aspects of the implementation without going through it line-by-line. Feel free to look into the entire solution over at Github.

We go with the serverless framework to get up and running in no time. With this approach, we also get the ability to package and deploy our solution in a readily scriptable way and into different stages for free. To ease our development efforts further, the solution contains a lot of setup/configuration which allows us to work with JavaScript's ES7 features even though an AWS Lambda container currently runs Node v.6.10.

Hooking our Lambda function to the proper CloudWatch Event is a vital part of our solution. We can achieve this connection via the CloudWatch Console but since we are all about automation we use serverless' built-in capabilities to do that for us. In serverless.yml we define the following as a trigger of our function. Whenever a CodePipeline Pipeline Execution State Change event is emitted, our Lambda function will be triggered.

events:
  - cloudwatchEvent:
      event:
        source:
          - "aws.codepipeline"
        detail-type:
          - "CodePipeline Pipeline Execution State Change"

Slack allows us to send formatted text, as well as, override other properties of the WebHook integration. For example, we can replace the username and set a new icon. Why do we want that? Well, we want to see as clearly as possible what's going on, like below. Pipeline failed notification

To get this result, we have to prepare the WebHook's payload suitably. Below is the message's blueprint we are using in our solution.

{
  "icon_emoji":":fire:",
  "username":"DeploymentNotifier - us-east-1",
  "attachments":[
    {
      "fallback":"myPipeline has *failed*!",
      "text":"myPipeline has *failed*!",
      "color":"danger"
    }
  ]
}

The Lambda function parses the incoming event and grabs the AWS region which we are using as a suffix in the username to indicate from where the event originated. This comes in handy when you are running pipelines in different regions. Besides that, we are mapping the icon_emoji, the color and the text (with its fallback) to a set of prepared values depending on the event's state. Keep in mind that the icon does not change if the WebHook integration is called in rapid succession. Thus, the color will highlight the current state as well. The entire mapping can be found in slackNotifier.js

Deployment

To get the solution up and running we just need the WebHook integration URL and hand it over during deployment. Just export an environment variable called SLACK_URL and use the deployment command prepared in the package.json file like so:

export SLACK_URL="<Your WebHook URL>" && npm run deploy:prod

If everything goes well and your next pipeline execution eventually succeeds you will be notified with an appropriate message... Pipeline succeeded notification

Conclusion

With a simple Lambda function and Slack's WebHook integration, we can quickly push state changes of our deployment pipelines into Slack. No need for elaborate email notification setups or there like to increase the visibility into our CI/CD pipelines. Notifications will be delivered right away and pretty much free of charge (or are burning through Lambda's free tier already?).

arrow_back

Previous

How to autoincrement in DynamoDB if you really need to

Next

Gatsby.js
arrow_forward