Skip to content

Instantly share code, notes, and snippets.

@michimani
Last active December 15, 2022 13:32
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save michimani/b245aeb15bdc61e2449dda9e90a91744 to your computer and use it in GitHub Desktop.
Save michimani/b245aeb15bdc61e2449dda9e90a91744 to your computer and use it in GitHub Desktop.
This is a sample of AWS Lambda function that notifies CodeBuild Notification (only state changes) to Slack via Amazon SNS.
import json
import traceback
from datetime import datetime, timezone, timedelta
from urllib.request import Request, urlopen
SLACK_WEBHOOK_URL = '<your-slack-incomming-webhook-url>'
SLACK_CHANNEL = '<your-slack-channel>'
TEST_EVENT_FILE = './sample__CodeBuild.json'
def lambda_handler(event, context):
try:
main(event, context)
except Exception as e:
print(traceback.format_exc())
def main(event, context=None):
event_message = str(event['Records'][0]['Sns']['Message'])
event_message_json = json.loads(event_message)
optimezed_info = optimize_notification_info(event_message_json)
post_to_slack_with_attachment(optimezed_info)
def load_test_event():
with open(TEST_EVENT_FILE) as f:
test_event = json.load(f)
return {
'Records': [
{
'Sns': {
'Message': json.dumps(test_event)
}
}
]
}
def optimize_notification_info(event):
ts = int(datetime.fromisoformat(
event['time'].replace('Z', '')).strftime('%s'))
color = '#cfd8dc'
if event['detail']['build-status'] == 'SUCCEEDED':
color = '#76ff03'
elif event['detail']['build-status'] == 'STOPPED':
color = '#ffeb3b'
elif event['detail']['build-status'] == 'FAILED':
color = '#d50000'
attachments = [
{
'title': event['detailType'],
'color': color,
'ts': ts,
'fields': [
{
'title': 'project-name',
'value': '`{}`'.format(event['detail']['project-name'])
},
{
'title': 'build-status',
'value': '`{}`'.format(event['detail']['build-status'])
},
{
'title': 'build-id',
'value': '`{}`'.format(event['detail']['build-id'])
}
]
}
]
# not succeeded phases
if event['detail']['build-status'] != 'IN_PROGRESS':
not_succeeded_phases_info = get_not_succeeded_phase_info(
event['detail']['additional-information']['phases'])
if not_succeeded_phases_info != '':
attachments[0]['fields'].append(
{
'title': 'NOT-SUCCEEDED-phases',
'value': '```\n{}\n```'.format(not_succeeded_phases_info)
}
)
# CloudWatch Logs link
if 'deep-link' in event['detail']['additional-information']['logs'] and 'group-name' in event['detail']['additional-information']['logs']:
attachments[0]['fields'].append(
{
'title': 'logs',
'value': '<{deep_link}|{group_name}:{stream_name}>'.format(
deep_link=event['detail']['additional-information']['logs']['deep-link'],
group_name=event['detail']['additional-information']['logs']['group-name'],
stream_name=event['detail']['additional-information']['logs']['stream-name']
)
}
)
return attachments
def get_not_succeeded_phase_info(phases):
info = ''
for phase in phases:
if 'phase-status' in phase and phase['phase-status'] != 'SUCCEEDED':
if info != '':
info += '\n'
info += '- {type}\n\tstatus: {status}\n\tcontext: "{context}"'.format(
type=phase['phase-type'],
status=phase['phase-status'],
context=', '.join(phase['phase-context'])
)
return info
def post_to_slack_with_attachment(attachment):
post_data = {
'username': 'CodeBuild Notification',
'attachments': attachment,
'channel': SLACK_CHANNEL
}
headers = {'Content-Type': 'application/json'}
data = json.dumps(post_data).encode('utf-8')
request = Request(SLACK_WEBHOOK_URL, data=data, headers=headers)
urlopen(request)
if __name__ == '__main__':
event = load_test_event()
main(event)
{
"account": "999999999999",
"detailType": "SampleProject Build State Change",
"region": "ap-northeast-1",
"source": "aws.codebuild",
"time": "2019-11-11T05:05:05Z",
"notificationRuleArn": "arn:aws:codestar-notifications:ap-northeast-1:999999999999:notificationrule/b5bd8303-f06f-466e-a0a1-XXXXXXXXXXXX",
"detail": {
"build-status": "SUCCEEDED",
"project-name": "SampleProjectBuild",
"build-id": "arn:aws:codebuild:ap-northeast-1:999999999999:build/SampleProjectBuild:408c5476-c8c0-4aa9-a81b-XXXXXXXXXXXX",
"additional-information": {
"cache": {
"type": "NO_CACHE"
},
"timeout-in-minutes": 60,
"build-complete": true,
"initiator": "INITIATOR",
"build-start-time": "Nov 11, 2019 5:03:42 AM",
"source": {
"location": "location-link",
"type": "GITHUB"
},
"artifact": {
"location": ""
},
"environment": {
"image": "aws/codebuild/amazonlinux2-x86_64-standard:1.0",
"privileged-mode": false,
"image-pull-credentials-type": "CODEBUILD",
"compute-type": "BUILD_GENERAL1_SMALL",
"type": "LINUX_CONTAINER",
"environment-variables": []
},
"logs": {
"group-name": "/aws/codebuild/SampleProjectBuild",
"stream-name": "408c5476-c8c0-4aa9-a81b-XXXXXXXXXXXX",
"deep-link": "https://console.aws.amazon.com/cloudwatch/home?region=ap-northeast-1#logEvent:group=/aws/codebuild/SampleProjectBuild;stream=408c5476-c8c0-4aa9-a81b-XXXXXXXXXXXX"
},
"phases": [
{
"phase-context": [],
"start-time": "Nov 11, 2019 5:03:42 AM",
"end-time": "Nov 11, 2019 5:03:42 AM",
"duration-in-seconds": 0,
"phase-type": "SUBMITTED",
"phase-status": "SUCCEEDED"
},
{
"phase-context": [],
"start-time": "Nov 11, 2019 5:03:42 AM",
"end-time": "Nov 11, 2019 5:03:44 AM",
"duration-in-seconds": 1,
"phase-type": "QUEUED",
"phase-status": "SUCCEEDED"
},
{
"phase-context": [
": "
],
"start-time": "Nov 11, 2019 5:03:44 AM",
"end-time": "Nov 11, 2019 5:03:59 AM",
"duration-in-seconds": 15,
"phase-type": "PROVISIONING",
"phase-status": "SUCCEEDED"
},
{
"phase-context": [
": "
],
"start-time": "Nov 11, 2019 5:03:59 AM",
"end-time": "Nov 11, 2019 5:04:02 AM",
"duration-in-seconds": 2,
"phase-type": "DOWNLOAD_SOURCE",
"phase-status": "SUCCEEDED"
},
{
"phase-context": [
": "
],
"start-time": "Nov 11, 2019 5:04:02 AM",
"end-time": "Nov 11, 2019 5:04:35 AM",
"duration-in-seconds": 33,
"phase-type": "INSTALL",
"phase-status": "SUCCEEDED"
},
{
"phase-context": [
": "
],
"start-time": "Nov 11, 2019 5:04:35 AM",
"end-time": "Nov 11, 2019 5:04:35 AM",
"duration-in-seconds": 0,
"phase-type": "PRE_BUILD",
"phase-status": "SUCCEEDED"
},
{
"phase-context": [
": "
],
"start-time": "Nov 11, 2019 5:04:35 AM",
"end-time": "Nov 11, 2019 5:04:53 AM",
"duration-in-seconds": 17,
"phase-type": "BUILD",
"phase-status": "SUCCEEDED"
},
{
"phase-context": [
": "
],
"start-time": "Nov 11, 2019 5:04:53 AM",
"end-time": "Nov 11, 2019 5:05:01 AM",
"duration-in-seconds": 8,
"phase-type": "POST_BUILD",
"phase-status": "SUCCEEDED"
},
{
"phase-context": [
": "
],
"start-time": "Nov 11, 2019 5:05:01 AM",
"end-time": "Nov 11, 2019 5:05:01 AM",
"duration-in-seconds": 0,
"phase-type": "UPLOAD_ARTIFACTS",
"phase-status": "SUCCEEDED"
},
{
"phase-context": [
": "
],
"start-time": "Nov 11, 2019 5:05:01 AM",
"end-time": "Nov 11, 2019 5:05:03 AM",
"duration-in-seconds": 2,
"phase-type": "FINALIZING",
"phase-status": "SUCCEEDED"
},
{
"start-time": "Nov 11, 2019 5:05:03 AM",
"phase-type": "COMPLETED"
}
],
"queued-timeout-in-minutes": 480
},
"current-phase": "COMPLETED",
"current-phase-context": "[: ]",
"version": "1"
},
"resources": [
"arn:aws:codebuild:ap-northeast-1:999999999999:build/SampleProjectBuild:408c5476-c8c0-4aa9-a81b-XXXXXXXXXXXX"
],
"additionalAttributes": {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment