インスタンス作成時にインスタンスとEBSに自動タグ付け

# 目的
前回は誰が作成したインスタンスなのかわかるようにインスタンス作成時に自動的にUserタグを付与するLambdaを作成しました。
[Lambdaでインスタンス作成時に自動タグ付け](http://qiita.com/d-yamanaka/items/c50f00caabb521530283)

インスタンス作成時に作成されるrootボリュームはインスタンス削除時にデフォルト設定で一緒に削除されますが、インスタンス作成時に追加したEBSボリュームはデフォルトで「合わせて削除」のチェックが外れているのでデフォルト設定でインスタンスを削除した場合は、追加ボリュームは削除されません。
そして、availableのEBSだけが残ってしまい、また「誰が作ったのこのEBS」状況が作り出されてしまいます。

そこで今回はインスタンス作成時に、インスタンスとEBSにUserタグを付与するLambdaを作成しました。

# コード
以下が作成したコードとなります。

```javascript:index.js
/* ====================================================================== */
/**
 *  インスタンス起動時に自動でインスタンスとEBSにタグつける
 *
 */
/* ====================================================================== */
'use strict';

console.log('Loading function');
var aws  = require('aws-sdk');
var region_name;

exports.handle = function(event, context) {

    var generator  = (function *() {
        try {
            console.log('Received event:');
            console.log(JSON.stringify(event));

            // ログをフェッチ
            var s3Log = yield fetchLogFromS3(event, generator);
            // ログ解凍処理
            var uncompressedLog = yield uncompressLog(s3Log, generator);
            // レコード抽出
            var matchingRecords = pickupRecords(uncompressedLog);

            //利用するRegionを指定
            var EC2 = new aws.EC2({
                region: region_name
            });

            // タグターゲットにインスタンスIDを追加
            var tagTargets = addInstanceIds(matchingRecords);

            for (var i = 0, max = tagTargets.length; i < max; i++) {
                var volumeIds = yield addEbsIds(tagTargets[i].resourceIds, EC2, generator);
                // タグターゲットにVolumeIDを追加
                Array.prototype.push.apply(tagTargets[i].resourceIds, volumeIds);

                // タグ付け
                yield createTags(tagTargets[i].userName, tagTargets[i].resourceIds, EC2, generator);
            }

            context.succeed('succeed');
        } catch (e) {
            console.log("event:" + JSON.stringify(event, null, 2));
            context.fail(e.message);
        }
    })();

    /* 処理開始 */
    generator.next();
};

function fetchLogFromS3 (event, generator) {

    var S3 = new aws.S3();

    var params = {
        Bucket: event.Records[0].s3.bucket.name,
        Key: event.Records[0].s3.object.key
    };

    region_name = params.Key.split('/')[3];
    console.log('regionname' + region_name);

    console.log('Fetching compressed log from S3...');
    S3.getObject(params, function(err, data) {
        if (err) {
            console.log(err);
            generator.throw(new Error('500:Unable to Fetching S3'));
            return;
        }
        generator.next(data);
    });
}

function uncompressLog (log, generator) {
    var zlib = require('zlib');

    console.log('Uncompressing log...');
    zlib.gunzip(log.Body, function(err, data){
        if (err) {
            console.log(err);
            generator.throw(new Error('500:Unable to Uncompress Log'));
            return;
        }
        generator.next(data);
    });
}

function pickupRecords (jsonBuffer) {

    console.log('CloudTrail JSON from S3:');
    console.log(json);
    var json = jsonBuffer.toString();
    var records;
    try {
        records = JSON.parse(json);
    } catch (err) {
        throw(new Error('500:Unable to parse CloudTrail JSON'));
    }

    var matchingRecords = records
        .Records
        .filter(function(record) {
            return record.eventSource.match('ec2.amazonaws.com') && record.eventName.match('RunInstances');
        });

    return matchingRecords;
}

function createTags(createUserName, resourceIds, EC2, generator) {
    console.log('CreateTags to Resources: ', resourceIds);
    var params = {
        Resources: resourceIds,
        Tags: [{Key: 'User', Value: createUserName}]
    };
    EC2.createTags(params, function(err, data){
        if (err) {
            console.log(err);
            generator.throw(new Error('500:Unable to Create Tags'));
            return;
        }
        generator.next();
    });
}

// タグターゲットにインスタンスIDを追加
function addInstanceIds(matchingRecords) {
    var tagTargets = [];

    // ユーザ毎
    for (var i = 0, max = matchingRecords.length; i < max; i=+1) {
        console.log('Filtered JSON:');
        console.log(JSON.stringify(matchingRecords[i]));
        tagTargets[i] = {
            userName : matchingRecords[i].userIdentity.userName,
            resourceIds : []
        };

        var items = matchingRecords[i].responseElements.instancesSet.items;
        var index = 0;

        // タグターゲットにインスタンスIDを追加
        while (index < items.length) {
            tagTargets[i].resourceIds.push(items[index].instanceId);
            index=+1;
        }
    }
    return tagTargets;
}

function addEbsIds(instanceIds, EC2, generator) {
    console.log('add Ebs Ids from instanceIds: ', instanceIds);
    var ebsParams = {
        InstanceIds: instanceIds
    };

    EC2.describeInstances(ebsParams, function(err, data) {
        if (err) {
            console.log(err);
            generator.throw(new Error('500:Unable to Add VolumeIds'));
            return;
        }
        var volumeIds = [];
        var volumeIdList = data.Reservations[0].Instances[0].BlockDeviceMappings;
        for (var i = 0, max = volumeIdList.length; i < max; i++) {
            console.log('addingEbs: ', volumeIdList[i].Ebs.VolumeId);
            volumeIds.push(volumeIdList[i].Ebs.VolumeId);
        }
        generator.next(volumeIds);
    });
}

```

前回のコードを修正して作成しました。
タグターゲットにタグ付けしたいリソースIDを格納して、タグ付けを行っています。

# 試してみる
早速インスタンスを作成してちゃんとタグが自動で付与されるか試してみます。

今回はテストとして3つのEBSを追加ボリュームとしました。
<img width="1264" alt="Screen Shot 2016-07-18 at 14.19.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/40136/0ba4b2ab-2f9a-9ce9-a4b2-371400e5ceca.png">

インスタンスのNameタグに適当に名前をつけています。
<img width="1267" alt="Screen Shot 2016-07-18 at 14.20.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/40136/7f9b19ae-ed1a-c797-6da8-e2597263ed65.png">

インスタンスが作成中になっています。
Nameタグのみついています。
<img width="1064" alt="Screen Shot 2016-07-18 at 14.21.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/40136/e2a5ecfd-e060-ea46-c536-019c5aa7e894.png">

5分〜7分経過するとタグが付与されました！
<img width="1065" alt="Screen Shot 2016-07-18 at 14.27.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/40136/b35d293e-446e-b893-df48-f444c6edc8dc.png">

作成されたEBSについてもタグが付与されているでしょうか。

まずは、Rootボリューム。
<img width="566" alt="Screen Shot 2016-07-18 at 14.29.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/40136/02fbf51c-cac0-116a-f580-09e3a969021f.png">

<img width="1065" alt="Screen Shot 2016-07-18 at 14.29.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/40136/30036b8a-4414-47c3-5ddb-f0edcff8f2c8.png">

きちんとタグ付けされています！

他のEBSも同様にタグがついていました。

<img width="1063" alt="Screen Shot 2016-07-18 at 14.30.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/40136/e3f2102c-69e3-df24-07d4-19685b850cdb.png">

<img width="1063" alt="Screen Shot 2016-07-18 at 14.30.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/40136/57d055ef-2e1b-dfe5-8226-f4290db295f2.png">

<img width="1063" alt="Screen Shot 2016-07-18 at 14.30.58.png" src="https://qiita-image-store.s3.amazonaws.com/0/40136/cd51e7b1-c70e-89f2-14af-c4e149d574bb.png">

# まとめ
インスタンス作成時に作成されるEC2及びEBSに自動的にUserタグを付与できるようになりました。
これで今までよりも少しだけリソースの管理が楽になると思います。

また何か間違いやこうした方がよいのでは？という意見があれば教えていただければ幸いです。

以上