Imported from iwonderanddev/terraform-provider-awx (
AGENTS.md). Install upstream withnpx skills add iwonderanddev/terraform-provider-awx. Copyright stays with the author.
AGENTS.md
Purpose
This repository implements a Terraform provider for AWX API v2, with broad coverage driven by a vendored OpenAPI schema plus curated metadata overrides.
Target compatibility is AWX 24.6.1 (API /api/v2), with HTTP Basic authentication at GA.
Quick Facts
- Language: Go
1.25.0 - Provider address:
registry.terraform.io/iwd/awx - Resource/data source registration is dynamic from embedded manifest JSON
- Object import IDs:
- Collection-created objects: numeric (
42) - Detail-path keyed objects (for example settings): detail identifier (
system)
- Collection-created objects: numeric (
- Relationship import IDs:
- Standard associations:
<primary_id>:<related_id>(for example12:34) - Survey spec relationships:
<resource_id>(for example12)
- Standard associations:
Repository Map
cmd/terraform-provider-awx/main.go: provider server entrypointcmd/awxgen/main.go: generator/validator/docs CLIinternal/provider/*: provider runtime for objects, relationships, data sourcesinternal/client/*: AWX HTTP transport, retries, pagination, errorsinternal/openapi/*: schema parsing + manifest derivation logicinternal/manifest/*: curated controls + generated manifests (embedded at runtime)internal/acceptance/*: direct client-level live AWX acceptance testsdocs/*: generated provider/resource/data-source docsexamples/*: Terraform usage examplesexternal/awx-openapi/schema.json: vendored AWX OpenAPI source schema.gitlab-ci.yml: GitLab CI (optional mirror of default branch and tags to GitHub).github/workflows/release.yml: GitHub Actions release (GoReleaser → Terraform Registry).goreleaser.yml,terraform-registry-manifest.json: multi-platform release assets for the registryscripts/ci/github-installation-token.sh: GitHub App installation token helper for CI
GitLab CI → GitHub mirror
When the canonical remote is GitLab and a GitHub copy should stay in sync, the
mirror_to_github job force-pushes the GitLab default branch only to
refs/heads/<default-branch> on GitHub. The mirror_tag_to_github job runs on
tag pipelines and pushes the same tag ref to GitHub so GitHub Actions can build a release for Terraform Registry. Authentication uses a GitHub App
(JWT signed with the app private key, then
POST /app/installations/{id}/access_tokens); do not use a long-lived PAT for
this flow.
GitHub (one-time): Create a GitHub App with Contents: Read and write, install it for the target owner, and align branch protection with automation because the job force-updates the target default branch.
GitLab CI/CD variables: GITHUB_APP_CLIENT_ID (JWT iss — GitHub recommends the app Client ID for this claim; see Generating a JWT for a GitHub App), GITHUB_APP_INSTALLATION_ID (required for POST /app/installations/{id}/access_tokens; not the same as Client ID), GITHUB_APP_PRIVATE_KEY (PEM; File-type variable is most reliable; if you use a multiline value in the UI, the script normalizes literal \n and CRLF — see scripts/ci/github-installation-token.sh), GITHUB_MIRROR_REPOSITORY (owner/repo). Prefer protected variables for protected branches.
Logs: The installation token must never appear in job output; avoid set -x
around secret handling (the job disables xtrace before resolving the token).
GitLab script expansion: Use normal shell expansion for shell-local
variables (for example ${TOKEN} in the git push URL). Do not write
$${TOKEN} in shell commands: if it reaches bash, $$ becomes the shell PID
and breaks authentication.
Push mode: Push only the checked-out GitLab default-branch commit to
refs/heads/$CI_DEFAULT_BRANCH on GitHub. Do not use git push --mirror
when the intent is to publish only the main branch.
GitLab ref cleanup: The job deletes stale refs/merge-requests/* and
refs/pipelines/* refs from the GitHub remote if they were mirrored by an older
configuration.
Inspecting pipelines (glab): With glab authenticated against your GitLab instance (glab auth login), from the repo root: glab ci list -P 10 (recent pipelines), glab ci status (pipeline for current branch), glab ci trace <job_id> (full job log). Use -R group/project when not inside the checkout.
Source Of Truth Rules
Curated (manual edits expected)
internal/manifest/runtime_exclusions.jsoninternal/manifest/deprecated_exclusions.jsoninternal/manifest/relationship_priorities.jsoninternal/manifest/field_overrides.jsonexternal/awx-openapi/schema.json(normally via update script)external/awx-openapi/README.md(retrieval date/hash after schema updates)
Generated (do not hand-edit)
internal/manifest/managed_objects.jsoninternal/manifest/relationships.jsoninternal/manifest/coverage_report.jsondocs/index.mddocs/resources/*.mddocs/data-sources/*.md
After changing curated inputs or schema, always run:
make generatemake validate-manifestmake docsmake docs-validatemake testmake build
Core Architecture
awxgenloadsexternal/awx-openapi/schema.json.internal/openapiderives managed objects and relationship candidates.- Curated exclusions/priorities/field overrides/deprecation exclusions are applied.
- Generated manifests are written to
internal/manifest/*.json. internal/manifest.Load()embeds and loads catalog metadata at provider startup.- Provider dynamically registers:
- object resources (
object_resource.go) - relationship resources (
relationship_resource.go) - object data sources (
object_data_source.go)
- object resources (
Runtime Behavior Details
Object resources
collectionCreate=true:- Create via
POSTcollection endpoint - State
idis numeric
- Create via
collectionCreate=false:- Lifecycle keyed by detail-path identifier from config (
idrequired) - Non-numeric IDs are allowed for these resources
- Lifecycle keyed by detail-path identifier from config (
- Write-only sensitive fields are sent on create/update and preserved from plan/state; they are not read back from API responses.
- Array/object fields are represented in Terraform as JSON-encoded strings.
- Optional fields with AWX OpenAPI defaults are often marked
Optional + Computedto avoid null/default drift after apply.
Relationship resources
- Standard relationships:
- Inputs: canonical object-specific
*_idattributes (for exampleteam_id,user_id) - State/import ID:
<primary_id>:<related_id>
- Inputs: canonical object-specific
- Survey spec relationships (
.../survey_spec/) are special:- Inputs: canonical parent object
*_idattribute +spec(JSON string) - State/import ID:
<resource_id>
- Inputs: canonical parent object
Data sources
- Deterministic lookup order:
idif providednameexact match (only if the object has anamefield)
- Name lookup must resolve exactly one result; 0 or >1 is an error.
AWX Client Contract
- Auth: HTTP Basic only (
username+password) - TLS options:
insecure_skip_tls_verify,ca_cert_pem - Retry behavior with backoff for retryable failures
- Pagination support via
ListAllfollowing AWXnextlinks Ping()validates connectivity against/api/v2/during provider configure
Commands
make generate: regenerate manifests + coverage reportmake validate-manifest: verify manifests are in sync with generator outputmake docs: regenerate docs from manifestsmake docs-validate: verify docs presence and required sectionsmake coverage-report: print coverage summarymake test: run all Go testsmake test-acceptance: run opt-in live AWX tests (internal/acceptance+ Terraform-driven provider acceptance tests)make build: builddist/terraform-provider-awx
Markdown Quality Gate
- When creating or editing any
*.mdfile, use$markdownlint-auto-fix; the skill is responsible for running markdownlint, applying--fix, resolving remaining violations, and finishing only when lint returns zero errors.
Acceptance Testing
.env is loaded by make test-acceptance if present.
Required:
AWX_ACCEPTANCE=1AWX_BASE_URLAWX_USERNAMEAWX_PASSWORD
Scenario fixture vars:
AWX_TEST_ORGANIZATION_IDAWX_TEST_TEAM_IDAWX_TEST_USER_ID
Suites:
internal/acceptance: direct client-level live API behaviorinternal/provider: Terraform lifecycle/import checks viaterraform-plugin-testing
Common Change Playbooks
1) Refresh AWX schema
./external/awx-openapi/update.sh- Update date/hash in
external/awx-openapi/README.md - Run generate/validate/docs/test command chain
2) Runtime-only object appears in coverage validation
- Confirm object is runtime-only/non-desired-state
- Add exclusion to
internal/manifest/runtime_exclusions.json - Regenerate + validate + docs + tests
3) Schema/runtime mismatch for a field
- Add/adjust entry in
internal/manifest/field_overrides.json - Regenerate + validate manifests
- Update docs and tests as needed
4) Relationship ordering/name behavior needs adjustment
- Modify
internal/manifest/relationship_priorities.json - Regenerate and validate manifests/docs/tests
5) Deprecated endpoint should be removed from provider surface
- Add object/path entry to
internal/manifest/deprecated_exclusions.json - Regenerate and validate manifests/docs/tests
Invariants To Preserve
- Keep AWX-native naming alignment (
awx_<singular>and generated relationship resource names). - Preserve import ID contracts (numeric/detail-key for objects; composite/parent-key for relationships).
- Do not repopulate write-only secret values from read responses.
- Keep generated manifests and docs in sync before concluding a change.
- Treat runtime-only objects via explicit exclusions, not ad hoc runtime branching.
Current Coverage Snapshot
From internal/manifest/coverage_report.json (generated 2026-02-10):
39total object candidates23managed object resources24managed object data sources14runtime exclusions61relationship resources