personal_infra/tofu/nodito/README.md
counterweight 35b3817e15
tofu: stop gitignoring the lock file and the VM inventory
The root .gitignore excluded .terraform.lock.hcl and every *.tfvars, which
hid two things that belong in version control:

- .terraform.lock.hcl pins the provider hashes. versions.tf tracks
  Telmate/proxmox 3.0.2-rc05, a release candidate, so the version
  constraint alone is not enough if that tag is ever re-published.

- terraform.tfvars held one real secret (proxmox_api_token_secret) plus the
  entire vms map — 7 VMs with their vmids, sizes and static IPs. That is
  infra definition, and it existed only on one laptop. Meanwhile the
  committed terraform.tfvars.example still advertised web1/db1.

Split at the credential boundary: the provider auth triple stays in the
gitignored terraform.tfvars, everything else moves to vms.auto.tfvars, which
is committed and auto-loaded (no -var-file needed). terraform.tfvars.example
is now credentials-only. `tofu plan` reports no changes.

State stays ignored — it carries cloud-init attributes and should not be in
git. Noted in the README that it has no remote backend, and that state
manages two VMs (bastion-box, nonkeiwaisi-box) the map does not declare.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-12 18:43:14 +02:00

78 lines
3.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## Nodito VMs with OpenTofu (Proxmox)
This directory lets you declare VMs on the `nodito` Proxmox node and apply with OpenTofu. It clones the Ansible-built template `debian-13-cloud-init` and places disks on the ZFS pool `proxmox-tank-1`.
### Prereqs
- Proxmox API token with VM privileges. Example: user `root@pam`, token name `tofu`.
- OpenTofu installed.
```
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://get.opentofu.org/opentofu.gpg | sudo tee /etc/apt/keyrings/opentofu.gpg >/dev/null
curl -fsSL https://packages.opentofu.org/opentofu/tofu/gpgkey | sudo gpg --no-tty --batch --dearmor -o /etc/apt/keyrings/opentofu-repo.gpg >/dev/null
sudo chmod a+r /etc/apt/keyrings/opentofu.gpg /etc/apt/keyrings/opentofu-repo.gpg
echo \
"deb [signed-by=/etc/apt/keyrings/opentofu.gpg,/etc/apt/keyrings/opentofu-repo.gpg] https://packages.opentofu.org/opentofu/tofu/any/ any main
deb-src [signed-by=/etc/apt/keyrings/opentofu.gpg,/etc/apt/keyrings/opentofu-repo.gpg] https://packages.opentofu.org/opentofu/tofu/any/ any main" | \
sudo tee /etc/apt/sources.list.d/opentofu.list > /dev/null
sudo chmod a+r /etc/apt/sources.list.d/opentofu.list
sudo apt-get update
sudo apt-get install -y tofu
tofu version
```
- The Ansible template exists: `debian-13-cloud-init` (VMID 9001 by default).
### Provider Auth
Credentials are the only thing not in git. Copy `terraform.tfvars.example` to
`terraform.tfvars` (gitignored) and set:
- `proxmox_api_url` (e.g. `https://nodito:8006/api2/json`)
- `proxmox_api_token_id` (e.g. `root@pam!tofu`)
- `proxmox_api_token_secret`
Alternatively, export them as `TF_VAR_proxmox_api_token_secret` etc.
### Declare VMs
VMs are declared in `vms.auto.tfvars`, which is committed. `*.auto.tfvars` is
loaded automatically, so it needs no `-var-file`. Example entry:
```
vms = {
web1 = {
name = "web1"
cores = 2
memory_mb = 2048
disk_size_gb = 20
ipconfig0 = "ip=dhcp" # or "ip=192.168.1.50/24,gw=192.168.1.1"
}
}
```
All VM disks are created on `zfs_storage_name` (defaults to `proxmox-tank-1`). Network attaches to `vmbr0`. VLAN can be set per-VM with `vlan_tag`.
### Usage
```
tofu init
tofu plan
tofu apply
```
`terraform.tfvars` and `vms.auto.tfvars` are both auto-loaded.
> VMs are created once and then protected: the module sets `lifecycle.prevent_destroy = true` and ignores subsequent config changes. After the initial apply, manage day2 changes directly in Proxmox (or remove the lifecycle block if you need OpenTofu to own ongoing updates).
### Notes
- Clones are full clones by default (`full_clone = true`).
- Cloud-init injects `cloud_init_user` and `ssh_authorized_keys`.
- `.terraform.lock.hcl` is committed: it pins the provider hashes, which matters
because `versions.tf` tracks a release candidate (`3.0.2-rc05`).
- State is local (`terraform.tfstate`, gitignored) and has no remote backend, so
it exists only on the machine that last ran `tofu apply`.
- The map is not a complete inventory of nodito: state also manages
`bastion-box` (1100) and `nonkeiwaisi-box` (3300), which are not declared in
`vms.auto.tfvars`. `tofu plan` is clean today, but relaxing the `lifecycle`
block without first declaring them would put them up for destruction.
- Disks use `scsi0` on ZFS with `discard` enabled.