terraformでAWS IoT Rules Engineを設定していたらハマったのでメモ。 公式terraformリファレンス の記述が貧弱なのでその辺りの補強を兼ねている。
前提
- DynamoDBは既に設定されている
DeviceLog
というテーブルが作成されている
HCLの記述
# AWS IoT Rules Engineの設定本体 resource "aws_iot_topic_rule" "main" { name = "ExampleRule" description = "Example rule for AWS IoT Rules Engine" enabled = true sql_version = "2016-03-23" sql = "SELECT * FROM 'devices/#'" dynamodb { hash_key_field = "DeviceId" hash_key_type = "STRING" # トピック `devices/<device-id>/status` から `<device-id>` を取得する hash_key_value = "$${topic(2)}" range_key_field = "Timestamp" range_key_type = "NUMBER" # JSON ペイロードから `timestamp` の値を取得する range_key_value = "$${timestamp}" role_arn = aws_iam_role.dynamodb_put_only_role.arn table_name = "DeviceLog" operation = "INSERT" } } # Rules Engine用ロール resource "aws_iam_role" "dynamodb_put_only_role" { name = "DynamoDbDeviceLogPutOnlyRole" assume_role_policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Service": "iot.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } EOF } # Rules Engine用ロールのポリシ resource "aws_iam_role_policy" "dynamodb_put_only_policy" { name = "DynamoDbDeviceLogPutOnlyRolePolicy" role = aws_iam_role.dynamodb_put_only_role.id policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "dynamodb:PutItem", "Resource": "arn:aws:dynamodb:*:*:table/DeviceLog" } ] } EOF }
HCLの記述でundocなところ
HashKeyValueに含める値の設定
${topic()}
はリクエストされたトピック名を取得することを意味する。
()
内に引数を渡すと、トピックを /
で分割したスライスにアクセスすることができる。
例えば、 ${topic(2)}
を指定した場合、トピック名が devices/DeviceId-X123/status
であると、得られる結果は DeviceId-X123
になり、 DeviceId
フィールドに DeviceId-X123
を格納することが出来る。
HCL内に記述がないが ${timestamp()}
を指定すると処理した時刻が置換される。整数値で、単位はミリセカンド単位。
${something-value}
のように指定すると、JSONペイロードに含まれるキーを探索して値をセットできる。
例えば、 ${tm}
を設定した場合、次のような JSON から tm
の値 1606875290000
を取り出して使う形となる。
{ "status": "ok", "tm": 1606875290000 }
なお、上記HCL内では $
が特別な意味を持つのでエスケープして設定している。
この辺りのドキュメントどこにあるんだ…。
Basic Ingestを使う場合
エッジデバイスからBasic Ingestを使って送信する際は次のようなトピックになる。
$aws/rules/ExampleRule/devices/DeviceId-X123/status
Rules Engineで取り扱う際は $aws/rules/ExampleRule/
を取り除いた値、つまり devices/DeviceId-X123/status
を扱うことになる(そのため、前述のサンプルで SQL
の設定値を SELECT * FROM 'devices/#'
にしている)。