S3に画像をアップロードしたらLambdaでサムネイルを生成する(node-imagemagick)


公式ドキュメントでは gm でサムネイルを作っているが node-imagemagick が入っているのでそのまま貼れば一応動く。
node-imagemagick はメンテされてないので gm を使ったほうがいいとは思う。

http://docs.aws.amazon.com/lambda/latest/dg/walkthrough-s3-events-adminuser.html

元画像用のバケットと、そのバケット名に `-thumbnail` のサフィックスを付けたサムネイル用バケットが必要。


# S3 バケットを作る

バケットとファンクションは同じリージョンに作る必要がある。
今回は US Standard に作った。

# Lambda ファンクションを作る

## Lambda function code

```js:handler
var fs = require('fs');
var im = require('imagemagick');
var aws = require('aws-sdk');
var s3 = new aws.S3({apiVersion: '2006-03-01'});

exports.handler = function(event, context) {
    console.log(JSON.stringify(event, null, 2));
    console.log(JSON.stringify(context, null, 2));

    var bucket = event.Records[0].s3.bucket.name;
    var key = event.Records[0].s3.object.key;

    s3.getObject({
        Bucket: bucket,
        Key: key,
        IfMatch: event.Records[0].s3.object.eTag
    }, function(err,data) {
        if (err) {
            context.done('error getting object', err);
        } else {
            console.log(data);

            var contentType = data.ContentType;
            var extension = contentType.split('/').pop();

            im.resize({
                srcData: data.Body,
                format: extension,
                width: 256
            }, function(err, stdout, stderr) {
                if (err) {
                    context.done('resize failed', err);
                } else {
                    var thumbnailBucket = bucket + "-thumbnail";
                    var thumbnailKey = key.split('.')[0] + "-thumbnail." + extension;

                    s3.putObject({
                        Bucket: thumbnailBucket,
                        Key: thumbnailKey,
                        Body: new Buffer(stdout, 'binary'),
                        ContentType: contentType
                    }, function(err, res) {
                        if (err) {
                            context.done('error putting object', err);
                        } else {
                            console.log(JSON.stringify(res, null, 2));
                            context.done();
                        }
                    });
                }
            });
        }
    });
};
```

## Execution role

Lambda がファンクション実行時に使う権限を定義する。

```js:access-policy
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:*"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": [
        "arn:aws:s3:::*"
      ]
    }
  ]
}
```

```js:trust-policy
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```

## その他

メモリやタイムアウトの設定はデフォルトのまま。

# S3 の通知先に登録する

Lambda コンソールから Configure event source ボタンを押下。
先ほど作ったバケットを選択し Create/Select Role ボタンを押下。
Invocation Role を作成/選択する。

```js:access-policy
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "lambda:InvokeFunction"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}
```

```js:trust-policy
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "s3.amazonaws.com"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringLike": {
          "sts:ExternalId": "arn:aws:s3:::*"
        }
      }
    }
  ]
}
```