Lambdaと自殺するCloudFormation

rpmがS3に追加されたらLambdaでインデックス更新するやつを作ろうと思ったんですが、awscli-bundle.zipをダウンロードして /tmpに解凍して いろいろオプション付けてインストールして … 時間的に無理!という結論になりました。

でまあ、いろいろ考えてみて「自殺するCloudFormationならバッチ的に使えるかなぁ」ということで作ってみました。

github.com

Lambdaは以下のような感じです。イベントが飛んでくると、cfnテンプレートからスタックを作成します。

#!/usr/bin/env lambchop -d
/*
function_name: call-cfn
handler: index.handler
role: arn:aws:iam::XXXXXXXXXXXX:role/lambda_basic_execution
include_files: template.json
*/
var Promise = require('bluebird');

var AWS = require("aws-sdk");
AWS.config.update({region: 'ap-northeast-1'});

var cloudformation = Promise.promisifyAll(new AWS.CloudFormation());

var fs = Promise.promisifyAll(require('fs'));

exports.handler = function(event, context) {
  var stackName = 'my-stack-' + new Date().getTime();

  fs.readFileAsync('template.json', 'utf8').then(function(data) {
    return cloudformation.createStackAsync({
      StackName: stackName,
      Parameters: [
        {
          ParameterKey: 'StackName',
          ParameterValue: stackName
        }
      ],
      TemplateBody: data
    });
  }).then(function(data) {
    console.log(data);
  }).then(function() {
    context.succeed('OK');
  }).catch(function(err) {
    context.fail(err);
  });
};

cfnテンプレートは以下の通り。処理を行ったら自殺します。

{
  "Parameters": {
    "StackName": {
      "Type": "String"
    },
    "Region": {
      "Type": "String",
      "Default": "ap-northeast-1"
    }
  },
  "Resources": {
    "Instance": {
      "Type": "AWS::EC2::Instance",
      "Properties": {
        "ImageId": "ami-cbf90ecb",
        "InstanceType": "t2.micro",
        "SubnetId": "subnet-XXXXXXXX",
        "IamInstanceProfile": "my_role",
        "UserData": {
          "Fn::Base64": {
            "Fn::Join": [
              "",
              [
                "#!/bin/bash\n",
                "aws configure set region ap-northeast-1\n",
                // ここに処理を書く
                "aws cloudformation delete-stack --stack-name ", { "Ref": "StackName" }, "\n"
              ]
            ]
          }
        }
      }
    }
  }
}

まあ、こんな感じにすれば比較的重たい処理でも、イベントドリブンでできるかなーと考えてます。