AWS Greengrassのリソース構造が少し複雑だったため、
CLIを叩きながらそのリソースの全体的な構造を把握し、それぞれの役割を整理します。
全体像
いきなりですが全体像です。
※ Coreのみで利用していたため、DeviceDefinitionについては割愛しています
Coreと証明書の作成
まずはGreengrass Coreの実体となるAWS IoTのThingを作成します。
出力結果は後々必要になるので、変数に入れて取っておきます。
$ RESULT=$(aws iot create-thing --thing-name ${GROUP_NAME}_Core)
$ echo $RESULT
{
"thingName": "GreengrassTest_Core",
"thingArn": "arn:aws:iot:ap-northeast-1:{aws_account_id}:thing/GreengrassTest_Core",
"thingId": "{uuid v4 string}"
}
$ CORE_THING_ID=$(echo ${RESULT} | jq -r ".thingId")
$ CORE_THING_ARN=$(echo ${RESULT} | jq -r ".thingArn")
$ CORE_THING_NAME=$(echo ${RESULT} | jq -r ".thingName")
次に、作成したThingに証明書・ポリシーをアタッチします。
まずは証明書を作成。ARNは変数に保持しておき、ファイル名に使います。
jqを使いたい所なのですが、Keyの改行のせい?か、パース出来なかったためCLIのqueryを使いました。
$ CERT_ARN=$(aws iot create-keys-and-certificate --set-as-active \
--certificate-pem-outfile temp.cert.pem \
--public-key-outfile temp.public.key \
--private-key-outfile temp.private.key \
--query certificateArn --output text)
$ CERT_ID=$(echo $CERT_ARN | cut -d / -f 2)
$ mv temp.cert.pem ${CERT_ID:0:10}.cert.pem
$ mv temp.private.key ${CERT_ID:0:10}.private.key
$ mv temp.public.key ${CERT_ID:0:10}.public.key
証明書にポリシーをアタッチします。
ポリシーの作成は省略します。
$ aws iot attach-policy --policy-name Greengrass-pubsub-policy \
--target ${CERT_ARN}
Thingに証明書をアタッチします。
$ aws iot attach-thing-principal \
--thing-name ${CORE_THING_NAME} \
--principal ${CERT_ARN}
仕上げに、Greengrass Coreを作成します。
$ aws greengrass create-core-definition \
--cli-input-json '{
"Name": "'"${GROUP_NAME}_Core_Definition"'",
"InitialVersion": {
"Cores": [{
"Id": "'"$(uuidgen)"'",
"ThingArn": "'"${CORE_THING_ARN}"'",
"CertificateArn": "'"${CERT_ARN}"'"
}]
}
}'
このコマンドによって、CoreDefinitionとCoreDefinitionVersionが1つずつ作成されます。
また、Cores[].Id
のところではuuidgen
を使って生成したUUIDを入れています。
これはCoreを一意に識別するIDとなりますが、システム側で自動で生成される訳ではなく、自前で128bitのUUIDv4文字列を生成する必要があります。
また、この後のFunctionやSubscriptionでもこのUUIDが必要となります。
CoreDefinitionの内容は以下の様の形です。
{
"Arn": "arn:aws:greengrass:ap-northeast-1:{AWS_ACCOUNT_ID}:/greengrass/definition/cores/{CORE_DEFINITION_ID}",
"CreationTimestamp": "2018-08-18T12:01:21.810Z",
"Id": "{CORE_DEFINITION_ID}",
"LastUpdatedTimestamp": "2018-08-18T12:01:21.810Z",
"LatestVersion": "{CORE_DEF_VER_ID}",
"LatestVersionArn": "arn:aws:greengrass:ap-northeast-1:{AWS_ACCOUNT_ID}:/greengrass/definition/cores/{CORE_DEFINITION_ID}/versions/{CORE_DEF_VER_ID}",
"Name": "GreengrassTest_Core_Definition"
}
CoreDefinitionVersionは以下のような形です。
{
"Arn": "arn:aws:greengrass:ap-northeast-1:{AWS_ACCOUNT_ID}:/greengrass/definition/cores/{CORE_DEFINITION_ID}/versions/{CORE_DEF_VER_ID}",
"CreationTimestamp": "2018-08-18T12:01:21.810Z",
"Definition": {
"Cores": [
{
"CertificateArn": "arn:aws:iot:ap-northeast-1:{AWS_ACCOUNT_ID}:cert/{CERT_ID}",
"Id": "{CORE_ID}",
"SyncShadow": false,
"ThingArn": "arn:aws:iot:ap-northeast-1:{AWS_ACCOUNT_ID}:thing/GreengrassTest_Core"
}
]
},
"Id": "{CORE_DEFINITION_ID}",
"Version": "{CORE_DEF_VER_ID}"
}
CoreDefinitionで保持しているのはほぼメタデータのみであり、
実際の機能的?な部分は、CoreDefinitionVersionに記載されています。
また、Cores
の部分は配列になっていますが、1つしか指定出来ません。
Functionの作成
次に、LambdaFunctionをGreengrassに紐づけるFunctionDefinitionを作成します。
ここでは一旦空の(何れのLambdaFunctionも紐付けない)状態で空の定義を作成します。
$ aws greengrass create-function-definition \
--cli-input-json '{
"Name": "'"${GROUP_NAME}_Function_Definition"'",
"InitialVersion": {
"Functions": []
}
}'
リファレンス
https://docs.aws.amazon.com/cli/latest/reference/greengrass/create-function-definition.html
これで、CoreDefinitionと同様にFunctionDefinitionとFunctionDefinitionVersionが作成されます。
Subscription、Resource、Loggerの作成
Functionと同様の手順で、Subscription、Resource、LoggerのDefinitionを作成していきます。
まずはSubscription、MQTTトピックのルーティングのようなことが行なえます。
これも空で作成。
リファレンスはこちら。
https://docs.aws.amazon.com/cli/latest/reference/greengrass/create-function-definition.html
$ aws greengrass create-subscription-definition \
--cli-input-json '{
"Name": "'"${GROUP_NAME}_Subscription_Definition"'",
"InitialVersion": {
"Subscriptions": []
}
}'
次にResource。
ローカルのファイルシステムやデバイスにアクセスする場合、ここに設定を記述します。
リファレンスはこちら。
https://docs.aws.amazon.com/cli/latest/reference/greengrass/create-resource-definition.html
$ aws greengrass create-resource-definition \
--cli-input-json '{
"Name": "'"${GROUP_NAME}_Resource_Definition"'",
"InitialVersion": {
"Resources": []
}
}'
そしてLogger。
Cloudwatchへログを流したり、ファイルシステムにログを保存する設定となります。
リファレンスはこちら。
https://docs.aws.amazon.com/cli/latest/reference/greengrass/create-logger-definition.html
$ CLI_INPUT_JSON='{
"Name": "'"${GROUP_NAME}_Logger_Definition"'",
"InitialVersion": {
"Loggers": [
{
"Component": "Lambda",
"Id": "'"$(uuidgen | awk '{print tolower($1)}')"'",
"Level": "INFO",
"Space": 25600,
"Type": "FileSystem"
},
{
"Component": "GreengrassSystem",
"Id": "'"$(uuidgen | awk '{print tolower($1)}')"'",
"Level": "INFO",
"Space": 25600,
"Type": "FileSystem"
},
{
"Component": "Lambda",
"Id": "'"$(uuidgen | awk '{print tolower($1)}')"'",
"Level": "INFO",
"Type": "AWSCloudWatch"
},
{
"Component": "GreengrassSystem",
"Id": "'"$(uuidgen | awk '{print tolower($1)}')"'",
"Level": "INFO",
"Type": "AWSCloudWatch"
}
]
}
}'
$ aws greengrass create-logger-definition \
--cli-input-json $(echo $CLI_INPUT_JSON | jq -cr ".")
Groupの作成
以上でGreengrass Groupに必要な各要素が揃ったので、
ついにGroupを作成していきます。
$ aws greengrass create-group --cli-input-json '{
"Name": "'"${GROUP_NAME}"'",
"InitialVersion": {
"CoreDefinitionVersionArn": "'"${CORE_DEF_LATEST_VER_ARN}"'",
"FunctionDefinitionVersionArn": "'"${FUNC_DEF_LATEST_VER_ARN}"'",
"SubscriptionDefinitionVersionArn": "'"${SUBS_DEF_LATEST_VER_ARN}"'",
"ResourceDefinitionVersionArn": "'"${RES_DEF_LATEST_VER_ARN}"'",
"LoggerDefinitionVersionArn": "'"${LOG_DEF_LATEST_VER_ARN}"'"
}
}'
これで新しいGreengrass Groupが出来たことが、Webからも確認出来るかと思います。
ですが、FunctionDefinitionなどはまだ空です。
FunctionDefinitionの更新
FunctionDefinitionの更新の手順は、
- 新しいFunctionDefinitionVersionの作成
- 作成したFunctionDefinitionVersionのARNを指定し、新しいGroupVersionを作成
まずはFunctionDefinitionVersionの基となるjsonファイルを作成。
FUNC_ID
はUUIDv4で、新しいFunctionを追加するときは新規に生成します。
FUNC_DEF_ID
は、最初のGroup作成時に作成したものです。
{
"FunctionDefinitionId": "${FUNC_DEF_ID}",
"Functions": [
{
"FunctionArn": "arn:aws:lambda:::function:GGIPDetector:1",
"FunctionConfiguration": {
"Environment": {},
"MemorySize": 32768,
"Pinned": true,
"Timeout": 3
},
"Id": "$(uuidgen)"
},
{
"FunctionArn": "arn:aws:lambda:ap-northeast-1:{AWS_ACCOUNT_ID}:function:greengrass-hello-world:LATEST",
"FunctionConfiguration": {
"Environment": {},
"MemorySize": 32768,
"Pinned": true,
"Timeout": 30
},
"Id": "$(uuidgen)"
}
]
}
これを使って新しいFunctionDefinitionVersionを作成します。
$ aws greengrass create-function-definition-version --cli-input-json file://new_func_def_ver.json
{
"Arn": "arn:aws:greengrass:ap-northeast-1:{AWS_ACCOUNT_ID}:/greengrass/definition/functions/{FUNC_DEF_ID}/versions/{FUNC_DEF_VER_ID}",
"CreationTimestamp": "2018-08-19T01:32:24.886Z",
"Id": "{FUNC_DEF_ID}",
"Version": "{FUNC_DEF_VER_ID}"
}
次にGroupVersionを更新します。
ここまでやって初めてGroupに変更が反映されます。
まずは、現在のGroupVersionを取得し・・・
$ LATEST_VERSION_ID=$(aws greengrass get-group --group-id $GROUP_ID | jq -r ".LatestVersion")
$ aws greengrass get-group-version --group-id $GROUP_ID --group-version-id $LATEST_VERSION_ID
指定した部分だけアップデート、という挙動ではないため、
上記手順で取得したjsonのFunctionDefinitionVersionなどを適宜書き換え・・・
{
"FunctionDefinitionVersionArn": "arn:aws:greengrass:ap-northeast-1:{AWS_ACCOUNT_ID}:/greengrass/definition/functions/{FUNC_DEF_ID}/versions/{NEW_FUNC_DEF_VER_ID}",
"CoreDefinitionVersionArn": "...",
"LoggerDefinitionVersionArn": "...",
"ResourceDefinitionVersionArn": "...",
"SubscriptionDefinitionVersionArn": "...",
"GroupId": "{GROUP_ID}"
}
最後に、新しいGroupVersionを作成します。
GroupVersionは自動的に最新のものが使用されます。
aws greengrass create-group-version --cli-input-json file://new_group_ver.json
これでGroupにLambdaFunctionが追加されました。
SubscriptionやResourceに関しては割愛しますが、
同様の手順でGroupを更新することが出来ます。
とっつきにくいリソース構造はしていましたが、
CLIでいじってみると結構わかりやすい構造でした。