From c9842f7878c60c13566e65c27d5a6fd34f07b131 Mon Sep 17 00:00:00 2001 From: ramil Date: Fri, 20 Sep 2019 00:16:29 +0300 Subject: [PATCH] Add support Amazon ECS Event Stream for CloudWatch Events --- index.js | 58 +++++++++++++++++++++- package.json | 5 +- scripts/test.sh | 4 +- test/sns-cloudwatch-event-ecs-pending.json | 18 +++++++ test/sns-cloudwatch-event-ecs-stopped.json | 18 +++++++ 5 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 test/sns-cloudwatch-event-ecs-pending.json create mode 100644 test/sns-cloudwatch-event-ecs-stopped.json diff --git a/index.js b/index.js index c61ab4e..3cc97de 100644 --- a/index.js +++ b/index.js @@ -194,7 +194,7 @@ var handleCodePipeline = function(event, context) { }; var handleElasticache = function(event, context) { - var subject = "AWS ElastiCache Notification" + var subject = "AWS ElastiCache Notification"; var message = JSON.parse(event.Records[0].Sns.Message); var timestamp = (new Date(event.Records[0].Sns.Timestamp)).getTime()/1000; var region = event.Records[0].EventSubscriptionArn.split(":")[3]; @@ -227,6 +227,56 @@ var handleElasticache = function(event, context) { return _.merge(slackMessage, baseSlackMessage); }; +var handleCloudWatchEventECS = function(event, context) { + var timestamp = (new Date(event.Records[0].Sns.Timestamp)).getTime()/1000; + var message = JSON.parse(event.Records[0].Sns.Message); + var region = event.Records[0].EventSubscriptionArn.split(":")[3]; + var subject = "AWS CloudWatch Notification"; + var fields = []; + + + try { + message = JSON.parse(event.Records[0].Sns.Message); + const detailType = message['detail-type']; + const status = message.detail.lastStatus; + + let color = "danger"; + + if (status === "RUNNING") { + color = "good"; + } else if (status === "PENDING") { + color = "warning"; + } + + const container = message.detail.containers[0].name; + const stoppedReason = message.detail.stoppedReason; + + fields.push({ "title": detailType, "value": "", "short": false }); + fields.push({ "title": "Container", "value": container, "short": false }); + fields.push({ "title": "Status", "value": status, "short": false }); + if (stoppedReason) { + fields.push({ "title": "Reason", "value": stoppedReason, "short": false }); + } + + var slackMessage = { + text: "*" + subject + "*", + attachments: [ + { + "color": color, + "fields": fields, + "ts": timestamp + } + ] + }; + + return _.merge(slackMessage, baseSlackMessage); + } + catch(e) { + console.log(e); + return handleCatchAll(event, context); + } +}; + var handleCloudWatch = function(event, context) { var timestamp = (new Date(event.Records[0].Sns.Timestamp)).getTime()/1000; var message = JSON.parse(event.Records[0].Sns.Message); @@ -364,7 +414,7 @@ var processEvent = function(event, context) { try { eventSnsMessage = JSON.parse(eventSnsMessageRaw); } - catch (e) { + catch (e) { } if(eventSubscriptionArn.indexOf(config.services.codepipeline.match_text) > -1 || eventSnsSubject.indexOf(config.services.codepipeline.match_text) > -1 || eventSnsMessageRaw.indexOf(config.services.codepipeline.match_text) > -1){ @@ -379,6 +429,10 @@ var processEvent = function(event, context) { console.log("processing cloudwatch notification"); slackMessage = handleCloudWatch(event,context); } + else if(eventSnsMessage && 'source' in eventSnsMessage && eventSnsMessage.source === 'aws.ecs'){ + console.log("processing cloudwatch ECS event notification"); + slackMessage = handleCloudWatchEventECS(event,context); + } else if(eventSubscriptionArn.indexOf(config.services.codedeploy.match_text) > -1 || eventSnsSubject.indexOf(config.services.codedeploy.match_text) > -1 || eventSnsMessageRaw.indexOf(config.services.codedeploy.match_text) > -1){ console.log("processing codedeploy notification"); slackMessage = handleCodeDeploy(event,context); diff --git a/package.json b/package.json index 6e1e021..6923681 100644 --- a/package.json +++ b/package.json @@ -2,10 +2,11 @@ "name": "lambda-cloudwatch-slack", "version": "0.3.0", "description": "Better Slack notifications for AWS CloudWatch", - "authors": [ + "authors": [ "Christopher Reichert ", "Cody Reichert ", - "Alexandr Promakh " + "Alexandr Promakh ", + "Ramil Amerzyanov " ], "config": { "progress": "true" diff --git a/scripts/test.sh b/scripts/test.sh index c3e1b27..e26925a 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -10,4 +10,6 @@ $NODE_LAMBDA run -x test/context.json -j test/sns-elastic-beanstalk-event.json $NODE_LAMBDA run -x test/context.json -j test/sns-codedeploy-event.json $NODE_LAMBDA run -x test/context.json -j test/sns-codedeploy-configuration.json $NODE_LAMBDA run -x test/context.json -j test/sns-elasticache-event.json -$NODE_LAMBDA run -x test/context.json -j test/sns-autoscaling-event.json \ No newline at end of file +$NODE_LAMBDA run -x test/context.json -j test/sns-autoscaling-event.json +$NODE_LAMBDA run -x test/context.json -j test/sns-cloudwatch-event-ecs-stopped.json +$NODE_LAMBDA run -x test/context.json -j test/sns-cloudwatch-event-ecs-pending.json \ No newline at end of file diff --git a/test/sns-cloudwatch-event-ecs-pending.json b/test/sns-cloudwatch-event-ecs-pending.json new file mode 100644 index 0000000..63dc284 --- /dev/null +++ b/test/sns-cloudwatch-event-ecs-pending.json @@ -0,0 +1,18 @@ +{ + "Records": [ + { + "EventSource": "aws:sns", + "EventVersion": "1.0", + "EventSubscriptionArn": "arn:aws:sns:us-west-2:123456789123:CloudWatchNotifications:00000000-0000-0000-0000-000000000000", + "Sns": { + "Type": "Notification", + "MessageId": "00000000-0000-0000-0000-000000000000", + "TopicArn": "arn:aws:sns:us-west-2:123456789123:CloudWatchNotifications", + "Subject": null, + "Message": "{\"version\":\"0\",\"id\":\"5161328b-b6f8-c850-4e39-52e973dafd49\",\"detail-type\":\"ECS Task State Change\",\"source\":\"aws.ecs\",\"account\":\"000000000000\",\"time\":\"2019-09-19T13:26:12Z\",\"region\":\"us-east-1\",\"resources\":[\"arn:aws:ecs:us-east-1:000000000000:task/c08044ec-8b75-41ad-bdbb-8481e097fbae\"],\"detail\":{\"clusterArn\":\"arn:aws:ecs:us-east-1:000000000000:cluster/dev\",\"containerInstanceArn\":\"arn:aws:ecs:us-east-1:000000000000:container-instance/72609cd7-7211-4834-8120-b41c9d2234a9\",\"containers\":[{\"containerArn\":\"arn:aws:ecs:us-east-1:000000000000:container/b4d836b9-d9a1-4275-9536-b194b81d9930\",\"lastStatus\":\"PENDING\",\"name\":\"mycontainername\",\"taskArn\":\"arn:aws:ecs:us-east-1:000000000000:task/c08044ec-8b75-41ad-bdbb-8481e097fbae\",\"networkInterfaces\":[],\"cpu\":\"128\",\"memory\":\"128\"}],\"createdAt\":\"2019-09-19T13:26:12.237Z\",\"launchType\":\"EC2\",\"cpu\":\"128\",\"memory\":\"128\",\"desiredStatus\":\"RUNNING\",\"group\":\"service:mycontainername\",\"lastStatus\":\"PENDING\",\"overrides\":{\"containerOverrides\":[{\"name\":\"mycontainername\"}]},\"attachments\":[],\"startedBy\":\"ecs-svc/9223370467957936499\",\"updatedAt\":\"2019-09-19T13:26:12.237Z\",\"taskArn\":\"arn:aws:ecs:us-east-1:000000000000:task/c08044ec-8b75-41ad-bdbb-8481e097fbae\",\"taskDefinitionArn\":\"arn:aws:ecs:us-east-1:000000000000:task-definition/mycontainername:3\",\"version\":1}}", + "Timestamp": "2019-09-19T13:26:12.587Z", + "MessageAttributes": {} + } + } + ] +} \ No newline at end of file diff --git a/test/sns-cloudwatch-event-ecs-stopped.json b/test/sns-cloudwatch-event-ecs-stopped.json new file mode 100644 index 0000000..2c77ca4 --- /dev/null +++ b/test/sns-cloudwatch-event-ecs-stopped.json @@ -0,0 +1,18 @@ +{ + "Records": [ + { + "EventSource": "aws:sns", + "EventVersion": "1.0", + "EventSubscriptionArn": "arn:aws:sns:us-west-2:123456789123:CloudWatchNotifications:00000000-0000-0000-0000-000000000000", + "Sns": { + "Type": "Notification", + "MessageId": "00000000-0000-0000-0000-000000000000", + "TopicArn": "arn:aws:sns:us-west-2:123456789123:CloudWatchNotifications", + "Subject": null, + "Message": "{\"version\":\"0\",\"id\":\"790f94d1-41c7-859d-68af-7d040bc2ca9f\",\"detail-type\":\"ECS Task State Change\",\"source\":\"aws.ecs\",\"account\":\"000000000000\",\"time\":\"2019-09-19T13:25:44Z\",\"region\":\"us-east-1\",\"resources\":[\"arn:aws:ecs:us-east-1:000000000000:task/4097e8a3-3989-41d4-9494-81f97a2cb74d\"],\"detail\":{\"clusterArn\":\"arn:aws:ecs:us-east-1:000000000000:cluster/dev\",\"containerInstanceArn\":\"arn:aws:ecs:us-east-1:000000000000:container-instance/72609cd7-7211-4834-8120-b41c9d2234a9\",\"containers\":[{\"containerArn\":\"arn:aws:ecs:us-east-1:000000000000:container/dd3b6843-b5d1-401a-a319-6c8d8574017d\",\"exitCode\":137,\"lastStatus\":\"STOPPED\",\"name\":\"mycontainername\",\"runtimeId\":\"a01ca4d3390aae111d96e99d2759e346c5f3aed60560d4d8d2f9d4afa313a191\",\"taskArn\":\"arn:aws:ecs:us-east-1:000000000000:task/4097e8a3-3989-41d4-9494-81f97a2cb74d\",\"networkInterfaces\":[],\"cpu\":\"128\",\"memory\":\"128\"}],\"createdAt\":\"2019-09-19T13:19:41.935Z\",\"launchType\":\"EC2\",\"cpu\":\"128\",\"memory\":\"128\",\"desiredStatus\":\"STOPPED\",\"group\":\"service:mycontainername\",\"lastStatus\":\"STOPPED\",\"overrides\":{\"containerOverrides\":[{\"name\":\"mycontainername\"}]},\"attachments\":[],\"connectivity\":\"CONNECTED\",\"connectivityAt\":\"2019-09-19T13:19:41.935Z\",\"pullStartedAt\":\"2019-09-19T13:19:42.79Z\",\"startedAt\":\"2019-09-19T13:19:42.79Z\",\"startedBy\":\"ecs-svc/9223370467957936499\",\"stoppingAt\":\"2019-09-19T13:25:44.03Z\",\"stoppedAt\":\"2019-09-19T13:25:44.03Z\",\"pullStoppedAt\":\"2019-09-19T13:19:42.79Z\",\"executionStoppedAt\":\"2019-09-19T13:25:44Z\",\"stoppedReason\":\"Essential container in task exited\",\"stopCode\":\"EssentialContainerExited\",\"updatedAt\":\"2019-09-19T13:25:44.03Z\",\"taskArn\":\"arn:aws:ecs:us-east-1:000000000000:task/4097e8a3-3989-41d4-9494-81f97a2cb74d\",\"taskDefinitionArn\":\"arn:aws:ecs:us-east-1:000000000000:task-definition/mycontainername:3\",\"version\":3}}", + "Timestamp": "2019-09-19T13:25:44.297Z", + "MessageAttributes": {} + } + } + ] +} \ No newline at end of file