mcpField
I
infrahub-managing-generators

infrahub-managing-generators

github.com/opsmillクラウド・DevOps27160 回インストール1 日前に更新
リポジトリ

infrahub-managing-generators について

infrahub-managing-generators は、Infrahub Generator を作成する開発者向けのスキルです。GraphQL で設計データを取得して追跡可能なインフラオブジェクトを生成する方法を、スキーマ、登録、テストとともに説明します。

主な機能

  1. 01設計に基づくオブジェクト生成
  2. 02GraphQL クエリのガイダンス
  3. 03Python Generator の実装
  4. 04冪等な作成・更新パターン
  5. 05Generator の登録と依存関係の追跡
  6. 06infrahubctl による検証

活用シーン

  1. 01設計オブジェクトからインフラを生成
  2. 02テンプレートからオブジェクトと関係を作成
  3. 03Generator の反復実行を実装
  4. 04Generator のスキーマや追跡の問題を調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/opsmill/infrahub-skills --skill infrahub-managing-generators

インストール後、Claude Code で/infrahub-managing-generatorsを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

examples.md
reference.md
rules/
_sections.md
_template.md
api-reference.md
architecture-components.md
patterns-common.md
patterns-hydration.md
patterns-natural-key-preflight.md
patterns-path-traversal.md
python-concurrent-relationship-writes.md
python-delete-ordering.md
python-generate.md
python-multi-peer-add.md
python-relationship-references.md
registration-config.md
registration-watch-dependencies.md
testing-commands.md
testing-integration.md
tracking-idempotent.md

詳細

Infrahub Generator Creator

概要

Infrahub Generator を作成するための専門的なガイダンスです。Generator は GraphQL を介して Infrahub からデータをクエリし、その結果に基づいて新しいノードと リレーションシップを作成します -- これにより、「設計」オブジェクトが自動的に ダウンストリームのインフラストラクチャを作成する、設計駆動型の 自動化が可能になります。

プロジェクトコンテキスト

Infrahub 設定: !cat .infrahub.yml 2>/dev/null || echo "No .infrahub.yml found"

既存の Generator: !find . -name "*.py" -path "*/generators/*" 2>/dev/null | head -20

使用すべき場面

  • 設計駆動型の自動化の構築 (トポロジー -> デバイス)
  • テンプレートまたは設計定義からのオブジェクトの作成
  • 冪等な create-or-update ワークフローの実装
  • 高レベルの設計からのインフラストラクチャの自動生成
  • Generator のトラッキングシステムの理解

ルールカテゴリ

優先度カテゴリプレフィックス説明
CRITICALアーキテクチャarchitecture-コンポーネント、グループ
CRITICALPython クラスpython-Generator、generate()
HIGHトラッキングtracking-Upsert、冪等
HIGHAPI リファレンスapi-コンストラクター、プロパティ
HIGH登録registration-.infrahub.yml 設定
MEDIUMパターンpatterns-クリーニング、バッチ、ストア
LOWテストtesting-infrahubctl コマンド

このスキルに必要な前提条件

ジェネレーターは実際のオブジェクトを作成するため、スキーマはジェネレーターが出力する形状を許容する必要があります。初回実行前にこうした不足を見つけてください。バグのあるジェネレーターを再実行すると、追跡クリーンアップによってデータが削除されることがあります。

ジェネレーターが…スキーマに必要な条件…参照先
種類 X のオブジェクトを作成するジェネレーターが設定する属性を持つノード X を定義していること。種類に存在しないフィールドは、エラーなしでリクエスト送信前に破棄され、必須フィールドが不足していると作成が中止されます../infrahub-managing-schemas/rules/attribute-defaults-and-types.md
作成したオブジェクトを親にリンクする識別子が一致する Component/Parent のリレーションシップペアがあり、Parent 側で optional: false が指定されていること../infrahub-managing-schemas/rules/relationship-component-parent.md
出力を決めるために「design」ノードを読み取るジェネレーターの追跡キーが実行間で安定するよう、そのノードの human_friendly_id を定義していること../infrahub-managing-schemas/rules/display-human-friendly-id.md
グループへの所属によってトリガーされる種類を問わず、design オブジェクトがすでに所属しているグループを対象にすること。該当するグループが存在しない場合に限り、CoreStandardGroup を作成してください。CoreGeneratorGroup はジェネレーター自身の出力グループですrules/registration-config.md
再実行時に冪等である必要があるすべての save() で allow_upsert=True を使用すること。実行時の追跡コンテキストによって、以前の実行で作成され、再作成されなかったオブジェクトが削除されますrules/tracking-idempotent.md
リポジトリから何か(共有パッケージ、生成されたプロトコル、独自のクエリモデルなど)をインポートする.infrahub.yml に、それらすべてのパスを指定した watch: ブロックを含めること。インポートは追跡されないため、ヘルパーの宣言がないと、そのヘルパーが変更された際にジェネレーターが再実行されなくなりますrules/registration-watch-dependencies.md
カーディナリティが many のリレーションシップに複数のピアを追加するリストには .extend() を使用するか、ピアごとに .add() を呼び出すループを使用すること。リストを指定して .add() を呼び出すことはできませんrules/python-multi-peer-add.md
複数の実行で同時に書き込まれる可能性があるリレーションシップにピアを追加するnode.add_relationships(relation_to_update=..., related_nodes=[ids]) を使用することrules/python-concurrent-relationship-writes.md
ジェネレーターが以前に作成したオブジェクトを削除するピアを削除する前に、そのピアを参照するリレーションシップを切り離し、その間にホルダーを保存すること。削除後に save(allow_upsert=True) を実行すると、インメモリマネージャーから ID が再送信されますrules/python-delete-ordering.md
ジェネレーターを変更して、前回とは異なるオブジェクト群を生成するgenerate() から到達可能なすべての save() を、ヘルパー内のものも含めて監査することrules/tracking-idempotent.md

Python を書く前に

ジェネレーターは、設計からオブジェクトを計算して生成するものです。これから書こうとしているものが「ハードコードされたリストから、特定の N 個のオブジェクトを作る」のであれば、そのリストはデータです。objects/ に移し、オブジェクトローダーに直接処理させるか、より小さなジェネレーターに渡してください。InfrahubGenerator を使う前に、次の段階を確認してください。

シグナルより簡単なレイヤー参照するルール
ジェネレーターにオブジェクトリスト、ロールカタログ、ステータスセットがハードコードされているobjects/ 配下の YAML データファイル(オブジェクトローダーで読み込み)yagni-generator-hardcoding-data
ジェネレーターが組み込みの IPAM/VLAN プリミティブ(カスタム IP アドレス、プレフィックス、VLAN ノード)を再作成しているスキーマで inherit_from: [BuiltinIPAddress / BuiltinIPPrefix / IpamVLAN] を指定し、プリミティブを再実装するのではなく、ジェネレーターで参照を計算するyagni-custom-domain-primitives-instead-of-builtin
ジェネレーターの出力形状が、opsmill/schema-library にすでにあるオブジェクトと重複しているライブラリのジェネリックを inherit_from で継承する。ジェネレーターが計算するのはインスタンスであり、形状ではありませんyagni-duplicate-shape-not-extracted-to-generic
ジェネレーターが ipaddress の計算、random、または手書きの「最初の空きを探す」ループを使ってサブネット/IP/VLAN/ポートを割り当てている組み込みのリソースプールを使う。allocate_next_ip_prefix/allocate_next_ip_address、CoreIPPrefixPool/CoreNumberPool は使用状況を追跡し、再実行しても冪等性を保ちますyagni-imperative-allocation-vs-resource-pool
generate() が計算(分岐、派生する命名、割り当て)をせず、固定値を持つ一定の子オブジェクト群を登録しているユーザーが複製するオブジェクトテンプレート(generate_template: true)。構造は Python ではなくデータに記述しますyagni-generator-that-should-be-template

bootstrap/、seed/、demo/ 配下のブートストラップ、シード、デモ用ジェネレーターは例外です。初期状態をハードコードすることを目的としているためです。設計定義からオブジェクトを実際に計算する場合は Python を使用してください。適切なケースについては、rules/python-generate.md を参照してください。

Python を書く場合は、SDK 呼び出しで文字列の種類ではなく、生成されたプロトコルクラスを型として指定してください。たとえば kind="NetworkDevice" ではなく client.create(NetworkDevice, ...) とします。これにより、スキーマが変更された場合、返されたオブジェクトの属性読み取りに関する問題を型チェック時に検出できます。create() に渡すフィールド名は型チェックされません。詳しくは、protocols-adopt-typed-kinds を参照してください。

ジェネレーターの基本

すべてのジェネレーターには、次の 3 つの要素があります。

  1. 対象グループ -- ジェネレーターを起動するオブジェクト
  2. GraphQL クエリ(.gql ファイル) -- 設計データを取得します
  3. Python クラス -- InfrahubGenerator を継承し、generate() を実装します
from infrahub_sdk.generator import InfrahubGenerator

class MyGenerator(InfrahubGenerator):
    async def generate(self, data: dict) -> None:
        obj = await self.client.create(
            kind="DcimDevice",
            data={"name": "spine-01"},
        )
        await obj.save(allow_upsert=True)

ワークフロー

ジェネレーターを作成する際は、次の手順に従ってください。

  1. 設計パターンを特定する — どの「設計」 オブジェクトが生成をトリガーしますか?そこからどのオブジェクトを 作成すべきですか?対象グループとジェネレーターのコンポーネントについては rules/architecture-components.md を参照してください。
  2. GraphQL クエリを作成する — 設計データを取得する .gql ファイル を作成します。クエリのパターンについては ../infrahub-common/graphql-queries.md を参照してください。リポジトリが schema.graphql を保持している場合、そのファイルは生成されるものです。フィールドが不足しているときは 編集するのではなく再エクスポートしてください。 ../infrahub-common/rules/protocols-generated.md を参照してください。
  3. Python クラスを実装する — InfrahubGenerator を継承し、 generate() を実装します。クラスのパターンについては rules/python-generate.md を、利用可能なメソッドについては rules/api-reference.md を参照してください。
  4. 冪等にする — allow_upsert=True を使用して、 再実行しても重複なく作成または更新されるようにします。 rules/tracking-idempotent.md を参照してください。
  5. from_graphql を採用する機会がないか確認する — もし generate() がレスポンスのエッジを反復処理し、 self.client.get() を呼び出して型付きピアを再取得しているなら、 InfrahubNode.from_graphql() へのリファクタリングを検討し、 O(N + 1) 回のラウンドトリップを O(1) に削減できないか考えてください。判断ツリー、検出のヒューリスティック、 リファクタリングの手順については rules/patterns-hydration.md を参照してください。
  6. グラフ走査を制約する。generate() が 2 つのノード間のルートを必要とする場合は、手書きのホップごとの 走査ではなく SDK の traverse_paths を使用し、リレーションシップ識別子と 深さの上限によって制約してください。種別フィルタリングはどのノードが 現れてよいかを制限するものであり、どのエッジをたどるかではありません。したがって、 共有された参照オブジェクトは無関係なサブグラフ同士を橋渡ししてしまい、 走査は構造的には妥当でも無意味な結果を返します。パラメーターの意味と 切り捨てのシグナルについては rules/patterns-path-traversal.md を参照してください。
  7. .infrahub.yml に登録する — 対象グループを指定して generator_definitions の下に追加します。 rules/registration-config.md を参照してください。 次に、watch.files で Generator の依存関係を宣言します。そのインポートと 実行時のファイル読み取りを確認し、それらが解決されるすべてのファーストパーティのパスを 挙げてください。兄弟クエリモデルも含みます。常にこのキーを持たせてください。 Generator が自身のファイル以外に依存関係を本当に持たない場合は files: [] とします。 rules/registration-watch-dependencies.md を参照してください。ここでは、既存の watch ブロックについて、欠落しているエントリ、 古くなったエントリ、誤ったエントリがないかを確認する方法も扱っています。
  8. テストする — infrahubctl generator を実行して検証します。 rules/testing-commands.md を参照してください。

関連リファレンス

コメント