Motivation
I want to receive Slack notifications from CodePipeline through Amazon SNS and Lambda. By using the Lambda function, formatting and filtering of messages are available. (Therefore, not Chatbot.) In this blog, I'll share how to achieve this.
Example of Slack notification:
(Note: This is useful for other architectures' notifications if SNS and Lambda are used.)
Create Slack
-
Create Webhook
- Ref: This post describe how to use webhooks in Lambda function.
- Memo the webhook URL for Lambda environmental variables
Create Lambda
- Create a Lambda function of Py3.9
- Set Lambda environmental variables
- Key:
WEBHOOK_URL_SLACK
, Value:https://hooks.slack.com/services/xxxxxxx
- Key:
- In this Python script, get an event from SNS.
- If the CodePipeline status is SUCCEED, do nothing.
- If the CodePipeline status is FAIL, send a message to Slack.
- Permission: BasicExecutionRole will be OK.
import json
import os
import urllib3
http = urllib3.PoolManager()
WEBHOOK_URL_SLACK = os.environ["WEBHOOK_URL_SLACK"]
def gen_message_from_codepipeline_event(event_dict):
"""
Return message according to the CodePipeline state.
"""
# No message when SUCCEEDED
if event_dict["detail"]["state"] == "SUCCEEDED":
return ""
if event_dict["detail"]["state"] == "FAILED":
message = "CodePipeline state: FAILED"
failed_stage = event_dict.get("additionalAttributes", {}).get("failedStage")
stage_info = (
f"Failed Stage: {failed_stage}"
if failed_stage
else "Failed Stage: N/A"
)
message += f"\n{stage_info}"
failed_actions = event_dict.get("additionalAttributes", {}).get("failedActions")
if failed_actions:
# Send only the last try info
info_last_action = failed_actions[-1]['additionalInformation']
message += f"\nInformation: {info_last_action}"
return message
def lambda_handler(event, context):
"""
Handle CodePipeline notifications and send messages to Slack.
"""
try:
event_str = event["Records"][0]["Sns"]["Message"]
except (KeyError, IndexError):
print("Error: Event is missing required data")
return
event_dict = json.loads(event_str)
# generate message
message = gen_message_from_codepipeline_event(event_dict)
if not message:
print({"statusCode": 200, "body": "No message to return."})
return
region = event_dict["region"]
pipeline = event_dict["detail"]["pipeline"]
pipeline_url = f"https://{region}.console.aws.amazon.com/codesuite/codepipeline/pipelines/{pipeline}/view?region={region}"
# Send Slack webhook
text = f"{message}\n<{pipeline_url}|Visit CodePipeline>"
msg = {
"text": text,
}
encoded_msg = json.dumps(msg).encode("utf-8")
resp = http.request("POST", WEBHOOK_URL_SLACK, body=encoded_msg)
print({"statusCode": resp.status, "body": "Send message."})
return
Create CodePipeline
You can use any CodePipeline. If you want a simple sample, you can use a CloudFormation template I've created from the AWS document with the simple S3 and EC2 pipeline. Upload the zip file found in the section of this AWS document.
If you want to deploy to Windows Server instances using CodeDeploy, download the sample application here: SampleApp_Windows.zip.
Create notification
AWS doc is here.
On the pipeline page, select "Notify".
- Create notification rules
- Set Notification name
- Detail type: Full
- Select events: Pipeline execution Failed, Succeeded
- Targes
- Create target: SNS Topic
- Use existing SNS Topic --> Need to set access policy
My settings is as below.
As a target, the SNS topic is used here. When you use an existing SNS Topic, you may need to add access policy. *The Principal is codestar-notifications.amazonaws.com
. *
If you create a target topic here, the access policy is included.
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "codestar-notifications.amazonaws.com"
},
"Action": "SNS:Publish",
"Resource": "arn:aws:sns:REGION:ACCOUNT_ID:TOPIC_NAME"
},
Subscribe
- Subscribe the Lambda function to this SNS Topic.
Run and fail
Fail scenarios:
- Start Pipeline without the zip file in the proper S3 bucket.
- Start Deploy section with EC2 instances are stopped.
Then you'll receive the Slack notification.
Note that the Information
part is from the additionalInformation
in the JSON message. And it appears on the console like the below image.
Summary
I've demonstrated how to receive Slack notifications from CodePipeline.
Top comments (2)
Great article, very helpful.
I've tried it with different pipeline from the one referenced in the article, but every time when my pipeline purposely fails on a build action I couldn't get the failed stage to be shown in the slack message, it always show Failed stage: N/A
I was debugging and saw that additionalAttributes", {} it's always empty and there is no failedActions property.
Thank you for your comment!
Yes, your're correct. Sometimes there is an empty additionalAttributes in the event of CodePipeline. In such a case Failed stage: N/A will be used.
I don't have much examples but this re:Post is similar case with empty attribute when using Teams. repost.aws/questions/QUIi_L8yLSQ1G...?