S3バケットの内容をLambda関数で読み込んでみる(Python)


Lambda関数からS3を操作する練習です。
S3にファイルをアップロードしたタイミングでLambda関数が実行されるように設定します。
アップロードされたタイミングで、バケット名やファイルの一覧を取得する関数を書いてみます。

### S3バケットを作成する

「バケットを作成する」をクリックします。
<img width="657" alt="S3 Management Console 2018-01-06 09-29-55.png" src="https://qiita-image-store.s3.amazonaws.com/0/226431/7d978de8-dec7-0fec-802e-6524ac3f3a5e.png">

バケット名とリージョンを入力します。
<img width="698" alt="S3 Management Console 2018-01-06 09-31-18.png" src="https://qiita-image-store.s3.amazonaws.com/0/226431/72c84709-50dc-0d53-0a05-b1865a9b3bde.png">

プロパティの設定は特に何もせずに「次へ」をクリックします。
次の「アクセス許可の設定」はユーザーに対する設定のみです。とりあえずそのまま「次へ」をクリックします。

<img width="689" alt="S3 Management Console 2018-01-06 09-35-11.png" src="https://qiita-image-store.s3.amazonaws.com/0/226431/c4940118-8dd7-aaea-822f-bfefdc23cc5b.png">

### Lambdaにファイルをアップロードする

適当なファイルをアップロードしてみます。
<img width="1042" alt="S3 Management Console 2018-01-06 09-38-15.png" src="https://qiita-image-store.s3.amazonaws.com/0/226431/a8cfb22a-05fa-8274-ea09-b371a4cd03d1.png">

ドラッグアンドドロップでファイルのアップロードができます。
<img width="889" alt="S3 Management Console 2018-01-06 09-39-58.png" src="https://qiita-image-store.s3.amazonaws.com/0/226431/6a048cf4-c25d-9315-92a9-de24a9962512.png">

「アップロード」をクリックします。
<img width="693" alt="S3 Management Console 2018-01-06 09-41-26.png" src="https://qiita-image-store.s3.amazonaws.com/0/226431/186d5cab-af88-3952-7b1c-daf06bd7c118.png">

以下のようにアップロードしたファイルが表示されます。
<img width="923" alt="S3 Management Console 2018-01-06 09-42-26.png" src="https://qiita-image-store.s3.amazonaws.com/0/226431/a6d2be91-f937-09bf-be2a-1b1c57fc0906.png">


### IAMに権限を設定する

Lambdaを操作するIAMにS3へのアクセス権限を与えます。
<img width="1019" alt="IAM Management Console 2018-01-06 09-57-31.png" src="https://qiita-image-store.s3.amazonaws.com/0/226431/a9393b7d-7d10-bbc2-a55d-9a72732decfa.png">

AmazonS3FullAccessポリシーはフルアクセス権を与えてしまうので、どのS3バケットにもアクセスできてしまうことには注意が必要です。今回はサンプルなのでFullAccessを与えますが、実運用に入る際は、インラインポリシーを設定してポリシーを絞るのがいいと思います。
<img width="1110" alt="IAM Management Console 2018-01-06 09-58-50.png" src="https://qiita-image-store.s3.amazonaws.com/0/226431/da6df5f9-817e-2fff-030c-4d85f8fa1243.png">


### Lambda関数を作成する

設計図`s3-get-object-python`から作成します。
<img width="1105" alt="Lambda Management Console 2018-01-06 10-04-43.png" src="https://qiita-image-store.s3.amazonaws.com/0/226431/48784fe1-ff2a-64ac-82b6-0690bf09b8a2.png">

<img width="767" alt="Lambda Management Console 2018-01-06 10-07-20.png" src="https://qiita-image-store.s3.amazonaws.com/0/226431/0e0196cd-3f35-4827-fb27-c379229fe818.png">

<img width="738" alt="Lambda Management Console 2018-01-06 10-07-37.png" src="https://qiita-image-store.s3.amazonaws.com/0/226431/d638a9ad-0ca9-e53f-ae7b-c60c096d10c1.png">


boto3で何ができるかは本家のドキュメントをじっくり読むのがいいと思います。
ネットの情報は古くなってしまったものも多く、単純に真似するだけでは動かないものもありました。
「Boto 3 Docs documentation」
http://boto3.readthedocs.io/en/latest/reference/services/s3.html#client

こちらのサンプルはちゃんと動いてわかりやすかったです。
https://github.com/bloomberg/chef-bcs/blob/master/cookbooks/chef-bcs/files/default/s3-example-boto3.py


以下のような関数を作ってみました。

- S3バケット名を取得する
- S3バケット内のファイルの一覧を取得する
- S3バケット内のファイルの詳細情報を表示する

などを行っています。

```python
from __future__ import print_function

import json
import urllib
import boto3

print('Loading function')

#http://boto3.readthedocs.io/en/latest/reference/services/s3.html#client
s3 = boto3.client('s3')


def lambda_handler(event, context):
    
    
    bucket_name = event['Records'][0]['s3']['bucket']['name']
    print('==== bucket information =====')
    print(bucket_name)
    print('=============================')
    
    
    #https://github.com/bloomberg/chef-bcs/blob/master/cookbooks/chef-bcs/files/default/s3-example-boto3.py
    print('==== your bucket list ====')
    buckets = s3.list_buckets()
    for bucket in buckets['Buckets']:
        print(bucket.get('Name'))
       
    print('==== file list in bucket ====')
    # https://github.com/boto/boto3/issues/134
    AWS_S3_BUCKET_NAME = 'example.read.000'
    s3_resource = boto3.resource('s3')
    bucket = s3_resource.Bucket(AWS_S3_BUCKET_NAME)
    result = bucket.meta.client.list_objects(Bucket=bucket.name, Delimiter='/')
    for o in result.get('Contents'):
        print(o.get('Key'))
    
    
    print('==== file details ====')
    # https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/UsingObjects.html
    GET_OBJECT_KEY_NAME = 'sample.png'
    object = s3.get_object(Bucket=AWS_S3_BUCKET_NAME, Key=GET_OBJECT_KEY_NAME)
    print('ContentType ->' + str(object.get('ContentType')))
    print('ContentLength ->' + str(object.get('ContentLength')))
    
        
    print('==== uploaded file ====')
    for rec in event['Records']:
        print(rec['s3']['object']['key'])
    print('=============================')
    
    print("Received event: " + json.dumps(event, indent=2))
```

テストを実行すると以下のようなログが表示されます。

```
START RequestId: bdbee72e-f28b-11e7-a401-0d0509334621 Version: $LATEST
==== bucket information =====
sourcebucket
=============================
==== your bucket list ====
example.read.000
learnjs.benrady.com
==== file list in bucket ====
sample.png
sample2.png
==== file details ====
ContentType ->image/png
ContentLength ->82361
==== uploaded file ====
HappyFace.jpg
=============================
```

S3にオブジェクトをプットしても同じように関数が実行されます。