Skip to content

Commit

Permalink
Use CloudWatch Event Rule instead of SNS
Browse files Browse the repository at this point in the history
  • Loading branch information
andreaswittig committed Jul 31, 2020
1 parent dcf4d3b commit b64477a
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 152 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
extends: google
parserOptions:
ecmaVersion: 6
ecmaVersion: 8
262 changes: 131 additions & 131 deletions handler.js
Original file line number Diff line number Diff line change
@@ -1,173 +1,173 @@
'use strict';
const AWS = require('aws-sdk');
const cloudwatch = new AWS.CloudWatch({apiVersion: '2010-08-01'});
const axios = require('axios');
const axiosRetry = require('axios-retry');

const STATE2ACTION = {
'ALARM': 'AlarmActions',
'OK': 'OKActions',
'INSUFFICIENT_DATA': 'InsufficientDataActions',
};

axiosRetry(axios, {retries: 5});

async function sendMessage(message) {
var res = await axios.post(process.env.WEBHOOK_URL, message);
await axios.post(process.env.WEBHOOK_URL, message);
};

async function processRecord(record) {
const subject = record.Sns.Subject;
const message = JSON.parse(record.Sns.Message);

await sendMessage({
"type": "message",
"attachments": [
function generateMessage(event) {
return {
'type': 'message',
'attachments': [
{
"contentType": "application/vnd.microsoft.card.adaptive",
"contentUrl": null,
"content": {
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.0",
"text": "test",
"body": [
'contentType': 'application/vnd.microsoft.card.adaptive',
'contentUrl': null,
'content': {
'$schema': 'http://adaptivecards.io/schemas/adaptive-card.json',
'type': 'AdaptiveCard',
'version': '1.0',
'text': 'test',
'body': [
{
"type": "Container",
"id": "b45f7e00-2ca4-4fc0-4096-d0de09701619",
"padding": "None",
"items": [
'type': 'Container',
'id': 'b45f7e00-2ca4-4fc0-4096-d0de09701619',
'padding': 'None',
'items': [
{
"type": "TextBlock",
"id": "85d96053-78c6-73e2-82d0-c5c6dc9819d9",
"text": "CloudWatch Alarm",
"wrap": true,
"size": "Large",
"color": "Accent"
}
]
'type': 'TextBlock',
'id': '85d96053-78c6-73e2-82d0-c5c6dc9819d9',
'text': 'CloudWatch Alarm',
'wrap': true,
'size': 'Large',
'color': 'Accent',
},
],
},
{
"type": "Container",
"id": "fc84a4e0-7745-127e-ece2-47ee0d0ad098",
"padding": "None",
"items": [
'type': 'Container',
'id': 'fc84a4e0-7745-127e-ece2-47ee0d0ad098',
'padding': 'None',
'items': [
{
"type": "ColumnSet",
"id": "6fc5ab8b-7065-d2f8-6c22-87aedd672b0b",
"columns": [
'type': 'ColumnSet',
'id': '6fc5ab8b-7065-d2f8-6c22-87aedd672b0b',
'columns': [
{
"type": "Column",
"id": "4392347b-7571-0251-d090-30a240765042",
"padding": "None",
"width": "auto",
"items": [
'type': 'Column',
'id': '4392347b-7571-0251-d090-30a240765042',
'padding': 'None',
'width': 'auto',
'items': [
{
"type": "Image",
"id": "01b0d507-65dd-739b-4ce0-bc53006aea75",
"url": "https://media.giphy.com/media/l2Je5IMLrZSbFD63S/giphy.gif",
"size": "Large"
}
]
'type': 'Image',
'id': '01b0d507-65dd-739b-4ce0-bc53006aea75',
'url': 'https://media.giphy.com/media/l2Je5IMLrZSbFD63S/giphy.gif',
'size': 'Large',
},
],
},
{
"type": "Column",
"padding": "None",
"width": "stretch",
"items": [
'type': 'Column',
'padding': 'None',
'width': 'stretch',
'items': [
{
"type": "TextBlock",
"id": "9553f7d0-5f4f-3c1c-c551-29900463a164",
"text": message.NewStateReason,
"wrap": true
}
]
}
'type': 'TextBlock',
'id': '9553f7d0-5f4f-3c1c-c551-29900463a164',
'text': event.detail.state.reason,
'wrap': true,
},
],
},
],
"padding": "None"
}
]
'padding': 'None',
},
],
},
{
"type": "Container",
"id": "67498f5d-6401-66fb-c432-262474da9418",
"padding": "None",
"items": [
'type': 'Container',
'id': '67498f5d-6401-66fb-c432-262474da9418',
'padding': 'None',
'items': [
{
"type": "ColumnSet",
"id": "396dfde9-ae77-26c9-0627-280605f705f1",
"columns": [
'type': 'ColumnSet',
'id': '396dfde9-ae77-26c9-0627-280605f705f1',
'columns': [
{
"type": "Column",
"items": [
'type': 'Column',
'items': [
{
"type": "FactSet",
"id": "26002a2b-5fa2-3ad2-83e1-a86c36410497",
"facts": [
'type': 'FactSet',
'id': '26002a2b-5fa2-3ad2-83e1-a86c36410497',
'facts': [
{
"title": "Time",
"value": message.StateChangeTime
'title': 'Time',
'value': event.time,
},
{
"title": "Alarm Name",
"value": message.AlarmName
}
]
}
'title': 'Alarm Name',
'value': event.detail.alarmName,
},
],
},
],
"padding": "None",
"width": 50
'padding': 'None',
'width': 50,
},
{
"type": "Column",
"padding": "None",
"width": 50,
"items": [
'type': 'Column',
'padding': 'None',
'width': 50,
'items': [
{
"type": "FactSet",
"id": "90eeb1ed-cb00-8cc5-57db-ec3689f3b7ba",
"facts": [
'type': 'FactSet',
'id': '90eeb1ed-cb00-8cc5-57db-ec3689f3b7ba',
'facts': [
{
"title": "Region",
"value": message.Region
'title': 'Region',
'value': event.regiom,
},
{
"title": "Account",
"value": message.AWSAccountId
}
]
}
]
}
'title': 'Account',
'value': event.account,
},
],
},
],
},
],
"padding": "None"
}
]
}
'padding': 'None',
},
],
},
],
"padding": "None"
}
}
]
});
'padding': 'None',
},
},
],
};
};

