デバイスコネクターの開発

measurementプロジェクトのアプリケーション開発における、デバイスコネクターの開発について説明します。

../../../_images/develop_application_measurement_project_overview_device_connector.png

図 26 本章での説明部分(黄色枠)

measurementプロジェクトのデバイスコネクターはDockerコンテナ上で動作するため、以下の点に注意して開発する必要があります。

依存ライブラリのバージョン

デバイスコネクターが依存するライブラリのバージョンが、ビルド環境と実行環境で異なる場合、実行時にエラーや予期しない挙動が発生する可能性があります。 例えば、デバイスコネクターがglibcに依存する場合、ubuntu:22.04でビルドしたバイナリは、ubuntu:18.04ではglibcバージョンの不一致により実行することができません。

この問題を避けるため、デバイスコネクターは実行環境のDockerイメージと同じディストリビューションでビルドすることを推奨します。

アーキテクチャの違い

コンパイルが必要なアプリケーションの場合、エッジコンピューターのアーキテクチャ向けにクロスビルドが必要です。

また、Terminal System 2のデバイスコネクターとして、以下の要件が必要です。

intdash Edge Agent 2とのプロセス間通信

デバイスコネクターは、intdash Edge Agent 2とプロセス間通信をする際に、iscp-v2-compatフォーマット(または、非推奨のlogger-msgフォーマット)でデータを送受信する必要があります。 詳細については、 intdash Edge Agent 2 デベロッパーガイド を参照してください。

環境変数による設定

Terminal System APIのデバイスコネクター設定でデバイスコネクターに設定値を与える場合、環境変数により設定値を入力できるようにする必要があります。

推奨する開発方法

上記の要件を満たすデバイスコネクターを開発するために、以下の開発方法を推奨します。

  • アプトポッド製のデバイスコネクターdevice-connector-intdashを利用する

  • Device Connector Frameworkを利用し、カスタム開発部分を独自エレメントのプラグインとして開発する

この方法を選択すると、以下のメリットがあります。

  • 上記の要件を満たすデバイスコネクターを容易に開発できます

  • 環境変数による設定読み込み、スレッド管理などの基本機能や、intdash用のデータを扱う際に便利な機能を再利用できます

  • カスタム開発部分のみをプラグイン化することで、カスタム開発部分のみを構成管理でき、変更影響を少なくすることができます

一方、以下の制約があります。

  • device-connector-intdash(intdash Edge Agent 2)のシステム要件を満たさない環境では正しく動作しない可能性があります

  • 実行環境にdevice-connector-intdashの依存ライブラリが必要です

  • device-connector-intdashが利用しているRustバージョンと同じバージョンでプラグインをビルドする必要があります

この方法で開発が必要となるファイルは、以下の2つです。

独自エレメントのプラグイン

Device Connector Frameworkを利用し、独自エレメントのプラグイン(共有ライブラリファイル、.so形式)を開発します。 カスタムインベントリを送信したい場合は、カスタムインベントリのディレクトリにJSON形式のインベントリデータを出力するようにします。

パイプライン設定ファイル

デバイスコネクターで行いたい処理をエレメントの組み合わせで定義したファイルを用意します。 Terminal System APIのデバイスコネクター設定で設定値を与える場合、環境変数を $(VARIABLE_NAME) の形式で記述します。

../../../_images/develop_application_measurement_project_device_connector_recommended_development.png

図 27 推奨する開発方法で必要となるファイル(黄色枠)

注釈

Device Connector Frameworkおよびdevice-connector-intdashの詳細については、 デバイスコネクターデベロッパーガイド を参照してください。

以降の手順で、推奨する開発方法でデバイスコネクターを開発する方法を説明します。

ツールのインストール

推奨する開発方法では、RustおよびDockerのインストールが必要です。

テンプレートのビルド

