diff --git a/infrastructure/terraform/.gitignore b/infrastructure/terraform/.gitignore new file mode 100644 index 0000000..60bb0ee --- /dev/null +++ b/infrastructure/terraform/.gitignore @@ -0,0 +1,14 @@ +.terraform/ +*.tfstate +*.tfstate.* +*.tfvars +*.tfvars.json +crash.log +override.tf +override.tf.json +*_override.tf +*_override.tf.json +*.tfplan +plan.out +state/ +artifacts/ diff --git a/infrastructure/terraform/README.md b/infrastructure/terraform/README.md new file mode 100644 index 0000000..5b5cfb1 --- /dev/null +++ b/infrastructure/terraform/README.md @@ -0,0 +1,38 @@ +# Terraform foundations + +This directory introduces Terraform in a conservative, incremental way for this homelab repo. + +## Purpose in this repository + +Terraform is used here to **document and gradually adopt management** of existing infrastructure without disrupting running services. + +Current intent: +- Start with imported live Docker resources so infrastructure is visible and reproducible in code. +- Add Proxmox inventory/configuration later once provider details and import IDs are confirmed. +- Keep this phase local-state and learning-oriented (no remote backend yet). + +## Tool boundaries + +- **Docker Compose**: day-to-day application/service runtime definitions already used by this repo. +- **Terraform**: infrastructure state capture and controlled resource management (starting with imports). +- **Ansible**: follow-on host/configuration management after Terraform inventory and targets are stable. +- **NixOS**: host OS/system-level declarative configuration, separate from per-service compose workflows. + +## Layout + +- `docker/`: Docker provider scaffold and incremental import workflow. +- `proxmox/`: placeholder scaffold for later Proxmox adoption. +- `modules/`: placeholder module directories for future shared patterns. + +## Incremental adoption plan + +1. Import Docker containers one-by-one into Terraform state. +2. Reconcile and stabilize Docker Terraform configuration until `terraform plan` is clean. +3. Add Proxmox inventory/configuration scaffolding and imports later. +4. Introduce Ansible workflow after Terraform-managed inventory is trustworthy. + +## Safety notes + +- State files are intentionally gitignored for safety and portability. +- Do **not** run `terraform apply` until imported resources are fully reconciled and plan output is reviewed as no-op for intended targets. +- No remote backend is configured yet by design. diff --git a/infrastructure/terraform/docker/README.md b/infrastructure/terraform/docker/README.md new file mode 100644 index 0000000..1a99988 --- /dev/null +++ b/infrastructure/terraform/docker/README.md @@ -0,0 +1,48 @@ +# Docker Terraform scaffold + +This directory is for **incremental, import-first Terraform adoption** of existing Docker containers. + +## What this directory is for + +- Document existing live Docker resources in Terraform. +- Import containers one-by-one. +- Reconcile Terraform code with real runtime values until plan is clean. + +## Initialize + +From this directory: + +```bash +terraform init +``` + +## Safe incremental import workflow + +1. Add one `docker_container` resource block in `main.tf` for an already-running container. +2. Import it into state: + + ```bash + terraform import docker_container. + ``` + +3. Inspect imported state: + + ```bash + terraform state show docker_container. + ``` + +4. Copy required/meaningful arguments from state output into `main.tf`. +5. Run `terraform plan` and refine until there are no unintended changes. + +## Reconciliation guidance + +- Keep one resource block per imported container. +- Prefer explicit values for arguments that affect recreation. +- Avoid broad changes; reconcile each container independently. +- Do **not** run `terraform apply` until plan output is intentionally clean. + +## State and secrets handling + +- State files are ignored via `../.gitignore` because they may contain environment-specific metadata. +- Do not commit real `.tfvars` files with machine-specific values. +- Use `terraform.tfvars.example` as a safe starter template. diff --git a/infrastructure/terraform/docker/main.tf b/infrastructure/terraform/docker/main.tf index 8114314..ad60c96 100644 --- a/infrastructure/terraform/docker/main.tf +++ b/infrastructure/terraform/docker/main.tf @@ -1,16 +1,17 @@ -terraform { - required_providers { - docker = { - source = "kreuzwerker/docker" - version = "~> 3.0" - } - } -} +# Docker Terraform workflow in this repo: +# 1) Add a minimal resource block for ONE existing container. +# 2) Import that live container into state: +# terraform import docker_container. +# 3) Inspect imported arguments: +# terraform state show docker_container. +# 4) Copy required arguments into this file and refine. +# 5) Repeat until terraform plan shows no unintended changes. -provider "docker" { - host = "unix:///var/run/docker.sock" -} -resource "docker_container" "searxng" { - name = "searxng-webapp" - image = "searxng/searxng" -} +# Example skeleton for future imported containers (intentionally commented): +# resource "docker_container" "example_service" { +# name = "existing-container-name" +# image = "repo/image:tag" +# +# # Add additional arguments based on `terraform state show` output. +# # Keep values aligned with the live container so plan is a no-op. +# } diff --git a/infrastructure/terraform/docker/outputs.tf b/infrastructure/terraform/docker/outputs.tf new file mode 100644 index 0000000..2179104 --- /dev/null +++ b/infrastructure/terraform/docker/outputs.tf @@ -0,0 +1,19 @@ +output "docker_host_in_use" { + description = "Docker daemon endpoint currently targeted by this workspace." + value = var.docker_host +} + +output "managed_container_names" { + description = "Names of containers intentionally tracked in Terraform configuration." + value = var.managed_container_names +} + +output "import_reconciliation_steps" { + description = "Short reminder of the safe import-first workflow." + value = [ + "Create one docker_container block for an existing container.", + "Run terraform import for that block.", + "Run terraform state show and copy required arguments.", + "Refine config until terraform plan has no unintended changes.", + ] +} diff --git a/infrastructure/terraform/docker/providers.tf b/infrastructure/terraform/docker/providers.tf new file mode 100644 index 0000000..b002244 --- /dev/null +++ b/infrastructure/terraform/docker/providers.tf @@ -0,0 +1,4 @@ +provider "docker" { + # Local Docker socket default for incremental import/documentation workflow. + host = var.docker_host +} diff --git a/infrastructure/terraform/docker/terraform.tfvars.example b/infrastructure/terraform/docker/terraform.tfvars.example new file mode 100644 index 0000000..fe5449d --- /dev/null +++ b/infrastructure/terraform/docker/terraform.tfvars.example @@ -0,0 +1,9 @@ +# Example only. Copy to terraform.tfvars for local use if needed. +# Do not commit host-specific overrides. + +# docker_host = "unix:///var/run/docker.sock" + +# Optional: list container names intentionally tracked in Terraform outputs. +managed_container_names = [ + "example-container-name" +] diff --git a/infrastructure/terraform/docker/variables.tf b/infrastructure/terraform/docker/variables.tf new file mode 100644 index 0000000..3fc5dde --- /dev/null +++ b/infrastructure/terraform/docker/variables.tf @@ -0,0 +1,11 @@ +variable "docker_host" { + description = "Docker daemon host for local import workflow." + type = string + default = "unix:///var/run/docker.sock" +} + +variable "managed_container_names" { + description = "Human-maintained list of containers intentionally tracked in Terraform docs/outputs." + type = list(string) + default = [] +} diff --git a/infrastructure/terraform/docker/versions.tf b/infrastructure/terraform/docker/versions.tf new file mode 100644 index 0000000..04a5754 --- /dev/null +++ b/infrastructure/terraform/docker/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.6.0" + + required_providers { + docker = { + source = "kreuzwerker/docker" + version = "3.0.2" + } + } +} diff --git a/infrastructure/terraform/modules/docker_container_placeholder/README.md b/infrastructure/terraform/modules/docker_container_placeholder/README.md new file mode 100644 index 0000000..04e60fd --- /dev/null +++ b/infrastructure/terraform/modules/docker_container_placeholder/README.md @@ -0,0 +1,6 @@ +# docker_container_placeholder module + +Placeholder module directory for future shared Docker container patterns. + +This is intentionally empty during initial import-first adoption. +Keep per-container resources explicit in `../../docker/main.tf` until stable patterns emerge. diff --git a/infrastructure/terraform/modules/proxmox_vm_placeholder/README.md b/infrastructure/terraform/modules/proxmox_vm_placeholder/README.md new file mode 100644 index 0000000..12b4aec --- /dev/null +++ b/infrastructure/terraform/modules/proxmox_vm_placeholder/README.md @@ -0,0 +1,6 @@ +# proxmox_vm_placeholder module + +Placeholder module directory for future shared Proxmox VM patterns. + +This is intentionally empty until provider schemas, import ID formats, +and non-destructive reconciliation strategy are validated. diff --git a/infrastructure/terraform/proxmox/README.md b/infrastructure/terraform/proxmox/README.md new file mode 100644 index 0000000..b70f961 --- /dev/null +++ b/infrastructure/terraform/proxmox/README.md @@ -0,0 +1,36 @@ +# Proxmox Terraform scaffold + +This directory is a **placeholder scaffold** for future Proxmox Terraform adoption. + +## What this directory is for + +- Prepare provider/version/variable structure now. +- Delay real Proxmox resource management until import strategy is validated. + +## Initialize + +From this directory: + +```bash +terraform init +``` + +## Current status + +- No live Proxmox resources are defined yet. +- Provider auth variables are placeholders only. +- Import IDs and resource schemas must be verified against provider docs before adding resources. + +## Future safe workflow + +1. Add one resource block for an existing VM/object. +2. Import it with the provider-specific ID format. +3. Inspect with `terraform state show`. +4. Reconcile `.tf` arguments until `terraform plan` is clean. +5. Repeat incrementally. + +## Safety notes + +- Do not commit real credentials in `.tf` files or tracked `.tfvars`. +- State files are ignored by the Terraform-level `.gitignore`. +- Do not run `terraform apply` until plan is intentionally no-op for existing resources. diff --git a/infrastructure/terraform/proxmox/main.tf b/infrastructure/terraform/proxmox/main.tf new file mode 100644 index 0000000..9089e92 --- /dev/null +++ b/infrastructure/terraform/proxmox/main.tf @@ -0,0 +1,14 @@ +# Proxmox scaffold only. +# +# IMPORTANT: +# - Resource blocks are intentionally omitted for now. +# - Before adding resources, confirm: +# 1) provider resource schemas, +# 2) exact import ID formats, +# 3) non-destructive reconciliation strategy for existing VMs. +# +# Suggested future workflow mirrors docker/: +# - Define one resource for an existing object. +# - Import it. +# - Use `terraform state show` to reconcile config. +# - Proceed incrementally. diff --git a/infrastructure/terraform/proxmox/outputs.tf b/infrastructure/terraform/proxmox/outputs.tf new file mode 100644 index 0000000..998156a --- /dev/null +++ b/infrastructure/terraform/proxmox/outputs.tf @@ -0,0 +1,9 @@ +output "proxmox_scaffold_ready" { + description = "Indicates this directory is a placeholder scaffold for future Proxmox adoption." + value = true +} + +output "proxmox_endpoint_configured" { + description = "Whether a non-empty endpoint has been provided." + value = var.proxmox_endpoint != "" +} diff --git a/infrastructure/terraform/proxmox/providers.tf b/infrastructure/terraform/proxmox/providers.tf new file mode 100644 index 0000000..1b8e1e1 --- /dev/null +++ b/infrastructure/terraform/proxmox/providers.tf @@ -0,0 +1,11 @@ +provider "proxmox" { + # Placeholder-only scaffold. + # Confirm exact provider auth mode and endpoint details before real use. + endpoint = var.proxmox_endpoint + insecure = var.proxmox_insecure + + username = var.proxmox_username + password = var.proxmox_password + + api_token = var.proxmox_api_token +} diff --git a/infrastructure/terraform/proxmox/terraform.tfvars.example b/infrastructure/terraform/proxmox/terraform.tfvars.example new file mode 100644 index 0000000..adbce78 --- /dev/null +++ b/infrastructure/terraform/proxmox/terraform.tfvars.example @@ -0,0 +1,9 @@ +# Example placeholders only. Do not commit real credentials. + +proxmox_endpoint = "https://pve.example.local:8006/api2/json" +proxmox_insecure = false + +# Use either username/password or API token based on your chosen auth flow. +proxmox_username = "root@pam" +proxmox_password = "REPLACE_ME" +proxmox_api_token = "REPLACE_ME" diff --git a/infrastructure/terraform/proxmox/variables.tf b/infrastructure/terraform/proxmox/variables.tf new file mode 100644 index 0000000..dc78e7e --- /dev/null +++ b/infrastructure/terraform/proxmox/variables.tf @@ -0,0 +1,31 @@ +variable "proxmox_endpoint" { + description = "Proxmox API endpoint URL, for example https://pve.example.local:8006/api2/json" + type = string + default = "" +} + +variable "proxmox_insecure" { + description = "Set true only for local testing with self-signed TLS; prefer false in stable environments." + type = bool + default = false +} + +variable "proxmox_username" { + description = "Username for password-based auth (placeholder; optional if token auth is used)." + type = string + default = "" +} + +variable "proxmox_password" { + description = "Password for password-based auth (placeholder; optional if token auth is used)." + type = string + default = "" + sensitive = true +} + +variable "proxmox_api_token" { + description = "API token for token-based auth (placeholder; optional if username/password is used)." + type = string + default = "" + sensitive = true +} diff --git a/infrastructure/terraform/proxmox/versions.tf b/infrastructure/terraform/proxmox/versions.tf new file mode 100644 index 0000000..4f4dee4 --- /dev/null +++ b/infrastructure/terraform/proxmox/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.6.0" + + required_providers { + proxmox = { + source = "bpg/proxmox" + version = "0.68.0" + } + } +}