From b6a6bef52704712bc32704e6da9e3fe5d9aeb6f6 Mon Sep 17 00:00:00 2001 From: davinerd Date: Sun, 26 Nov 2017 15:12:58 +0100 Subject: [PATCH] added slack notification --- Chaosfile.json | 6 ++++ lambda/index.js | 89 ++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 91 insertions(+), 4 deletions(-) diff --git a/Chaosfile.json b/Chaosfile.json index 039e7b7..8f27f41 100644 --- a/Chaosfile.json +++ b/Chaosfile.json @@ -4,5 +4,11 @@ "enableForASGs": [ ], "disableForASGs": [ + ], + "slackWebhook": [ + { + "channel": "#random", + "webhookId": "XXXXXXXXX" + } ] } diff --git a/lambda/index.js b/lambda/index.js index 89b299a..e6ec251 100644 --- a/lambda/index.js +++ b/lambda/index.js @@ -2,6 +2,8 @@ // provided under the terms of either of those licenses. var AWS = require('aws-sdk'); +var https = require('https'); +var util = require('util'); var llamaConfig = require('./config.json'); AWS.config.region = llamaConfig.region || 'eu-west-1'; @@ -29,6 +31,7 @@ ec2.describeInstances(function(err, data) { } var candidates = []; + var asgNames = []; data.Reservations.forEach(function(res) { res.Instances.forEach(function(inst) { inst.Tags.forEach(function(tag) { @@ -38,11 +41,13 @@ ec2.describeInstances(function(err, data) { // this takes precedence - if defined we don't even look at disableForASGs if (llamaConfig.enableForASGs.indexOf(tag.Value) !== -1) { candidates.push(inst); + asgNames.push(tag.Value); } } else { if (llamaConfig.disableForASGs) { if (llamaConfig.disableForASGs.indexOf(tag.Value) === -1) { candidates.push(inst); + asgNames.push(tag.Value); } } } @@ -61,9 +66,63 @@ ec2.describeInstances(function(err, data) { var random = Math.floor(Math.random() * numInstances); var target = candidates[random]; + var asgName = asgNames[random]; console.log('Going to terminate instance with id = %s', target.InstanceId); + if (llamaConfig.slackWebhook) { + llamaConfig.slackWebhook.forEach(function(slack) { + if ( (slack.channel === null || typeof slack.channel === 'undefined') || (slack.webhookId === null || typeof slack.webhookId === 'undefined')) { + console.log('No channel or webhook specified. Slack message not sent.'); + return context.done(null); + } + + if (slack.username === null || typeof slack.username === 'undefined') { + slack.username = "Chaos Lambda"; + } + + // code taken from https://gist.github.com/stack72/ad97da2df376754e413a + var slackMessage = [ + "*Event*: CHAOS_TERMINATION - ShutdownInstance", + "*Description*: Going to terminate instance with id " + target.InstanceId + " (ASG *" + asgName + "*)", + "*Cause*: At " + getTimestamp() + " Chaos Lambda struk again!", + ].join("\n"); + + var postData = { + channel: slack.channel, + username: slack.username, + text: "*Chaos Lambda Termination Notification*", + attachments: [{ text: slackMessage, mrkdwn_in: ["text"] }] + }; + + var options = { + method: 'POST', + hostname: 'hooks.slack.com', + port: 443, + path: '/services/' + slack.webhookId + }; + + var req = https.request(options, function(res) { + res.setEncoding('utf8'); + if (res.statusCode !== "200") { + console.log('HTTP status code: %s', res.statusCode); + console.log('HTTP headers: %s', res.headers); + } + res.on('data', function (chunk) { + context.done(null); + }); + }); + + req.on('error', function(e) { + context.fail(e); + console.log('request error: ' + e.message); + }); + + req.write(util.format("%j", postData)); + req.end(); + }); + } + ec2.terminateInstances({InstanceIds:[target.InstanceId]}, function(err, data) { if (err) { return context.done(err, null); @@ -75,7 +134,29 @@ ec2.describeInstances(function(err, data) { }); }; -function randomIntFromInterval(min,max) -{ - return Math.floor(Math.random()*(max-min+1)+min); -} \ No newline at end of file +function randomIntFromInterval(min,max) { + return Math.floor(Math.random()*(max-min+1)+min); +} + +function getTimestamp() { + var date = new Date(); + + var hour = date.getHours(); + hour = (hour < 10 ? "0" : "") + hour; + + var min = date.getMinutes(); + min = (min < 10 ? "0" : "") + min; + + var sec = date.getSeconds(); + sec = (sec < 10 ? "0" : "") + sec; + + var year = date.getFullYear(); + + var month = date.getMonth() + 1; + month = (month < 10 ? "0" : "") + month; + + var day = date.getDate(); + day = (day < 10 ? "0" : "") + day; + + return year + "-" + month + "-" + day + " " + hour + ":" + min + ":" + sec; +}