独自エレメントのプラグインは、 Device Connector Template を利用して開発します。

  1. プロジェクトを作成します。 プロジェクト名はプラグインのファイル名で使用されます。ここでは custom を指定して説明します。

    $ cargo install cargo-generate
    $ cargo generate --git https://github.com/aptpod/device-connector-template.git
         Project Name : custom
    
  2. 作成したプロジェクトに移動します。

    $ cd custom
    
  3. クロスビルド環境のDockerイメージをビルドします。

    $ docker build -t rust-cross-builder .
    
  4. クロスビルド環境のコンテナを起動します。

    $ docker run --rm -it -v ${PWD}:/usr/local/src rust-cross-builder
    
  5. ターゲットアーキテクチャを指定してサンプルのデバイスコネクターをビルドします。

    エッジコンピューターのアーキテクチャを指定してビルドしてください。複数のアーキテクチャをサポートする場合は、それぞれビルドしてください。

    # cargo build --release --target aarch64-unknown-linux-gnu
    
    # cargo build --release --target armv7-unknown-linux-gnueabihf
    
    # cargo build --release --target x86_64-unknown-linux-gnu
    

    注釈

    エッジコンピューターのアーキテクチャは、エッジコンピューターで uname -m コマンドを実行すると確認できます。 ターゲットアーキテクチャと uname -m コマンドの対応関係は以下のとおりです。

    • aarch64-unknown-linux-gnu: aarch64

    • armv7-unknown-linux-gnueabihf: armv7l

    • x86_64-unknown-linux-gnu: x86_64

    target/<ターゲットアーキテクチャ>/release に、プラグインファイル(共有ライブラリ) libdc_custom.so が出力されることを確認します。

テンプレートのビルドが確認できたら、独自エレメントを開発します。

独自エレメントの開発

Device Connector Frameworkを利用した一般的な独自エレメントの開発については、 デバイスコネクターデベロッパーガイド を参照してください。

Terminal System 2の推奨開発方法では、以下の点を考慮する必要があります。

クロスビルド環境のカスタマイズ

クロスビルド環境の Dockerfile を必要に応じてカスタマイズします。

プラグインのRustバージョンをdevice-connector-intdashと合わせる

Device Connector Frameworkの制約により、device-connector-intdashとプラグインのRustバージョンを合わせる必要があります。 クロスビルド環境のRustバージョンは、 Dockerfileの RUST_TOOLCHAIN で設定することが可能です。 RUST_TOOLCHAIN のデフォルト設定値は、最新のdevice-connector-intdashのバージョンに合わせて更新されるため、最新バージョンを利用する場合はデフォルト設定のままで構いません。

設定するべきdevice-connector-intdashのRustバージョンは、デバイスコネクターデベロッパーガイド を参照してください。 実行環境で利用可能なdevice-connector-intdashのバージョンは、アプトポッドの公開リポジトリの設定後に以下のコマンドで確認が可能です。

表示例:

$ apt policy device-connector-intdash
 device-connector-intdash:
 Installed: 2.0.0
 Candidate: 2.0.0
 Version table:
 *** 2.0.0 500
       500 https://repository.aptpod.jp/intdash-edge/linux/ubuntu focal/stable amd64 Packages
       100 /var/lib/dpkg/status
ベースイメージの選択および依存パッケージの追加

必要に応じてクロスビルド環境のDockerfileを編集し、 FROM で使用するベースイメージを指定します。 device-connector-intdashの動作要件を満たしている、 debianubuntu をベースイメージに選択してください。 特にこだわりがなければ、 device-connector-intdashの動作要件を満たしている ubuntu の最新バージョンを推奨します。

また、独自エレメントのビルドに必要な依存パッケージがある場合、クロスビルド環境のDockerfileを編集してパッケージを追加してください。

Dockerfileを変更した場合は、クロスビルド環境のDockerイメージをビルドして、デバイスコネクターを再ビルドしてください。

カスタムインベントリの送信

カスタムインベントリを送信したい場合は、カスタムインベントリのディレクトリにJSON形式のインベントリデータを出力するように実装してください。

  1. テンプレートのソースコードを修正します。

    hello-src で、設定値の文字列をインベントリとして送信する場合、nextで以下のように /var/run/device-inventory/custom.d ディレクトリにファイルを作成し、 設定値の文字列をJSON形式のデータで出力する処理を追加してください。

    fn next(&mut self, pipeline: &mut Pipeline, _receiver: &mut MsgReceiver) -> ElementResult {
             pipeline.check_send_msg_type(0, || MsgType::from_mime("text/plain").unwrap())?;
    
             sleep(Duration::from_millis(100));
    
             let mut buf = pipeline.msg_buf(0);
             buf.write_all(self.conf.text.as_bytes())?;
    
    +        let mut file = std::fs::File::create("/var/run/device-inventory/custom.d/custom-text")?;
    +        let data = format!(r#"{{"text": "{}"}}"#, self.conf.text.as_str());
    +        file.write_all(data.as_bytes())?;
    +
             Ok(ElementValue::MsgBuf)
       }
    }
    
  2. クロスビルド環境のコンテナを起動して、サンプルのデバイスコネクターをビルドします。

    $ cd custom
    $ docker run --rm -it -v ${PWD}:/usr/local/src rust-cross-builder
    
    # cargo build --release --target aarch64-unknown-linux-gnu
    # cargo build --release --target armv7-unknown-linux-gnueabihf
    # cargo build --release --target x86_64-unknown-linux-gnu
    

注意

カスタムインベントリを送信する場合、ホストのカスタムインベントリのディレクトリをコンテナにバインドマウントする必要があります。

警告

Menderサーバーは、基本的にはインベントリの削除に対応していません。 古いインベントリが残り続けることを防ぐため、インベントリのキー名には動的に増減する名称を避ける必要があります。

デバイスのインベントリを削除したい場合は、一度デバイスを削除し、デバイス認証を再実施する必要があります。

カスタムインベントリの詳細については、 device-inventory を参照してください。

パイプライン設定ファイルの作成

デバイスコネクターで行いたい処理をエレメントの組み合わせで定義したファイルを用意します。 推奨する開発方法では、以下の2点を考慮して作成してください。

プラグインの設定

plugin_files にプラグインファイルへのパスを指定します。 本ガイドでは、ビルドしたプラグインは Dockerイメージの作成 でコンテナの /usr/local/lib に配置されます。

設定値の環境変数

Terminal System APIのデバイスコネクター設定で設定値を与える場合、環境変数を $(VARIABLE_NAME) の形式で記述します。

パイプライン設定ファイルの作成例を以下に挙げます。(この例は次章 Dockerイメージの作成 でも引き続き使用します。)

  1. プロジェクトディレクトリに conf ディレクトリを作成し、移動します。

    $ cd custom
    $ mkdir conf
    $ cd conf
    
  2. confディレクトリに custom-text-hexdump.yml ファイルを以下の内容で作成します。 この設定ファイルは、本ガイドでの動作確認のために利用します(本番運用時は不要です)。

    plugin:
      plugin_files:
        - /usr/local/lib/libdc_custom.so
    
    tasks:
      - id: 1
        element: hello-src
        conf:
          text: $(DC_TEXT)
    
      - id: 2
        element: iscp-v2-compat-filter
        from: [[1]]
        conf:
          timestamp:
            stamp:
              clock_id: CLOCK_MONOTONIC
          convert_rule:
            string:
              name: custom_text
    
      - id: 3
        element: hexdump-sink
        from: [[2]]
    

    これは、環境変数 DC_TEXT で指定された文字列を、string型のiscp-v2-compatフォーマットに変換し、16進数でダンプ出力するパイプラインになっています。

    • プラグインファイル libdc_custom.so をロードします

    • テンプレートのプラグインに含まれる hello-src および hexdump-sink エレメントを利用します

    • device-connector-intdashに含まれる iscp-v2-compat-filter エレメントを利用します

  3. 次に、 custom-text.yml ファイルを作成します。 この設定ファイルは、intdash Edge Agent2にデータを送信する際に利用します。

    plugin:
      plugin_files:
        - /usr/local/lib/libdc_custom.so
    
    tasks:
      - id: 1
        element: hello-src
        conf:
          text: $(DC_TEXT)
    
      - id: 2
        element: iscp-v2-compat-filter
        from: [[1]]
        conf:
          timestamp:
            stamp:
              clock_id: CLOCK_MONOTONIC
          convert_rule:
            string:
              name: custom_text
    
      - id: 3
        element: print-log-filter
        from: [[2]]
        conf:
          duration_ms: 10000
          tag: $(DC_PRINT_LOG_FILTER_CONF_TAG)
          output: stderr
    
      - id: 4
        element: file-sink
        from: [ [3] ]
        conf:
          path: $(DC_FILE_SINK_CONF_PATH)
    

    環境変数 DC_TEXT で指定された文字列を、string型のiscp-v2-compatフォーマットに変換し、 環境変数 DC_FILE_SINK_CONF_PATH で指定されたFIFOに出力するパイプラインです。 また、 print-log-filter で、10秒ごとに iscp-v2-compat-filterフォーマットのデータのメッセージ数およびバイト数をログ出力しています。

    • device-connector-intdashに含まれる print-log-filter および file-sink エレメントを利用します

次章では、作成したプラグインおよびパイプライン設定ファイルを含めたDockerイメージを作成する方法を説明します。