S3にPUTしたテキストから、LambdaでHTMLを生成する
AWSでは可視化に関するサービスが充実している。
例えば、センサーデータなどをモニタリングしたい場合はKibanaやQuickSightなどで可視化すれば良い。
一方で、もっと泥臭いこと、例えば収集したデータから算出したデータを使って、独自のレポートやHTMLなどをほぼリアルタイムで作成したい時がある。
これをなんとかAWSを使ってできないかと思い試行錯誤した。
今回は第一歩として、S3にデータをPUTしたことをトリガーにLambdaでHTMLを作成してみた。
イメージとしてはこんな感じ。
コードはgithubに。
github.com
S3へのPUTの準備
まず、boto3でS3にPUTするデータを作成する。
とりあえずdata.txtとかにしとく。
#data.txt
HTML Generation Success!!!
続いて、S3にPUTするスクリプトを作成する。
import boto3 # 設定値 bucket_name = $バケットの名前 filepath = $data.txtのパス Key = $S3に上げた時のファイル名 #実行内容 s3 = boto3.resource('s3') bucket = s3.Bucket(bucket_name) bucket.upload_file(filepath, Key)
この内容に合うように、S3にバケットを作成しておく。
Lambdaの設定
Lambdaの実行内容は以下のようにした。
ポイントとしては、
・ソースのS3とKeyはeventから取得する。
・HTMLのS3への格納はboto3で行う。
html_storeみたいな名前であらかじめバケットを作っておく。
・読み込むS3上のファイルは、ローカルにtmpフォルダを作成して格納する。
・HTMLはハードコードしておく。
・トリガーのバケットと、出力のバケットは違うものにする。
同じものにしておくと無限ループに入ってしまう可能性がある?
→ 無限ループに入って破産する可能性があるので注意してください。(はじめてのクラウド破産体験★LambdaのトリガーにS3を設定するときに気を付けること!!)
import boto3 import os def lambda_handler(event, context): #putトリガーの適用元 input_bucket = event['Records'][0]['s3']['bucket']['name'] input_key = event['Records'][0]['s3']['object']['key'] tmp = '/tmp/' + os.path.basename(input_key) #出力先 output_bucket = 'html_store' output_key = 'data.html' try: s3 = boto3.resource('s3') bucket = s3.Bucket(input_bucket) bucket.download_file(input_key, tmp) with open(tmp, 'r') as input_f: lines = [ line for line in input_f ] with open('./data.html', 'w') as output_f: output_f.write('<html><head></head><body>\n') [output_f.write(line + '\n') for line in lines] output_f.write('</body></html>') s3.Bucket(output_bucket).put_object(Key = output_key , Body = output_f) except Exception as e: raise e
トリガーはS3を選択する。
バケット:data.txtを格納するバケットを指定する。
イベントタイプ:今回はPUTを選択。
プレフィックス、サフィックス:今回は未検証。とりあえず空にしておく。
IAMロールはS3の読み出しと書き込みができれば良いので、今回はとりあえずFullAccessにしておく。
バケットも作成しておくこと。
~~~
HTMLはハードコードしないバージョンも試してみた。
lambdaに入れるpythonスクリプトをzipで上げる際に、同じzipにHTMLの中身を入れておく。
これをスクリプト中で開いてファイルオブジェクトに書き出す。
今回はHTML中にlambdaで処理した内容を入れるイメージで、head.txtとtail.txtに前後のHTMLを書いておく。
import boto3 import os def lambda_handler(event, context): #putトリガーの適用元 input_bucket = event['Records'][0]['s3']['bucket']['name'] input_key = event['Records'][0]['s3']['object']['key'] tmp = '/tmp/' + os.path.basename(input_key) #出力先 output_bucket = 'htmlstore' output_key = 'data.html' try: s3 = boto3.resource('s3') ibucket = s3.Bucket(input_bucket) ibucket.download_file(input_key, tmp) obucket = s3.Bucket(output_bucket) with open('./head.txt', 'r') as head_f: heads = [ line for line in head_f ] with open(tmp, 'r', encoding='utf-8') as input_f: lines = [ line for line in input_f ] with open('./tail.txt', 'r') as tail_f: tails = [ line for line in tail_f ] with open('/tmp/data.html', 'w', encoding='utf-8') as output_f: [output_f.write(line + '\n') for line in heads] [output_f.write(line + '\n') for line in lines] [output_f.write(line + '\n') for line in tails] obucket.upload_file('/tmp/data.html','data.html') except Exception as e: print(e) raise e
S3からHTMLをダウンロードする準備
ダウンロードの方法はいろいろある。
作成したHTMLにPublic権限をつけておけばブラウザからでも読めるが、意外と難しかったので、とりあえずboto3で取ってくることにする。
import boto3 #設定値 bucket_name = $バケットの名前 filepath = $data.txtのパス Key = $S3に上げた時のファイル名 #実行内容 s3 = boto3.resource('s3') bucket = s3.Bucket(bucket_name) bucket.download_file(Key, filepath)
実行結果
こんな感じ。
感想
head.txtとtail.txtはS3に入れて置いて、boto3でtmpに取ってきても良さそう。
生成したHTMLにPublic権限をつけて、metaデータで再読み込みできるようにしておけば、リアルタイムでレポートを更新することもできる。
head.txtとtail.txtの書き方次第でかなり使えそう。