Last active
February 6, 2019 12:00
-
-
Save zyphlar/7eb181a4aa6d21b6674b6c2dc4af2104 to your computer and use it in GitHub Desktop.
See comments
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
/** | |
* See http://notes.webutvikling.org/send-aws-cloudwatch-alarms-to-slack/ for instructions | |
* But I like this code better because the snsToSlack.js code doesn't parse the CloudWatch JSON | |
* | |
* Follow these steps to configure the webhook in Slack: | |
* | |
* 1. Navigate to https://<your-team-domain>.slack.com/services/new | |
* | |
* 2. Search for and select "Incoming WebHooks". | |
* | |
* 3. Choose the default channel where messages will be sent and click "Add Incoming WebHooks Integration". | |
* | |
* 4. Copy the webhook URL from the setup instructions and use it in hookUrl environment variable, OR follow the encryption instructions below. | |
* | |
* 5. Type the channel for messages to be sent into the slackChannel environment variable. | |
* | |
* | |
* To encrypt your secrets use the following steps: | |
* | |
* 1. Create or use an existing KMS Key - http://docs.aws.amazon.com/kms/latest/developerguide/create-keys.html | |
* | |
* 2. Click the "Enable Encryption Helpers" checkbox | |
* | |
* 3. Paste <SLACK_HOOK_URL> into the kmsEncryptedHookUrl environment variable and click encrypt | |
* | |
* Note: You must exclude the protocol from the URL (e.g. "hooks.slack.com/services/abc123"). | |
* | |
* 4. Give your function's role permission for the kms:Decrypt action. | |
* Example: | |
{ | |
"Version": "2012-10-17", | |
"Statement": [ | |
{ | |
"Sid": "Stmt1443036478000", | |
"Effect": "Allow", | |
"Action": [ | |
"kms:Decrypt" | |
], | |
"Resource": [ | |
"<your KMS key ARN>" | |
] | |
} | |
] | |
} | |
*/ | |
const AWS = require('aws-sdk'); | |
const url = require('url'); | |
const https = require('https'); | |
// The base-64 encoded, encrypted key (CiphertextBlob) stored in the kmsEncryptedHookUrl environment variable | |
const kmsEncryptedHookUrl = process.env.kmsEncryptedHookUrl; | |
// The Slack channel to send a message to stored in the slackChannel environment variable | |
const slackChannel = process.env.slackChannel; | |
const hookUrl = process.env.hookUrl; | |
var goodStates = [ | |
"OK" | |
]; | |
var badStates = [ | |
"ALARM" | |
]; | |
// unused because default is warning | |
//var neutralStates = [ | |
// "INSUFFICIENT_DATA" | |
//]; | |
function postMessage(message, callback) { | |
const body = JSON.stringify(message); | |
const options = url.parse(hookUrl); | |
options.method = 'POST'; | |
options.headers = { | |
'Content-Type': 'application/json', | |
'Content-Length': Buffer.byteLength(body), | |
}; | |
const postReq = https.request(options, (res) => { | |
const chunks = []; | |
res.setEncoding('utf8'); | |
res.on('data', (chunk) => chunks.push(chunk)); | |
res.on('end', () => { | |
if (callback) { | |
callback({ | |
body: chunks.join(''), | |
statusCode: res.statusCode, | |
statusMessage: res.statusMessage, | |
}); | |
} | |
}); | |
return res; | |
}); | |
postReq.write(body); | |
postReq.end(); | |
} | |
function processEvent(event, callback) { | |
const subject = event.Records[0].Sns.Subject; | |
const message = JSON.parse(event.Records[0].Sns.Message); | |
// start the process with a default severity. | |
var severity = "warning"; | |
const alarmName = message.AlarmName; | |
//var oldState = message.OldStateValue; | |
const newState = message.NewStateValue; | |
const reason = message.NewStateReason; | |
for(var state in badStates) { | |
if (newState.indexOf(badStates[state]) != -1) { | |
severity = "danger"; | |
break; | |
} | |
} | |
// only check for good states if state hasn't changed | |
if (severity == "warning") { | |
for(var state in goodStates) { | |
if (newState.indexOf(goodStates[state]) != -1) { | |
severity = "good"; | |
break; | |
} | |
} | |
} | |
const slackMessage = { | |
channel: slackChannel, | |
attachments: [{ | |
color: severity, | |
text: `${alarmName} state is now ${newState}: ${reason}`, | |
}], | |
text: "*" + subject + "*", | |
icon_emoji: ":lightning_cloud:" | |
}; | |
postMessage(slackMessage, (response) => { | |
if (response.statusCode < 400) { | |
console.info('Message posted successfully'); | |
callback(null); | |
} else if (response.statusCode < 500) { | |
console.error(`Error posting message to Slack API: ${response.statusCode} - ${response.statusMessage}`); | |
callback(null); // Don't retry because the error is due to a problem with the request | |
} else { | |
// Let Lambda retry | |
callback(`Server error when processing message: ${response.statusCode} - ${response.statusMessage}`); | |
} | |
}); | |
} | |
exports.handler = (event, context, callback) => { | |
if (hookUrl) { | |
// Container reuse, simply process the event with the key in memory | |
processEvent(event, callback); | |
} else if (kmsEncryptedHookUrl && kmsEncryptedHookUrl !== '<kmsEncryptedHookUrl>') { | |
const encryptedBuf = new Buffer(kmsEncryptedHookUrl, 'base64'); | |
const cipherText = { CiphertextBlob: encryptedBuf }; | |
const kms = new AWS.KMS(); | |
kms.decrypt(cipherText, (err, data) => { | |
if (err) { | |
console.log('Decrypt error:', err); | |
return callback(err); | |
} | |
hookUrl = `https://${data.Plaintext.toString('ascii')}`; | |
processEvent(event, callback); | |
}); | |
} else { | |
callback('Hook URL has not been set.'); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment