Greengrassのローカルシャドウがお手軽に確認できるハックをご紹介します
CX事業本部の岩田です。
Greengrassのローカルシャドウを操作していたところ、シャドウの状態が意図通りに更新されずどハマりしてしまいました。 原因を切り分けようにもローカルシャドウの中身を確認するために、いちいちLambdaを実行するのが面倒で面倒で...
nsenter
を使って、いわゆる「コンテナの中に入る」操作を行ってからGreengrass SDKを使用すればLambdaを使わなくても行けるか?と思ったのですが、普通にGreengrass SDKを使用すると動作に必要な環境変数が不足し正常に動作しませんでした。
Greengrass SDKを正常動作させるにはGreengrass Core経由でLambdaの中で利用する必要があるようです。
色々と調べた結果、ローカルシャドウを管理しているDBを直接参照する方法を発見したのでご紹介します。
Greengrassにおけるローカルシャドウの管理
Greengrass Coreのシャドウ同期に関連するログは/greengrass/ggc/var/log/system/GGShadowSyncManager.log
に出力されます。このログファイルを眺めていたところ、以下のような出力を発見しました。
[2019-08-06T04:01:32.367Z][INFO]-Using /state/shadow/shadow.db file for sqlite3
ん?!SQLite?どうもローカルシャドウの管理にはSQLite3を利用しているようです。
ということは普通にsqlite3
コマンドから中身を覗けるのでは...
早速やってみましょう
SQLiteの中身を覗いてみる
先ほど確認した通り、ローカルシャドウのDBは/greengrass/ggc/var/state/shadow/shadow.db
に作成されています。Greengrass Coreを稼働させているOSからsqlite3
コマンドを使ってDBの中身を確認してみましょう。
DBに接続
まずは接続から...
sqlite3 /greengrass/ggc/var/state/shadow/shadow.db SQLite version 3.7.17 2013-05-20 00:56:22 Enter ".help" for instructions Enter SQL statements terminated with a ";" sqlite>
テーブル一覧表示
テーブル一覧です
sqlite> .tables doc sync
doc
とsync
2つのテーブルを持っているようです
テーブルのスキーマ表示
doc
とsync
2つのテーブルのスキーマを確認してみます
まずはdoc
テーブルから
sqlite> .schema doc CREATE TABLE doc (arn text not null, name text, state text);
- arn
- name
- state
3つの列で構成されています。名前から察するにこれがローカルシャドウのシャドウドキュメントを格納しているテーブルでしょう。
続いてsync
テーブル
sqlite> .schema sync CREATE TABLE sync (arn text not null, local text, cloud text);
- arn
- local
- cloud
3つの列で構成されています。こちらがローカルシャドウとAWS IoT上のシャドウの同期を管理するテーブルなのでしょう
テーブルの中身表示
テーブルの中身を表示してみます。まずはdoc
テーブルから
sqlite> .headers ON sqlite> select * from doc; arn|name|state thing_hogehoge|thing_hogehoge|{"ggFlv":{"reported":{"hoge":{"version":14}}},"isDeleted":false,"metadata":{"reported":{"hoge":{"timestamp":1565069505}}},"state":{"reported":{"hoge":"fuga"}},"version":20}
state列をフォーマットするとこのような形になります
{ "ggFlv": { "reported": { "hoge": { "version": 14 } } }, "isDeleted": false, "metadata": { "reported": { "hoge": { "timestamp": 1565069505 } } }, "state": { "reported": { "hoge": "fuga" } }, "version": 20 }
続いてsync
テーブルです。
sqlite> select * from sync; arn|local|cloud thing_hogehoge|{"ggFlv":{"reported":{"hoge":{"version":14}}},"isDeleted":false,"metadata":{"reported":{"hoge":{"timestamp":1565069505}}},"state":{"reported":{"hoge":"fuga"}},"version":20}|{"metadata":{"reported":{"hoge":{"timestamp":1565069505}}},"state":{"reported":{"hoge":"fuga"}},"version":98}
カラムlocal
の値をフォーマットするとこのような形になります
{ "ggFlv": { "reported": { "hoge": { "version": 14 } } }, "isDeleted": false, "metadata": { "reported": { "hoge": { "timestamp": 1565069505 } } }, "state": { "reported": { "hoge": "fuga" } }, "version": 20 }
先ほどのdocテーブルの中身と一致しています。
同様にcloud
の値をフォーマットすると以下のようになります
{ "metadata": { "reported": { "hoge": { "timestamp": 1565069505 } } }, "state": { "reported": { "hoge": "fuga" } }, "version": 98 }
AWS IoT上でシャドウドキュメントを確認すると以下のような状態でした
sync
テーブルのcloud
列と同期が取れていることが分かります。
最後に
Greengrass Coreの裏側に少し詳しくなれました。 これでデバッグが捗りそうです。
誰かの参考になれば幸いです。