////// Save as index.js and upload it to Lambda as zip archive with node_modules directory. After: ////// npm install aws-cloudwatch-chart ////// npm install request ////// no need to upload aws-sdk module ////// Don't forget to change API keys here. ////// License: MIT ////// Docs: ////// https://github.com/jeka-kiselyov/aws-cloudwatch-chart ////// http://docs.aws.amazon.com/sns/latest/dg/sns-lambda.html ////// http://docs.aws.amazon.com/lambda/latest/dg/walkthrough-s3-events-adminuser-create-test-function-create-function.html ////// exports.handler = function(event, context) { var request = require('request'); var fs = require('fs'); var AwsCloudWatchChart = require('aws-cloudwatch-chart'); var config = {}; config.slack = { token: 'xoxp-4234234-234234-234234234-257abf', channel: '#aws', initialComment: "EC2 CPU Usage %from_time% to %to_time% UTC", fileTitle: "EC2 CPU Usage %from_time% to %to_time% UTC" }; config.aws = { accessKeyId: "ASDASDSADSADASD", secretAccessKey: "dsfsdfsdf/REWR/fdsdf/DFDSf34", region: "us-east-1" }; config.timeOffset = 1440; config.timePeriod = 60; config.graphSamples = 20; config.width = 1000; config.height = 250; if (typeof(event.Records) === 'undefined' || typeof(event.Records[0]) === 'undefined' || typeof(event.Records[0].Sns) === 'undefined') context.fail ('ERROR: requires SNS message'); if (typeof(event.Records[0].Sns.Message) !== 'undefined' && typeof(event.Records[0].Sns.Message.Trigger) === 'undefined') event.Records[0].Sns.Message = JSON.parse(event.Records[0].Sns.Message); config.slack.initialComment = event.Records[0].Sns.Subject + "\n" + event.Records[0].Sns.Message.AlarmDescription; config.metrics = []; console.log('event.Records[0].Sns.Message:'); console.log(event.Records[0].Sns.Message); if (typeof(event.Records[0].Sns.Message.Trigger) !== 'undefined' && typeof(event.Records[0].Sns.Message.Trigger.Dimensions) !== 'undefined') { if (event.Records[0].Sns.Message.Trigger.Namespace == 'AWS/EC2' && event.Records[0].Sns.Message.Trigger.MetricName == 'CPUUtilization') { config.metrics.push({ InstanceId: event.Records[0].Sns.Message.Trigger.Dimensions[0].value, title: event.Records[0].Sns.Message.Trigger.Dimensions[0].value+" EC2 Max CPU Usage", Namespace: event.Records[0].Sns.Message.Trigger.Namespace, MetricName: event.Records[0].Sns.Message.Trigger.MetricName, StatisticValues: "Maximum", Unit: "Percent", color: "af9cf4", thickness: 2, dashed: false }); } else if (event.Records[0].Sns.Message.Trigger.Namespace == 'AWS/RDS' && event.Records[0].Sns.Message.Trigger.MetricName == 'CPUUtilization') { config.metrics.push({ DBInstanceIdentifier: event.Records[0].Sns.Message.Trigger.Dimensions[0].value, title: event.Records[0].Sns.Message.Trigger.Dimensions[0].value+" DB Max CPU Usage", Namespace: event.Records[0].Sns.Message.Trigger.Namespace, MetricName: event.Records[0].Sns.Message.Trigger.MetricName, StatisticValues: "Maximum", Unit: "Percent", color: "9caff4", thickness: 2, dashed: false }); } else if (event.Records[0].Sns.Message.Trigger.Namespace == 'AWS/EC2' && event.Records[0].Sns.Message.Trigger.MetricName == 'CPUCreditBalance') { config.metrics.push({ InstanceId: event.Records[0].Sns.Message.Trigger.Dimensions[0].value, title: event.Records[0].Sns.Message.Trigger.Dimensions[0].value+" CPU Credit Balance", Namespace: event.Records[0].Sns.Message.Trigger.Namespace, MetricName: event.Records[0].Sns.Message.Trigger.MetricName, StatisticValues: "Maximum", Unit: "Count", color: "9caff4", thickness: 2, dashed: false }); } } var postSlackMessage = function(text, imageURL, callback) { var apiURL = "https://slack.com/api/chat.postMessage?token=" + encodeURIComponent(config.slack.token) + "&text=" + encodeURIComponent("ALERT\n"+imageURL) + "&username=" + encodeURIComponent('AWS') + "&as_user=" + encodeURIComponent('false') + "&icon_emoji=" + encodeURIComponent(':bell:') + "&attachments=" + encodeURIComponent('[{"fallback": '+JSON.stringify(text)+',"text": '+JSON.stringify(text)+', "color": "danger"}]') + "&channel=" + encodeURIComponent(config.slack.channel); var req = request.post(apiURL, callback); } if (config.metrics.length < 1) { /// post postSlackMessage(config.slack.initialComment, '', function() { context.done(null, 'Not AWS/EC2 CPUUtilization metric'); }); } else { var acs = new AwsCloudWatchChart(config); console.log('Start'); acs.getChart().then(function(chart){ console.log('Got chart URL'); console.log(chart.getURL()); chart.get().then(function(image){ console.log('Got chart image'); var fileTitle = config.slack.fileTitle. split('%from_time%').join(acs.getFromTimeString()). split('%to_time%').join(acs.getToTimeString()); var initialComment = config.slack.initialComment. split('%from_time%').join(acs.getFromTimeString()). split('%to_time%').join(acs.getToTimeString()); var apiURL = "https://slack.com/api/files.upload?token=" + encodeURIComponent(config.slack.token) + "&filename=" + encodeURIComponent("image.png") + "&title=" + encodeURIComponent(fileTitle) + "&initial_comment=" + encodeURIComponent(initialComment); console.log('Sending file to Slack...'); var callback = function (err, response, body) { var data = JSON.parse(body); var text = config.slack.initialComment; postSlackMessage(text, data.file.url, function() { context.done(null, "Done"); }); } var req = request.post(apiURL, callback); var form = req.form(); form.append('file', new Buffer(image), {contentType: 'image/png', filename: 'x.png', name: 'x.png'}); }); }); } };