Help us understand the problem. What is going on with this article?

AWS Greengrassのリソース構造をCLIを叩きながら読み解く

More than 1 year has passed since last update.

AWS Greengrassのリソース構造が少し複雑だったため、
CLIを叩きながらそのリソースの全体的な構造を把握し、それぞれの役割を整理します。

全体像

いきなりですが全体像です。

gg_resources.png

※ Coreのみで利用していたため、DeviceDefinitionについては割愛しています

Coreと証明書の作成

まずはGreengrass Coreの実体となるAWS IoTのThingを作成します。
出力結果は後々必要になるので、変数に入れて取っておきます。

$ RESULT=$(aws iot create-thing --thing-name ${GROUP_NAME}_Core)
Result
$ 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の内容は以下の様の形です。

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は以下のような形です。

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の更新の手順は、

  1. 新しいFunctionDefinitionVersionの作成
  2. 作成したFunctionDefinitionVersionのARNを指定し、新しいGroupVersionを作成

まずはFunctionDefinitionVersionの基となるjsonファイルを作成。
FUNC_IDはUUIDv4で、新しいFunctionを追加するときは新規に生成します。
FUNC_DEF_IDは、最初のGroup作成時に作成したものです。

new_func_def_ver.json
{
  "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
Result
{
    "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などを適宜書き換え・・・

new_group_ver.json
{
  "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でいじってみると結構わかりやすい構造でした。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした