UNS Governance
このプラグインは、ACLチェック時にUnified Namespace(UNS)トピック構造を強制します。
プラグインAPI
ベースパス: /api/v5/plugin_api/emqx_unsgov
ブートストラップモデル
- 起動時に、UNS Governanceは
priv/bootstrap_models/*.jsonをスキャンします。 - 各ブートストラップモデルについて:
- その
idがデータベースに存在しない場合、プラグインはモデルを保存し、アクティブとしてマークします。 - すでにデータベースに
idが存在する場合、プラグインは読み込みをスキップし、情報レベルでログを出力します。
- その
- バンドルされたデフォルトのブートストラップモデル:
priv/bootstrap_models/model-v1.json
注意:ブートストラップモデルはクラスター内で最初のプラグイン起動時にデータベースにロードされます。後のプラグインやノードの再起動では再ロードされません。モデルの更新はAPIを使用してデータベース内のモデルストアを更新してください。
JSONデータエンドポイント
GET /status— プラグインのステータス(on_mismatch、exempt_topics)。GET /stats— クラスター集約されたカウンターおよび最近のドロップ情報。GET /models— 保存されているすべてのモデルの一覧(各エントリにactiveフラグを含む)。GET /models/:id— 指定IDのモデルを取得。存在しない場合は404。POST /models— モデルの作成または更新。オプションでactivateフラグあり。POST /models/:id/activate— 保存済みモデルをアクティブ化。POST /models/:id/deactivate— モデルを非アクティブ化。DELETE /models/:id— 保存済みモデルを削除。POST /validate/topic— アクティブモデルに対してトピックのバリデーションを実施。
その他のエンドポイント
GET /ui— インタラクティブなモデルエディターUI。GET /metrics— Prometheusテキストエクスポート形式。
UNSモデルスキーマ
このセクションでは、UNS Governanceが受け入れる完全なモデルJSONフォーマットを定義します。
トップレベルキー
id(必須、文字列):モデルID。^[A-Za-z0-9_-]+$にマッチする必要があります。評価順序はIDのアルファベット順で制御されます。name(任意、文字列):モデルの表示名。デフォルトはidと同じです。variable_types(任意、オブジェクト):再利用可能な変数制約。tree(必須、オブジェクト):トピックツリー定義。payload_types(任意、オブジェクト):再利用可能なペイロードスキーマ。
variable_types
変数タイプ名から制約オブジェクトへのマップ。
サポートされる形式:
- 文字列正規表現マッチャー:
{"type":"string","pattern":"^...$"}
- 列挙型マッチャー:
{"type":"enum","values":["A","B","C"]}
変数タイプが欠落または無効な場合、マッチャーは寛容な any にフォールバックします。
payload_types
ペイロードスキーマ名からスキーマオブジェクトへのマップ。
バリデーションはJSON Schemaを使用し、以下の互換パッチがあります:
- トップレベルの
typeが省略された場合、UNS Governanceは"object"にパッチを当てます。 - トップレベルのペイロードスキーマはオブジェクトルートでなければなりません。プリミティブルートは拒否されます。
これにより以下が可能です:
- 完全な自己完結型オブジェクトJSON Schema。
- 既存の省略形オブジェクトスキーマ(例:
required/propertiesのみ)。
エンドポイントのペイロードバインディング:
- エンドポイントの
_payloadはpayload_typesのキー、またはペイロード検証をスキップする"any"を参照できます。
tree
tree は、各キーがルートトピックセグメントであり、各値がノードオブジェクトであるオブジェクトです。
ノードオブジェクトのキー:
children(任意、オブジェクト):子セグメントのマップ。_payload(任意、文字列):エンドポイントノードのペイロードタイプ名。デフォルトは"any"。_type(任意、互換性用):明示的なnamespace | variable | endpoint。_var_type(任意、互換性用):変数タイプ名。
ノードタイプの推論:
childrenが存在する場合:ノードは非エンドポイント。childrenがない場合:ノードはエンドポイント。- 非エンドポイントキーの場合:
- キー
{name}は変数ノード - キー
+は変数ワイルドカードノード - その他のキーはネームスペースノード
- キー
変数タイプの解決:
- キー
{name}の場合:_var_typeがあればそれを使用- なければ推論されたタイプ名
nameを使用
- キー
+の場合:- マッチャーは
any(1セグメントにマッチ)
- マッチャーは
ツリー内のワイルドカードキー:
+:トピックセグメント1つに正確にマッチ。#:残りのトピックセグメントすべてにマッチ(0セグメントも含む)。
完全な例
{
"id": "model-v1",
"name": "UNS Model V1",
"variable_types": {
"site_id": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_]{0,31}$" },
"line_id": { "type": "string", "pattern": "^Line[0-9]{1,4}$" },
"mode": { "type": "enum", "values": ["auto", "manual"] }
},
"payload_types": {
"line_control": {
"type": "object",
"required": ["Status", "Mode"],
"properties": {
"Status": { "type": "string", "enum": ["running", "stopped"] },
"Mode": { "type": "string", "enum": ["auto", "manual"] }
},
"additionalProperties": false
}
},
"tree": {
"default": {
"children": {
"{site_id}": {
"children": {
"Lines": {
"children": {
"{line_id}": {
"children": {
"LineControl": { "_payload": "line_control" }
}
}
}
},
"stream": {
"children": {
"#": { "_payload": "any" }
}
}
}
}
}
}
}
}強制動作
UNS Governanceはトピック構造と(オプションで)ペイロードスキーマの両方を検証します。
トピック違反(
topic_nomatch、topic_invalid、not_endpoint):topic_nomatch:アクティブなモデルのトピックフィルターがトピックにマッチしなかった。 (モデル固有の検証は実行されません。) アクティブモデルが存在せずUNS Governanceが有効な場合、exempt_topicsを除きトピックはフェイルクローズでtopic_nomatchとして扱われます。topic_invalid:選択されたモデルのフィルターにマッチしたが、トピックがモデルの構造/セグメント制約に違反。not_endpoint:選択されたモデルがトピックパスにマッチしたが、対象ノードがエンドポイントではない。- QoS 0:メッセージは無視されます。
- QoS 1/2:パブリッシュは拒否され、クライアントにプロトコル理由コード(
Not Authorized)が返されます。 - EMQXの
authorization.deny_actionがdisconnectに設定されている場合、トピック認可失敗時にクライアントは切断されます(設定はdisconnectであり、dropではありません)。 authorization.deny_actionがignore(デフォルト)の場合、切断は行われませんが、QoS 1/2は拒否理由コードを受け取ります。- 観測可能なカウンター:
messages_dropped、topic_nomatch、topic_invalid、not_endpoint、およびモデル別カウンターのper_model。
ペイロード違反(
payload_invalid):- メッセージはUNS Governanceによってパブリッシュ処理中にドロップされます。
- この経路では認可拒否や切断は不要です。
- 観測可能なカウンター:
messages_dropped、payload_invalid、およびモデル別カウンターのper_model。
トピックフィルタープリチェック
複数モデルがアクティブな場合、UNS Governanceは完全な検証前にモデルをプリスクリーニングします:
- 各モデルはツリーパスから派生したトピックフィルターパターンにコンパイルされます。
- 変数セグメントは単一レベルワイルドカード(
+)に変換されます。- 例:
foo/{bar}/xはfoo/+/xに変換されます。
- 例:
- アクティブモデルはモデルID順に並べられます。
- UNS Governanceは、パブリッシュトピックにマッチする最初のモデル(ID順)を選択します。
- プリチェックは直接のトピック/フィルタマッチのみを使用し、パブリッシュトピックのプレフィックス展開(例:
/#の付加)は行いません。 - 選択されたモデルのみが完全に検証され、UNS Governanceは次のモデルに進みません。
- プリチェックに失敗したモデルはスキップされ、モデル別ドロップカウンターに寄与しません。
これにより無関係なアクティブモデルによるカウンターの膨張を防ぎ、モデルの動作を決定論的に保ちます。また、モデル間でトピックツリーの重複は避けるべきです。
カウンター
GET /stats はクラスター集約カウンターを返します。
トップレベルカウンター:
messages_total:処理されたメッセージ合計(messages_allowed + messages_dropped)。免除トラフィックも含む。messages_allowed:許可されたメッセージおよび免除されたメッセージ。messages_dropped:UNS検証失敗によるドロップ/拒否メッセージ。topic_nomatch:アクティブモデルのフィルターにマッチしなかったためのドロップ/拒否。topic_invalid:選択モデルのトピック不一致によるドロップ/拒否。not_endpoint:トピックが非エンドポイントノードにマッチしたためのドロップ/拒否。payload_invalid:ペイロードスキーマ不一致によるドロップ。exempt:exempt_topicsによってスキップされたメッセージ。per_model:モデルIDをキーとしたモデル別内訳マップ。recent_drops:最近のドロップイベント(topic、error_type、error_detail、timestamp_ms)。
モデル別カウンター(per_model.<model_id>):
messages_totalmessages_allowedmessages_droppedtopic_invalidnot_endpointpayload_invalid
カウンターの意味:
record_allowedは該当モデルのmessages_totalとmessages_allowedを増加させます。- トピック/ペイロードのドロップは、
messages_total、messages_dropped、および該当モデルの特定理由カウンターを増加させます。 - トピックフィルタープリチェックに合格するモデルがない場合、グローバルに
topic_nomatchが増加し、モデル別ドロップカウンターは増加しません。 これはアクティブモデルセットが空の場合も含みます。
ダウンロード
各EMQXリリースのtarball:
| EMQXバージョン | プラグインバージョン | パッケージ |
|---|---|---|
| 6.1.2 | 0.1.3 | emqx_unsgov-0.1.3.tar.gz |
| 6.1.3 | 0.1.3 | emqx_unsgov-0.1.3.tar.gz |