From 9ad21c5846c2500a1ee7883f866845cd5dff93e5 Mon Sep 17 00:00:00 2001 From: beatz174-bit Date: Tue, 14 Apr 2026 20:18:16 +1000 Subject: [PATCH] Harden generated config temp path creation --- infrastructure/terraform/README.md | 16 +++ .../terraform/scripts/reconcile_from_plan.sh | 105 ++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100755 infrastructure/terraform/scripts/reconcile_from_plan.sh diff --git a/infrastructure/terraform/README.md b/infrastructure/terraform/README.md index 5b5cfb1..53f03d4 100644 --- a/infrastructure/terraform/README.md +++ b/infrastructure/terraform/README.md @@ -31,6 +31,22 @@ Current intent: 3. Add Proxmox inventory/configuration scaffolding and imports later. 4. Introduce Ansible workflow after Terraform-managed inventory is trustworthy. + +## Plan-to-config helper script + +Use `scripts/reconcile_from_plan.sh` to automate Terraform configuration generation from `terraform plan` output (via Terraform's `-generate-config-out`). + +From a Terraform module directory (for example `infrastructure/terraform/docker`): + +```bash +../../scripts/reconcile_from_plan.sh --output-file zz_generated_from_plan.auto.tf +``` + +Notes: +- Best used with an import-first workflow that already contains `import {}` blocks. +- The script writes generated config into a `.auto.tf` file and runs `terraform fmt` on it. +- Always review generated arguments before apply. + ## Safety notes - State files are intentionally gitignored for safety and portability. diff --git a/infrastructure/terraform/scripts/reconcile_from_plan.sh b/infrastructure/terraform/scripts/reconcile_from_plan.sh new file mode 100755 index 0000000..cf11360 --- /dev/null +++ b/infrastructure/terraform/scripts/reconcile_from_plan.sh @@ -0,0 +1,105 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat <<'USAGE' +Usage: + reconcile_from_plan.sh [--output-file ] [--] [terraform plan args...] + +Description: + Runs `terraform plan` with `-generate-config-out` and writes the generated + configuration into a tracked Terraform file (default: + `zz_generated_from_plan.auto.tf`). + + This is designed for import-first workflows where `import { ... }` blocks are + present and Terraform can generate missing resource arguments from live + infrastructure. + +Options: + --output-file Destination .tf/.auto.tf file to receive generated + configuration. Default: zz_generated_from_plan.auto.tf + -h, --help Show this help text. + +Examples: + ./reconcile_from_plan.sh + ./reconcile_from_plan.sh --output-file generated_imports.auto.tf -- -var-file=terraform.tfvars +USAGE +} + +output_file="zz_generated_from_plan.auto.tf" +plan_args=() + +while (($# > 0)); do + case "$1" in + --output-file) + if (($# < 2)); then + echo "error: --output-file requires a value" >&2 + exit 1 + fi + output_file="$2" + shift 2 + ;; + -h|--help) + usage + exit 0 + ;; + --) + shift + plan_args=("$@") + break + ;; + *) + plan_args+=("$1") + shift + ;; + esac +done + +if ! command -v terraform >/dev/null 2>&1; then + echo "error: terraform is not installed or not in PATH" >&2 + exit 1 +fi + +if [[ ! -f "main.tf" ]] && ! compgen -G "*.tf" >/dev/null; then + echo "error: no Terraform configuration (*.tf) found in $(pwd)" >&2 + echo "run this script from a Terraform module directory" >&2 + exit 1 +fi + +generated_tmp_dir="$(mktemp -d -t terraform-generated-XXXXXX)" +generated_tmp="$generated_tmp_dir/generated.tf" +# terraform plan -generate-config-out requires a path that does not already exist +trap 'rm -rf "$generated_tmp_dir"' EXIT + +echo "Running: terraform plan -generate-config-out=$generated_tmp ${plan_args[*]-}" +set +e +terraform plan -generate-config-out="$generated_tmp" "${plan_args[@]}" +plan_exit=$? +set -e + +if [[ $plan_exit -ne 0 && $plan_exit -ne 2 ]]; then + echo "error: terraform plan failed with exit code $plan_exit" >&2 + exit "$plan_exit" +fi + +if [[ ! -s "$generated_tmp" ]]; then + echo "No generated configuration was produced." + echo "Tip: ensure you have import blocks and resources eligible for config generation." + exit 0 +fi + +cat > "$output_file" <> "$output_file" + +terraform fmt "$output_file" >/dev/null + +echo "Generated configuration written to: $output_file" +echo "Next step: review this file and run terraform plan again to confirm intent."