SORACOM CLI を実行する Lambda 関数を作って Step Functions から利用してみた
はじめに
AWS Step Functions は AWS の各種サービスを連鎖的に呼び出せてとても便利ですが、SORACOM API も呼び出せると便利だろうな、と常々考えていました。そして先日ふと気づきました。SORACOM CLI を実行して JSON を返すだけの Lambda 関数を用意しておけば、似たようなことができるのではないかと。
というわけで、試してみました。手っ取り早く試したい方は以下を使ってください。
SORACOM CLI とワークフローについて
SORACOM CLI は SORACOM API を呼び出すための CLI ツールです。自分の PC にインストールし、簡単に実行できます。SORACOM API を呼び出すための最も手軽な方法です。
SORACOM API は SORACOM のあらゆる機能を API として提供しており、とても汎用的な一方、目的を達成するためには、API の様々な機能を組み合わせて実行していく必要があります。例えば、次のような操作が必要になったりします。
1. 保有している SIM の一覧を取得する
2. それぞれの SIM に対して別の操作をする
単発の実行で要求が満たせることは少なく、実際には直列実行や並列実行、分岐、ループ、待機といった制御が必要になります。
もちろん、シェルスクリプトなどで実装すれば実現できますが、実行環境を用意する必要があります。Step Functions はまさにこういった実行制御のためのマネージドなサービスです。Step Functions は Lambda 関数を実行できるので、SORACOM CLI を実行する Lambda 関数を用意すれば、擬似的に SORACOM API に対応できそうです。
SORACOM CLI と Lambda 関数について
SORACOM CLI は Lambda レイヤーを提供しています。
このレイヤーを利用し、SORACOM CLI の引数を受け取って実行し、JSON レスポンスを出力する Lambda 関数を実装してみます。実行イメージは次のような感じです。
$ aws lambda invoke --function-name soracom-cli --payload file://request.json
{
"command": "sora-cam devices images export --device-id XXXXXXXX",
"body": {
"time": 1671206164000
}
}
このようにすると、Lambda 関数が次のように SORACOM CLI を実行します。
soracom sora-cam devices images export --device-id XXXXXXXX --body '{"time": 1671206164000}'
を実行します。SORACOM CLI のデフォルトの出力形式は JSON なので、出力をそのまま Lambda 関数のレスポンスとすれば良さそうです。
というわけで実装したのがこちらです。
SORACOM CLI の実行に必要な SAM ユーザーの認証キーは AWS Secrets Manager から取得するようにしました。次のキー / 値の secret が登録されていることを想定しています。
secret のキー | 値 |
---|---|
AUTH_KEY_ID | 認証キー ID |
AUTH_KEY | 認証キーのシークレット |
Lambda 関数は AWS SAM で作成していますので、デプロイには Docker と AWS SAM CLI が必要となります。インストールしたら、次のコマンドでデプロイできます。
sam build
sam deploy --guided
SoracomAuthKeySecretName
パラメータの値を聞かれたら、認証キーを保存した secret の ARN を入力します。
詳しくは README を参照してください。
Step Functions との統合
実際に Step Functions から利用してみました。サンプルとして、API で一覧を取得し、それぞれの要素について別の操作をしてみました。
- ソラカメ対応カメラの一覧を取得する
- それぞれのカメラについて ソラカメ対応カメラの情報を取得する
ステートマシンは次のようになります。
{
"StartAt": "SoraCam:listSoraCamDevices",
"States": {
"SoraCam:listSoraCamDevices": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"OutputPath": "$.Payload",
"Parameters": {
"FunctionName": "soracom-cli",
"Payload": {
"command": "sora-cam devices list"
}
},
"Next": "ForEachDevice"
},
"ForEachDevice": {
"Type": "Map",
"ItemProcessor": {
"ProcessorConfig": {
"Mode": "INLINE"
},
"StartAt": "SoraCam:getSoraCamDevice",
"States": {
"SoraCam:getSoraCamDevice": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"OutputPath": "$.Payload",
"Parameters": {
"FunctionName": "soracom-cli",
"Payload": {
"command.$": "States.Format('sora-cam devices get --device-id {}', $.deviceId)"
}
},
"End": true
}
}
},
"End": true
}
}
}
まず SoraCam:listSoraCamDevices
ステートが実行されて、次のような JSON が出力されます。
[
{
"configuration": {
"audioAlarmEnabled": false,
"motionDetectionEnabled": false,
"smokeAlarmEnabled": false
},
"connected": true,
"deviceCategory": "Camera",
"deviceId": "XXXXXXXXXXXX",
"firmwareVersion": "4.37.1.102",
"lastConnectedTime": 1671143094678,
"name": "リビング",
"productDisplayName": "ATOM Cam Swing"
},
{
"configuration": {
"audioAlarmEnabled": false,
"motionDetectionEnabled": true,
"smokeAlarmEnabled": false
},
"connected": true,
"deviceCategory": "Camera",
"deviceId": "YYYYYYYYYYYY",
"firmwareVersion": "4.58.0.100",
"lastConnectedTime": 1671145300995,
"name": "玄関",
"productDisplayName": "ATOM Cam 2"
}
]
これが ForEachDevice
ステートに渡ります。ForEachDevice
は Map
タイプなので、この配列の各要素を SoraCam:getSoraCamDevice
ステートに入力として渡します。
SoraCam:getSoraCamDevice
ステートは、Lambda 関数に渡すペイロードを次のようにしています。
"Payload": {
"command.$": "States.Format('sora-cam devices get --device-id {}', $.deviceId)"
}
これは Step Functions で利用できる関数 States.Format
で、実際には次のように変換されて Lambda 関数の入力となります。
{
"command": "sora-cam devices get --device-id XXXXXXXXXXXX"
}
このようにして、SORACOM CLI の実行結果を、次の SORACOM CLI の実行の入力として簡単に利用できます。
上記は簡単なステートマシンを作成してみましたが、もっと複雑なステートマシンも作成可能です。例えば、ソラカメ対応カメラが検出したイベントについて、その瞬間の動画をすべてエクスポートして S3 に保存する、といったことも可能です。
まとめ
AWS Step Functions から SORACOM CLI を利用する方法を紹介しました。Lambda 関数で SORACOM CLI を実行することで、あたかも Step Functions が SORACOM API に対応したかのような使い勝手を得ることができました。便利ですね。
Discussion