Architecture Overview
Relevant source files
The following files were used as context for generating this wiki page:
The opsmill.infrahub Ansible collection provides a structured interface for interacting with Infrahub, an infrastructure data platform. It enables users to manage infrastructure data through Ansible playbooks by providing specialized modules, inventory plugins, and lookup plugins. The architecture prioritizes standard Ansible patterns, idempotent state management, and a unified SDK abstraction layer.
Sources: dev/knowledge/architecture.md:3-5, AGENTS.md:3-5
Collection Structure
The collection follows a standard Ansible directory layout, separating user-facing interfaces from internal logic and utilities.
| Directory | Component Type | Purpose |
|---|---|---|
plugins/modules/ | Module Stubs | User-facing interface and argument validation. |
plugins/action/ | Action Plugins | Controller-side execution logic for API calls. |
plugins/inventory/ | Inventory Plugin | Dynamic inventory generation from Infrahub data. |
plugins/lookup/ | Lookup Plugin | Inline GraphQL query execution in playbooks. |
plugins/module_utils/ | Shared Utilities | Core logic, SDK wrappers, and base classes. |
plugins/doc_fragments/ | Doc Fragments | Reusable YAML documentation blocks. |
Sources: dev/knowledge/architecture.md:7-17, plugins/AGENTS.md:7-15
Plugin Execution Patterns
The collection strictly follows two established patterns for plugin execution to ensure consistency and reliability.
1. Module-Utils Pattern
This pattern manages stateful CRUD (Create, Read, Update, Delete) operations. The module stub in plugins/modules/ delegates all logic to an InfrahubModule subclass located in plugins/module_utils/. This pattern supports idempotency, check mode, and diff output.
Example Modules: node, branch.
2. Action Plugin Pattern
This pattern handles controller-side API calls, typically for read-only queries or operations where idempotency is not applicable. The module stub is minimal, primarily providing documentation, while the ActionModule in plugins/action/ performs the actual work.
Example Modules: query_graphql, artifact_fetch, artifact_generate.
Sources: dev/constitution.md:29-38, dev/adr/0001-two-plugin-patterns.md
Execution Data Flow
The following diagram illustrates the two distinct paths an Ansible task can take based on the plugin pattern.
The diagram shows how both patterns eventually converge at the InfrahubclientWrapper for API communication.
Sources: dev/knowledge/architecture.md:52-73
Core Abstractions
SDK Abstraction Layer
All communication with the Infrahub API is mediated through the InfrahubclientWrapper. This wrapper encapsulates the infrahub-sdk and ensures that modules do not call the SDK directly.
- Sync-Only: The collection uses
InfrahubClientSyncexclusively; asynchronous calls are prohibited. - Conditional Imports: Files guard SDK imports using a
HAS_INFRAHUBCLIENTflag to allowansible-docto parse files without the SDK installed. - Exception Mapping: The
handle_infrahub_exceptions_decoratormaps SDK-specific exceptions to standard Ansible error messages.
Sources: dev/constitution.md:52-64, plugins/AGENTS.md:44-55
Idempotency and State Management
Modules managing objects must follow a "fetch-compare-act" cycle. The system fetches the existing object, compares it with the desired state, and only performs an API call if changes are necessary.
_ensure_object_exists(): Handles creation or updates._ensure_object_absent(): Handles deletion.check_mode: Supported by skipping mutations whenmodule.check_modeis enabled.- Diff Support: Provided via
_build_diff(before, after).
Sources: dev/constitution.md:40-50, dev/knowledge/plugin-patterns.md:120-129
Common Configuration
Plugins share a standard set of arguments for connecting to Infrahub, defined in INFRAHUB_ARG_SPEC.
| Parameter | Type | Default | Environment Variable |
|---|---|---|---|
api_endpoint | str | None | INFRAHUB_ADDRESS |
token | str | None | INFRAHUB_API_TOKEN |
timeout | int | 10 | None |
branch | str | main | None |
validate_certs | bool | True | None |
Sources: dev/knowledge/plugin-patterns.md:44-55, plugins/AGENTS.md:33-42
Implementation Example: Module Stub
Modules utilize deepcopy to extend the standard argument specification.
def main():
argument_spec = deepcopy(INFRAHUB_ARG_SPEC)
argument_spec.update(
kind=dict(required=True, type="str"),
data=dict(required=True, type="raw"),
)
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
node_module = NodeModule(module=module)
node_module.run()
Sources: [dev/knowledge/plugin-patterns.md:65-72]
Summary
The opsmill.infrahub collection architecture centralizes API logic within a wrapper and strictly enforces two plugin patterns to maintain idempotency and Ansible standards. By delegating complex logic to module_utils and action plugins, the collection provides a robust and predictable developer experience for managing Infrahub data.