opentofu-modules

OpenTofu Modules & Testing

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "opentofu-modules" with this command: npx skills add ionfury/homelab/ionfury-homelab-opentofu-modules

OpenTofu Modules & Testing

Write OpenTofu modules and tests for the homelab infrastructure. Modules live in infrastructure/modules/ , tests in infrastructure/modules/<name>/tests/ .

Quick Reference

Run tests for a module

task tg:test-<module> # e.g., task tg:test-config

Format all HCL

task tg:fmt

Version pinned in .opentofu-version (currently 1.11.2)

Module Structure

Every module MUST have:

infrastructure/modules/<name>/ ├── variables.tf # Input definitions with descriptions and validations ├── main.tf # Primary resources and locals ├── outputs.tf # Output definitions ├── versions.tf # Provider and OpenTofu version constraints └── tests/ # Test directory └── *.tftest.hcl

Test File Structure

Use .tftest.hcl extension. Define top-level variables for defaults inherited by all run blocks.

Top-level variables set defaults for ALL run blocks

variables { name = "test-cluster" features = ["gateway-api", "longhorn"]

networking = { id = 1 internal_tld = "internal.test.local" # ... other required fields }

Default machine - inherited unless overridden

machines = { node1 = { cluster = "test-cluster" type = "controlplane" install = { selector = "disk.model = *" } interfaces = [{ id = "eth0" hardwareAddr = "aa:bb:cc:dd:ee:01" addresses = [{ ip = "192.168.10.101" }] }] } } }

run "descriptive_test_name" { command = plan # Use plan mode - no real resources created

variables { features = ["prometheus"] # Only override what differs }

assert { condition = output.some_value == "expected" error_message = "Descriptive failure message" } }

Key Patterns

Use command = plan

Always use plan mode for tests. This validates configuration without creating resources.

Variable Inheritance

Only include variables in run blocks when they differ from defaults. Minimizes duplication.

CORRECT: Override only what changes

run "feature_enabled" { command = plan variables { features = ["prometheus"] } assert { ... } }

AVOID: Repeating all variables

run "feature_enabled" { command = plan variables { name = "test-cluster" # Unnecessary - inherited features = ["prometheus"] machines = { ... } # Unnecessary - inherited } }

Assert Against Outputs

Reference module outputs in assertions, not internal resources.

assert { condition = length(output.machines) == 2 error_message = "Expected 2 machines" }

assert { condition = output.talos.kubernetes_version == "1.32.0" error_message = "Version mismatch" }

Test Feature Flags

Test both enabled and disabled states:

run "feature_enabled" { command = plan variables { features = ["longhorn"] }

assert { condition = alltrue([ for m in output.talos.talos_machines : contains(m.install.extensions, "iscsi-tools") ]) error_message = "Extension should be added when feature enabled" } }

run "feature_disabled" { command = plan variables { features = [] }

assert { condition = alltrue([ for m in output.talos.talos_machines : !contains(m.install.extensions, "iscsi-tools") ]) error_message = "Extension should not be present without feature" } }

Test Validations

Use expect_failures to verify variable validation rules:

run "invalid_version_rejected" { command = plan variables { versions = { talos = "1.9.0" # Missing v prefix - should fail # ... } } expect_failures = [var.versions] }

Common Assertions

Check length

condition = length(output.items) == 3

Check key exists

condition = contains(keys(output.map), "expected_key")

Check value in list

condition = contains(output.list, "expected_value")

Check string contains

condition = strcontains(output.config, "expected_substring")

Check all items match

condition = alltrue([for item in output.list : item.enabled == true])

Check any item matches

condition = anytrue([for item in output.list : item.name == "target"])

Nested check with labels/annotations

condition = anytrue([ for label in output.machines["node1"].labels : label.key == "expected-label" && label.value == "expected-value" ])

Test Organization

Organize tests by concern:

  • plan.tftest.hcl

  • Basic structure and output validation

  • validation.tftest.hcl

  • Input validation rules

  • feature_<name>.tftest.hcl

  • Feature flag behavior

  • edge_cases.tftest.hcl

  • Boundary conditions

Detailed Reference

For OpenTofu testing syntax, mock providers, and advanced patterns, see: references/opentofu-testing.md

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

prometheus

No summary provided by upstream source.

Repository SourceNeeds Review
General

taskfiles

No summary provided by upstream source.

Repository SourceNeeds Review
General

terragrunt

No summary provided by upstream source.

Repository SourceNeeds Review