Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save sanggiChoi/eae3cc7e054b32247aca3fbb8d22747f to your computer and use it in GitHub Desktop.

Select an option

Save sanggiChoi/eae3cc7e054b32247aca3fbb8d22747f to your computer and use it in GitHub Desktop.

Revisions

  1. @rantav rantav renamed this gist Jan 19, 2016. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. @rantav rantav revised this gist Jan 18, 2016. 1 changed file with 9 additions and 0 deletions.
    9 changes: 9 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -3,6 +3,15 @@
    ## What is this?
    AWS have released a new featue called CloudWatch Events, which lets you configure events fired by cloudwatch and direct them to SNS, Lambda functions, etc. Here's the [blog post](https://aws.amazon.com/blogs/aws/new-cloudwatch-events-track-and-respond-to-changes-to-your-aws-resources/)

    ## Motivational image:
    Here's the motivational image:

    ![Slack image](https://jumpshare.com/v/I0DarhG7O56FxiEabgsN+/Screen+Shot+2016-01-19+at+1.22.37+AM.png)





    The set of supported events sources is still somewhat limited, but this is way better than polling, which is what we had to do up until now...

    In this gist you'll learn how to create such event and post updates to slack whenever an EC2 instance changes state (e.g. starting, terminating etc)
  3. @rantav rantav revised this gist Jan 18, 2016. 2 changed files with 82 additions and 16 deletions.
    15 changes: 12 additions & 3 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -40,8 +40,17 @@ You may of course use similar events to send SNS notofications to emails or anyt
    ]
    }
    ```
    5. Create a new CloudWatch Event Rule to send EC2 events to this lambda function
    5. Add the following permission to the same IAM role as before in order to allow describing EC2 instnaces:
    ```
    {
    "Effect": "Allow",
    "Action": "ec2:Describe*",
    "Resource": "*"
    }
    ```
    6. Create a new CloudWatch Event Rule to send EC2 events to this lambda function
    Screenshot: http://jmp.sh/uBi6dV8
    6. You may test this by terminating and lanching an EC2 instance.
    7. You may test this by terminating and lanching an EC2 instance.
    Example output on Slack: `aws.ec2 (us-west-2): i-531a188a is shutting-down`
    7. Prosper
    8. Prosper
    83 changes: 70 additions & 13 deletions cloudwatch-event-to-slack.js
    Original file line number Diff line number Diff line change
    @@ -22,9 +22,9 @@ const qs = require('querystring');


    exports.handler = function(event, context) {
    var token = null;
    console.log('event=%j', event);
    var slackReqOpts = null;
    if (token) {
    if (slackReqOpts) {
    // Container reuse, simply process the event with the key in memory
    processEvent(event, context, slackReqOpts);
    } else {
    @@ -39,7 +39,7 @@ exports.handler = function(event, context) {
    } else {
    token = data.Plaintext.toString('ascii');
    const slackUrl = SLACK_URL;
    slackReqOpts = url.parse(slackUrl + '?token=' + token);
    slackReqOpts = url.parse(slackUrl + token);
    slackReqOpts.method = 'POST';
    slackReqOpts.headers = {'Content-Type': 'application/json'};
    processEvent(event, context, slackReqOpts);
    @@ -48,21 +48,56 @@ exports.handler = function(event, context) {
    }
    };


    var processEvent = function(event, context, slackReqOpts) {
    var source = event.source;
    var region = event.region;
    var detail = event.detail;
    var instanceId = detail['instance-id'];
    var state = detail.state;
    var text = [];
    text.push(source);
    text.push(' (' + region + ')');
    text.push(': ');
    text.push(instanceId);
    text.push(' is ');
    text.push(state);

    var detail = event.detail;
    if (source === 'aws.ec2') {
    var instanceId = detail['instance-id'];
    var ec2 = new AWS.EC2();
    ec2.describeInstances({InstanceIds: [instanceId]}, function(error, data) {
    if (error) {
    console.error(error); // an error occurred
    context.fail(error);
    } else {
    var instance = data.Reservations[0].Instances[0];
    var type = instance.InstanceType
    var name = getName(instance.Tags);
    console.log('type=%s name=%s', type, name);
    var state = detail.state;
    text.push(instanceId);
    text.push(' (')
    if (name) {
    text.push(name);
    text.push(', ');
    }
    text.push(type);
    text.push(') ')
    text.push(' is ');
    text.push(state);
    text = text.join('');
    var url = getEc2Url(instanceId, region);
    var extraText = 'See <' + url + '|' + instanceId + '>';
    postText(text, extraText, slackReqOpts, context);
    }
    });
    } else {
    text = text.join('');
    postText(text, '', slackReqOpts, context);
    }
    };

    var getEc2Url = function(instanceId, region) {
    return 'https://' + region + '.console.aws.amazon.com/ec2/v2/home?region=' + region + '#Instances:search=' + instanceId;
    };

    var postText = function(text, extraText, slackReqOpts, context) {
    var req = https.request(slackReqOpts, function (res) {
    if (res.statusCode === 200) {
    context.succeed('posted to slack');
    @@ -76,10 +111,32 @@ var processEvent = function(event, context, slackReqOpts) {
    context.fail(e.message);
    });
    req.write(JSON.stringify({
    channel: SLACK_CHANNEL_NAME,
    username: SLACK_USERNAME,
    text: text.join(''),
    icon_emoji: ":ghost:"
    channel: SLACK_CHANNEL_NAME,
    username: SLACK_USERNAME,
    icon_emoji: ":ghost:",
    attachments: [
    {
    fallback: text,
    pretext: "AWS update",
    color: "#36a64f", // Can either be one of 'good', 'warning', 'danger', or any hex color code
    fields: [
    {
    title: text,
    value: extraText,
    short: false // Optional flag indicating whether the `value` is short enough to be displayed side-by-side with other values
    }
    ]
    }
    ]
    }));
    req.end();
    };

    var getName = function(tags) {
    var names = tags.filter(function(t) {
    return t.Key === 'Name';
    });
    if (names && names.length) {
    return names[0].Value;
    }
    }
  4. @rantav rantav revised this gist Jan 17, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -11,7 +11,7 @@ You may of course use similar events to send SNS notofications to emails or anyt
    ## Setup:
    1. Create a slack incoming webhook and get your token
    2. Encrypt this token with KMS and paste the CiphertextBlob at 'Replace with your KMS token' (KMS encryption is a bonus, not required, you may just use the token plaintext)
    Example how to encrypt:
    Example how to encrypt: (replace `22e06448-f73c-42c4-b18f-74f91eb7bc1a` with your own key-id from KMS - create a new key and copy the ID)
    ```
    $ aws kms encrypt --key-id 22e06448-f73c-42c4-b18f-74f91eb7bc1a --plaintext "your slack token"
    {
  5. @rantav rantav revised this gist Jan 17, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion cloudwatch-event-to-slack.js
    Original file line number Diff line number Diff line change
    @@ -9,7 +9,7 @@


    const SLACK_URL = 'https://<your organization>.slack.com/services/hooks/incoming-webhook'; // Replace
    const SLACK_CHANNEL_NAME = "#updates-dev"; // Replace with yout own channel name
    const SLACK_CHANNEL_NAME = "#ops"; // Replace with yout own channel name
    const kmsEncyptedToken = 'Replace with your KMS token'; // Replace
    const SLACK_USERNAME = "webhookbot";

  6. @rantav rantav revised this gist Jan 17, 2016. 2 changed files with 15 additions and 40 deletions.
    19 changes: 13 additions & 6 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -1,21 +1,28 @@
    # Sends Cloudwatch Event notifications to Slack

    ## What is this?
    AWS have released a new featue called CloudWatch Events, which lets you configure events fired by cloudwatch and direct them to SNS, Lambda functions, etc. Here's the [blog post](https://aws.amazon.com/blogs/aws/new-cloudwatch-events-track-and-respond-to-changes-to-your-aws-resources/)

    The set of supported events sources is still somewhat limited, but this is way better than polling, which is what we had to do up until now...

    In this gist you'll learn how to create such event and post updates to slack whenever an EC2 instance changes state (e.g. starting, terminating etc)
    You may of course use similar events to send SNS notofications to emails or anything else of that sort (in case you don't want slack)

    ## Setup:
    1. Create a slack incoming webhook and get your token
    2. Encrypt this token with KMS and paste the CiphertextBlob at 'Replace with your KMS token'
    Example:
    2. Encrypt this token with KMS and paste the CiphertextBlob at 'Replace with your KMS token' (KMS encryption is a bonus, not required, you may just use the token plaintext)
    Example how to encrypt:
    ```
    $ aws kms encrypt --key-id 22e06448-f73c-42c4-b18f-74f91eb7bc1a --plaintext "your slack token"
    {
    "KeyId": "arn:aws:kms:us-west-2:xxxxxxxxxx:key/22e06448-f73c-42c4-b18f-74f91eb7bc1a",
    "CiphertextBlob": "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
    }
    ```
    3. Create a Lambda function and replace all the const with the required data
    3. Create a Lambda function and replace all the const at tge header of the file with your personal data
    Function name: cloudwatch-event-to-slack
    You may use the attached test data to test this function (right after you finish the next item)
    4. Give your function's role permission for the kms:Decrypt action.
    4. Give your function's role permission for the kms:Decrypt action. (assuming you're using KMS)
    Example:
    ```
    {
    @@ -35,6 +42,6 @@
    ```
    5. Create a new CloudWatch Event Rule to send EC2 events to this lambda function
    Screenshot: http://jmp.sh/uBi6dV8
    6. You may test this by terminating and lanching an EC2 instance. Example output on Slack: `
    aws.ec2 (us-west-2): i-531a188a is shutting-down`
    6. You may test this by terminating and lanching an EC2 instance.
    Example output on Slack: `aws.ec2 (us-west-2): i-531a188a is shutting-down`
    7. Prosper
    36 changes: 2 additions & 34 deletions cloudwatch-event-to-slack.js
    Original file line number Diff line number Diff line change
    @@ -4,46 +4,14 @@


    //
    // Setup:
    //
    // 1. Create a slack incoming webhook and get your token
    // 2. Encrypt this token with KMS and paste the CiphertextBlob at 'Replace with your KMS token'
    // Example:
    // $ aws kms encrypt --key-id 22e06448-f73c-42c4-b18f-74f91eb7bc1a --plaintext "your slack token"
    // {
    // "KeyId": "arn:aws:kms:us-west-2:xxxxxxxxxx:key/22e06448-f73c-42c4-b18f-74f91eb7bc1a",
    // "CiphertextBlob": "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
    // }
    // 3. Create a Lambda function and replace all the const with the required data
    // Function name: cloudwatch-event-to-slack
    // You may use the attached test data to test this function (right after you finish the next item)
    // 4. Give your function's role permission for the kms:Decrypt action.
    // Example:
    // {
    // "Version": "2012-10-17",
    // "Statement": [
    // {
    // "Effect": "Allow",
    // "Action": [
    // "kms:Decrypt"
    // ],
    // "Resource": [
    // "<your KMS key ARN>"
    // ]
    // }
    // ]
    // }
    //
    // 5. Create a new CloudWatch Event Rule to send EC2 events to this lambda function
    // Screenshot: http://jmp.sh/uBi6dV8
    // 6. You may test this by terminating and lanching an EC2 instance
    // Setup: See setup in the readme file
    //


    const SLACK_URL = 'https://<your organization>.slack.com/services/hooks/incoming-webhook'; // Replace
    const SLACK_CHANNEL_NAME = "#updates-dev"; // Replace with yout own channel name
    const SLACK_USERNAME = "webhookbot";
    const kmsEncyptedToken = 'Replace with your KMS token'; // Replace
    const SLACK_USERNAME = "webhookbot";

    console.log('Loading function');

  7. @rantav rantav revised this gist Jan 17, 2016. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -35,5 +35,6 @@
    ```
    5. Create a new CloudWatch Event Rule to send EC2 events to this lambda function
    Screenshot: http://jmp.sh/uBi6dV8
    6. You may test this by terminating and lanching an EC2 instance
    6. You may test this by terminating and lanching an EC2 instance. Example output on Slack: `
    aws.ec2 (us-west-2): i-531a188a is shutting-down`
    7. Prosper
  8. @rantav rantav created this gist Jan 17, 2016.
    39 changes: 39 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,39 @@
    # Sends Cloudwatch Event notifications to Slack


    ## Setup:
    1. Create a slack incoming webhook and get your token
    2. Encrypt this token with KMS and paste the CiphertextBlob at 'Replace with your KMS token'
    Example:
    ```
    $ aws kms encrypt --key-id 22e06448-f73c-42c4-b18f-74f91eb7bc1a --plaintext "your slack token"
    {
    "KeyId": "arn:aws:kms:us-west-2:xxxxxxxxxx:key/22e06448-f73c-42c4-b18f-74f91eb7bc1a",
    "CiphertextBlob": "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
    }
    ```
    3. Create a Lambda function and replace all the const with the required data
    Function name: cloudwatch-event-to-slack
    You may use the attached test data to test this function (right after you finish the next item)
    4. Give your function's role permission for the kms:Decrypt action.
    Example:
    ```
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Effect": "Allow",
    "Action": [
    "kms:Decrypt"
    ],
    "Resource": [
    "<your KMS key ARN>"
    ]
    }
    ]
    }
    ```
    5. Create a new CloudWatch Event Rule to send EC2 events to this lambda function
    Screenshot: http://jmp.sh/uBi6dV8
    6. You may test this by terminating and lanching an EC2 instance
    7. Prosper
    117 changes: 117 additions & 0 deletions cloudwatch-event-to-slack.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,117 @@
    //
    // Sends Cloudwatch Event notifications to Slack
    //


    //
    // Setup:
    //
    // 1. Create a slack incoming webhook and get your token
    // 2. Encrypt this token with KMS and paste the CiphertextBlob at 'Replace with your KMS token'
    // Example:
    // $ aws kms encrypt --key-id 22e06448-f73c-42c4-b18f-74f91eb7bc1a --plaintext "your slack token"
    // {
    // "KeyId": "arn:aws:kms:us-west-2:xxxxxxxxxx:key/22e06448-f73c-42c4-b18f-74f91eb7bc1a",
    // "CiphertextBlob": "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
    // }
    // 3. Create a Lambda function and replace all the const with the required data
    // Function name: cloudwatch-event-to-slack
    // You may use the attached test data to test this function (right after you finish the next item)
    // 4. Give your function's role permission for the kms:Decrypt action.
    // Example:
    // {
    // "Version": "2012-10-17",
    // "Statement": [
    // {
    // "Effect": "Allow",
    // "Action": [
    // "kms:Decrypt"
    // ],
    // "Resource": [
    // "<your KMS key ARN>"
    // ]
    // }
    // ]
    // }
    //
    // 5. Create a new CloudWatch Event Rule to send EC2 events to this lambda function
    // Screenshot: http://jmp.sh/uBi6dV8
    // 6. You may test this by terminating and lanching an EC2 instance
    //


    const SLACK_URL = 'https://<your organization>.slack.com/services/hooks/incoming-webhook'; // Replace
    const SLACK_CHANNEL_NAME = "#updates-dev"; // Replace with yout own channel name
    const SLACK_USERNAME = "webhookbot";
    const kmsEncyptedToken = 'Replace with your KMS token'; // Replace

    console.log('Loading function');

    const AWS = require('aws-sdk');
    const url = require('url');
    const https = require('https');
    const qs = require('querystring');


    exports.handler = function(event, context) {
    var token = null;
    var slackReqOpts = null;
    if (token) {
    // Container reuse, simply process the event with the key in memory
    processEvent(event, context, slackReqOpts);
    } else {
    const encryptedBuf = new Buffer(kmsEncyptedToken, 'base64');
    const cipherText = {CiphertextBlob: encryptedBuf};

    const kms = new AWS.KMS();
    kms.decrypt(cipherText, function (err, data) {
    if (err) {
    console.log("Decrypt error: " + err);
    context.fail(err);
    } else {
    token = data.Plaintext.toString('ascii');
    const slackUrl = SLACK_URL;
    slackReqOpts = url.parse(slackUrl + '?token=' + token);
    slackReqOpts.method = 'POST';
    slackReqOpts.headers = {'Content-Type': 'application/json'};
    processEvent(event, context, slackReqOpts);
    }
    });
    }
    };

    var processEvent = function(event, context, slackReqOpts) {
    var source = event.source;
    var region = event.region;
    var detail = event.detail;
    var instanceId = detail['instance-id'];
    var state = detail.state;
    var text = [];
    text.push(source);
    text.push(' (' + region + ')');
    text.push(': ');
    text.push(instanceId);
    text.push(' is ');
    text.push(state);


    var req = https.request(slackReqOpts, function (res) {
    if (res.statusCode === 200) {
    context.succeed('posted to slack');
    } else {
    context.fail('status code: ' + res.statusCode);
    }
    });

    req.on('error', function(e) {
    console.log('problem with request: ' + e.message);
    context.fail(e.message);
    });
    req.write(JSON.stringify({
    channel: SLACK_CHANNEL_NAME,
    username: SLACK_USERNAME,
    text: text.join(''),
    icon_emoji: ":ghost:"
    }));
    req.end();
    }
    16 changes: 16 additions & 0 deletions test-file.json
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,16 @@
    {
    "version": "0",
    "id": "7b14d7de-3adb-4fac-9b90-6dc5019727e3",
    "detail-type": "EC2 Instance State-change Notification",
    "source": "aws.ec2",
    "account": "xxxxxxxxxx",
    "time": "2016-01-17T11:03:34Z",
    "region": "us-west-2",
    "resources": [
    "arn:aws:ec2:us-west-2:xxxxxxxxxx:instance/i-531a188a"
    ],
    "detail": {
    "instance-id": "i-531a188a",
    "state": "shutting-down"
    }
    }