/*
example event:
{
"Records": [{
"EventSource": "aws:sns",
"EventVersion": "1.0",
"EventSubscriptionArn": "arn:aws:sns:us-east-1:XXX:cw-to-slack-Topic-1B8S548158492:a0e76b10-796e-471d-82d3-0510fc89ad93",
"Sns": {
"Type": "Notification",
"MessageId": "[...]",
"TopicArn": "arn:aws:sns:us-east-1:XXX:cw-to-slack-Topic-1B8S548158492",
"Subject": "ALARM: \"cw-to-slack-Alarm-9THDKWBS1876\" in US East (N. Virginia)",
"Message": "{\"AlarmName\":\"cw-to-slack-Alarm-9THDKWBS1876\",\"AlarmDescription\":null,\"AWSAccountId\":\"XXX\",\"NewStateValue\":\"ALARM\",\"NewStateReason\":\"Threshold Crossed: 1 datapoint [3.22 (29/10/17 13:20:00)] was greater than the threshold (1.0).\",\"StateChangeTime\":\"2017-10-30T13:20:35.831+0000\",\"Region\":\"US East (N. Virginia)\",\"OldStateValue\":\"INSUFFICIENT_DATA\",\"Trigger\":{\"MetricName\":\"EstimatedCharges\",\"Namespace\":\"AWS/Billing\",\"StatisticType\":\"Statistic\",\"Statistic\":\"MAXIMUM\",\"Unit\":null,\"Dimensions\":[{\"name\":\"Currency\",\"value\":\"USD\"}],\"Period\":86400,\"EvaluationPeriods\":1,\"ComparisonOperator\":\"GreaterThanThreshold\",\"Threshold\":1.0,\"TreatMissingData\":\"\",\"EvaluateLowSampleCountPercentile\":\"\"}}",
"Timestamp": "2017-10-30T13:20:35.855Z",
"SignatureVersion": "1",
"Signature": "[...]",
"SigningCertUrl": "[...]",
"UnsubscribeUrl": "[...]",
"MessageAttributes": {}
}
}]
}
*/
exports.processEvent = async function(event) {
for (const record of event.Records) {
await processRecord(record);
console.log(event);
const data = await cloudwatch.describeAlarms({
AlarmNames: [event.detail.alarmName],
MaxRecords: 1,
}).promise();
const alarms = [...data.CompositeAlarms, ...data.MetricAlarms];
if (alarms.length === 0) {
return;
} else {
const alarm = alarms[0];
const action = STATE2ACTION[event.detail.state.value];
const actions = alarm[action];
if (alarm.ActionsEnabled) {
if (actions.filter((action) => action.includes(':autoscaling:')).length > 0) {
console.log('Dropped auto-scaling alarm.');
} else {
await sendMessage(generateMessage(event));
}
}
}
};
42 changes: 22 additions & 20 deletions template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Parameters:
Resources:
Topic:
Type: 'AWS::SNS::Topic'
LambdaFunction:
ForwardAlarmFunction:
Type: 'AWS::Serverless::Function'
Properties:
Handler: 'handler.processEvent'
Expand All @@ -20,24 +20,26 @@ Resources:
Variables:
WEBHOOK_URL: !Ref WebhookURL
Events:
SNS:
Type: SNS
EventRule:
Type: EventBridgeRule
Properties:
Topic: !Ref Topic
ErrorsTooHighAlarm:
Type: 'AWS::CloudWatch::Alarm'
Pattern:
source:
- 'aws.cloudwatch'
'detail-type':
- 'CloudWatch Alarm State Change'
detail:
state:
value:
- ALARM
Policies:
- !Ref ForwardAlarmPolicy
ForwardAlarmPolicy:
Type: 'AWS::IAM::ManagedPolicy'
Properties:
AlarmDescription: 'Invocations failed due to errors in the function'
Namespace: 'AWS/Lambda'
MetricName: Errors
Dimensions:
- Name: FunctionName
Value: !Ref LambdaFunction
Statistic: Sum
Period: 60
EvaluationPeriods: 1
ComparisonOperator: GreaterThanThreshold
Threshold: 0
TreatMissingData: notBreaching
AlarmActions:
- !Ref Topic
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: 'cloudwatch:describeAlarms'
Resource: '*'

0 comments on commit b64477a

Please sign in to comment.