[AWS IoT Greemgrass V2] MQTTのメッセージで再起動やシャットダウンを行うコンポーネントを作成してみました。
1 はじめに
IoT事業部の平内(SIN)です。
エッジデバイスとして、RaspberryPIを使用している場合、遠隔からシャットダウンやリブートしたくなることがあると思います。
今回は、AWS IoT Greengrass V2のコンポーネントで、これを作成してみました。 操作コマンドは、MQTTメッセージとなっています。
2 操作コマンド
操作コマンドの仕様です。
(1) Topic
maintenance/コアデバイス名
例)
maintenance/gg-device-001
(2) Payload
キー | 値 | 備考 |
---|---|---|
cmd | reboot | 再起動 |
cmd | shutdown | シャットダウン |
例)
{ "cmd": "reboot" }
次のような形でメッセージを送ることで、デバイス(gg-device-001)が、再起動されます。
3 アーティクル
コードです。
環境変数から、コアデバイス名(ホスト名ではありません)を取得し、自身に当てたメッセージをSubscribeしています。
また、cmdの種類に応じて、sudoコマンドを発行しています。
Greenglassのセットアップや、コンポーネントの作成、MQTTのSubscribeに関しては、下記の記事をご参照ください。
[AWS IoT Greengrass V2] RaspberryPIにインストールしてみました
[AWS IoT Greengrass V2] RaspberryPIでコンポーネントを作成してみました
[AWS IoT Greengrass V2] コンポーネントからIoT CoreのメッセージブローカーにPublish/Subscribeしてみました
import time import os import json import subprocess import awsiot.greengrasscoreipc import awsiot.greengrasscoreipc.client as client from awsiot.greengrasscoreipc.model import ( IoTCoreMessage, QOS, SubscribeToIoTCoreRequest ) # MQTT送受信クラス class Mqtt(): def __init__(self) -> None: self.ipc_client = awsiot.greengrasscoreipc.connect() self.timeout = 10 class StreamHandler(client.SubscribeToIoTCoreStreamHandler): def __init__(self, on_recv): super().__init__() self.__on_recv = on_recv def on_stream_event(self, event: IoTCoreMessage) -> None: message = str(event.message.payload, "utf-8") print("Stream.Recv payload:{}".format(message)) self.__on_recv(json.loads(message)) def on_stream_error(self, error: Exception) -> bool: print("Stream.Error: {}".format(error)) return True def on_stream_closed(self) -> None: print("Stream.Close") pass def subscribe(self, topic, on_recv): print("Subscribe: {}".format(topic)) qos = QOS.AT_LEAST_ONCE request = SubscribeToIoTCoreRequest() request.topic_name = topic request.qos = qos handler = self.StreamHandler(on_recv) operation = self.ipc_client.new_subscribe_to_iot_core(handler) future = operation.activate(request) future.result(self.timeout) def on_recv(message): if("cmd" in message): cmd = '' if(message["cmd"] == "shutdown"): cmd = 'sudo shutdown -h now' elif(message["cmd"] == "reboot"): cmd = 'sudo reboot' if(cmd != ''): print(cmd) subprocess.Popen(cmd, shell=True) # 自分のコアデバイス名だけサブスクライブする thing_name = os.environ['AWS_IOT_THING_NAME'] topic = "maintenance/{}".format(thing_name) mqtt = Mqtt() mqtt.subscribe(topic, on_recv) while True: time.sleep(1)
4 レシピ
レシピは、以下の通りです。デフォルトのコンフィグで、IoT CoreへのSubscribeを許可しています。
--- RecipeFormatVersion: '2020-01-25' ComponentName: com.example.Shutdown ComponentVersion: '1.0.0' ComponentConfiguration: DefaultConfiguration: accessControl: aws.greengrass.ipc.mqttproxy: com.example.Shutdown:mqtt:1: operations: - "aws.greengrass#SubscribeToIoTCore" resources: - "maintenance/#" Manifests: - Platform: os: linux Lifecycle: Install: pip3 install awsiotsdk Run: python3 -u {artifacts:path}/shutdown.py Artifacts: - URI: s3://gg-artifacts-2021-08-11/artifacts/com.example.Shutdown/1.0.0/shutdown.py
5 sudo
コンポーネントの中では、sudo をつけたコマンドを実行していますが、何も設定しないと、下記のエラーが発生します。
コンポーネントのログ
stderr. sudo: no tty present and no askpass program specified.
また、この時、syslogには、以下のように出力されています。
pam_unix(sudo:auth): auth could not identify password for [ggc_user]
こちらは、パスワード無しでの実行を許可する必要がります。
具体的には、sudo visudoを実行して、以下の行を追加します。
$ sudo visudo
ggc_user ALL = NOPASSWD: /usr/sbin/shutdown, /usr/sbin/reboot
※ ユーザー(ggc_user)が、reboot/shutdownをパスワードなしで実行することを許可しています。
6 最後に
今回は、MQTTメッセージで、rebootやshutdownを行うコンポーネントを作成してみました。 visudoで許可が必要な点に、ちょっ戸惑いました。
Greengrass V2 強力です。引き続き、色々試して行きたいです。
7 参考リンク
[AWS IoT Greengrass V2] RaspberryPIにインストールしてみました
[AWS IoT Greengrass V2] RaspberryPIでコンポーネントを作成してみました
[AWS IoT Greengrass V2] クラウド側から複数のコアデバイスにコンポーネントをデプロイしてみました
[AWS IoT Greengrass V2] クラウド側からコンポーネントを削除してみました
[AWS IoT Greengrass V2] ローカルデバッグコンソール(aws.greengrass.LocalDebugConsole)を使用してみました
[AWS IoT Greengrass V2] Lambda関数(コンポーネント)をデプロイしてみました
[AWS IoT Greengrass V2] コンポーネントからIoT CoreのメッセージブローカーにPublish/Subscribeしてみました
[AWS IoT Greengrass V2] コンポーネントからシークレットマネージャにアクセスしてみました
[AWS IoT Greengrass V2] コンポーネントでコアデバイス間のPublish/Subscribeを試してみました
[AWS IoT Greengrass V2] ログマネージャでコンポーネントのログをCloudWatch Logsに送ってみました
[AWS IoT Greengrass V2] トークン交換サービスでコンポーネントからDynamoDBにアクセスしてみました
[AWS IoT Greengrass V2] ストリームマネージャーを使用してコンポーネントからKinesis Data Streamsへデータを送ってみました
[AWS IoT Greengrass V2] プロセス間通信 (IPC) を使用してコンポーネントの設定値を使用してみました
[AWS IoT Greengrass V2] ストリームマネージャーを使用してWebカメラの画像を毎秒2フレームでS3に送信してみました
[AWS IoT Greenglass V2] 100円ショップの Bluetooth リモコン シャッターでパトランプ回してみました