Serverless Framework(v1.x) でPythonの追加パッケージを使う

[Serverless(2)アドベントカレンダー](http://qiita.com/advent-calendar/2016/serverless2 "Serverless(2)アドベントカレンダー")17日目の記事です。
正直大したネタではないですが…(^_^;)
Serverless Framework(v1.x)でPythonの情報が少なくて自分でも悩んだため、こんなネタにしてみました。
（12月17日AM6:17追記）
別の件もあってインプットデータをCSVからJSONに変更しました。

#背景
もともとうちの「[IoTかんたんパック](http://dc.ogis-ri.co.jp/iotpack/ "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/

```serverless.yml
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コード
実際に動かすコードはこちら
デモ用なので引数のチェックとかまったくやってません(^_^;)

```handler.py
# -*- 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)
```