Serverless(2)アドベントカレンダー17日目の記事です。
正直大したネタではないですが…(^_^;)
Serverless Framework(v1.x)でPythonの情報が少なくて自分でも悩んだため、こんなネタにしてみました。
(12月17日AM6:17追記)
別の件もあってインプットデータをCSVからJSONに変更しました。
#背景
もともとうちの「IoTかんたんパック」では選択できるメッセージブローカーがMQTTのものしかなくてHTTPSに対応しないといけなくなったのがきっかけです。
(AWS IoTのRESTでもpublishできるんだけど認証が特殊すぎて今回は対象のデバイスがマイコンチップのためできるだけシンプルなAPIにしないといけなかったというか…^^;)
前回はServerless Framework(v1.1)でサンプルをそのままAPI Gatewayで動かしてみました。
[Serverless Frameworkを使ってみた](http://qiita.com/daikunjp/items/2b8aa35ecd104001f4e5 Serverless Frameworkを使ってみた)
今回はWebAPIにPUTされたCSVデータをMySQLにInsertするAPIを作ってみたいと思います。
#Serverless Framework をつかったWebAPI構築手順
##Serverless Framework のバージョンアップ
いつのまにやらv1.3にアップデートされていたので[前回](http://qiita.com/daikunjp/items/2b8aa35ecd104001f4e5 Serverless Frameworkを使ってみた)作成した環境をバージョンアップします。
% npm install -g serverless
バージョンの確認
% sls --version
1.3.0
##プロジェクト作成
プロジェクトのディレクトリを作成して初期化
% mkdir iot-api
% cd iot-api
% sls create --template aws-python --name iot-api
##PythonのMySQLライブラリ追加
lambdaのPythonにMySQLドライバを入れないといけないんだけど…
マニュアル見たらPythonの場合はpip使えと書いてあるので、普通にpipでmysql-pythonをインストールしたがうまくいかない。
どうやらプロジェクトのディレクトリに置いておけばそのままlambdaにアップロードするzipに入れてくれるみたいなので以下の手順でプロジェクトディレクトリにインストール。
% pip install mysql-python -t .
Shared Objectをカレントディレクトリにコピー
% cp /usr/lib64/mysql/libmysqlclient.so.18 .
##serverless.yml の編集
serverless.ymlを以下のように編集。
今回はlambdaからRDSのMySQLにアクセスするためVPCの設定も追加
【参考】
https://serverless.com/framework/docs/providers/aws/guide/functions/
http://dev.classmethod.jp/etc/serverless-framework-lambda-function-run-in-vpc/
service: iot-api
provider:
name: aws
runtime: python2.7
vpc:
securityGroupIds:
- sg-xxxxxxxx ←セキュリティグループID
subnetIds:
- subnet-xxxxxxxx ←サブネットID
- subnet-xxxxxxxx ←サブネットID
stage: dev
region: ap-northeast-1
iamRoleStatements:
- Effect: "Allow"
Action:
- "ec2:CreateNetworkInterface"
- "ec2:DescribeNetworkInterfaces"
- "ec2:DeleteNetworkInterface"
Resource:
- "*"
functions:
iotput:
handler: handler.iotput
events:
- http:
path: iotput
method: put
##Pythonコード
実際に動かすコードはこちら
デモ用なので引数のチェックとかまったくやってません(^_^;)
# -*- coding: utf-8 -*-
import MySQLdb,json
HOST = "接続するRDSのホスト名"
DBNAME = "DB名"
DBUSER = "DBユーザ名"
PASSWD = "パスワード"
CHARSET = "utf8"
def iotput(event, context):
# MySQL Connect
connect = MySQLdb.connect(host=HOST, db=DBNAME, user=DBUSER, passwd=PASSWD, charset=CHARSET)
connect.cursorclass = MySQLdb.cursors.DictCursor
cursor = connect.cursor()
# BODY Data split for CSV
# data1 = event['body'].split(",")
# BODY Data split for JSON
data1 = json.loads(event['body'])
data1[0] = data1['data1']
data1[1] = data1['data2']
data1[2] = data1['data3']
# MySQL Data insert
cursor.execute("insert into sensor01(data1,data2,data3) values(%s,%s,%s)",
(data1[0],data1[1],data1[2]))
connect.commit()
cursor.close()
connect.close()
body = {
"message": "input data is %s %s %s" % (data1[0],data1[1],data1[2]),
}
response = {
"statusCode": 200,
"body": json.dumps(body)
}
return response
##デプロイ
% sls deploy
Serverless: Packaging service...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading service .zip file to S3 (916.94 KB)...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
..............
Serverless: Stack update finished...
Service Information
service: iot-api
stage: dev
region: ap-northeast-1
api keys:
None
endpoints:
PUT - https://xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/iotput
functions:
iot-api-dev-iotput: arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxxxxx:function:iot-api-dev-iotput
##テスト
別のマシンからcurlでテストしてみる。
% curl -X PUT -d '{"data1":"10","data2":"20","data3":"40"}' https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/iotput
{"message": "input data is 10 20 40"}
% curl -X PUT -d '{"data1":"1.1","data2":"5.4","data3":"2.7"}' https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/iotput
{"message": "input data is 1.1 5.4 2.7"}
結果確認
mysql> select * from sensor01;
+-------+-------+-------+
| data1 | data2 | data3 |
+-------+-------+-------+
| 10 | 20 | 40 |
| 1.1 | 5.4 | 2.7 |
+-------+-------+-------+
2 rows in set (0.01 sec)