🔗

SORACOM CLI を実行する Lambda 関数を作って Step Functions から利用してみた

2022/12/24に公開

はじめに

AWS Step Functions は AWS の各種サービスを連鎖的に呼び出せてとても便利ですが、SORACOM API も呼び出せると便利だろうな、と常々考えていました。そして先日ふと気づきました。SORACOM CLI を実行して JSON を返すだけの Lambda 関数を用意しておけば、似たようなことができるのではないかと。

というわけで、試してみました。手っ取り早く試したい方は以下を使ってください。

https://github.com/hara/soracom-cli-lambda-function

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 レイヤーを提供しています。

https://users.soracom.io/ja-jp/tools/cli/use-lambda-layer/

このレイヤーを利用し、SORACOM CLI の引数を受け取って実行し、JSON レスポンスを出力する Lambda 関数を実装してみます。実行イメージは次のような感じです。

$ aws lambda invoke --function-name soracom-cli --payload file://request.json
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 関数のレスポンスとすれば良さそうです。

というわけで実装したのがこちらです。

https://github.com/hara/soracom-cli-lambda-function

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 ステートに渡ります。ForEachDeviceMap タイプなので、この配列の各要素を 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