terraform: add parameterized multi-VM deployment system
Some checks failed
Run nix flake check / flake-check (push) Failing after 1m52s
Run nix flake check / flake-check (pull_request) Failing after 1m24s

Implements Phase 1 of the OpenTofu deployment plan:
- Replace single-VM configuration with locals-based for_each pattern
- Support multiple VMs in single deployment
- Automatic DHCP vs static IP detection
- Configurable defaults with per-VM overrides
- Dynamic outputs for VM IPs and specifications

New files:
- outputs.tf: Dynamic outputs for deployed VMs
- vms.tf: VM definitions using locals.vms map

Updated files:
- variables.tf: Added default variables for VM configuration
- README.md: Comprehensive documentation and examples

Removed files:
- vm.tf: Replaced by new vms.tf (archived as vm.tf.old, then removed)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-31 23:30:00 +01:00
parent b3132fbe70
commit 7aa5137039
5 changed files with 376 additions and 93 deletions

114
terraform/vms.tf Normal file
View File

@@ -0,0 +1,114 @@
# VM Definitions
# Define all VMs to deploy in the locals.vms map below
# Omit fields to use defaults from variables.tf
locals {
# Define VMs here
# Each VM can override defaults by specifying values
# Omit "ip" field for DHCP, include it for static IP
vms = {
# Example DHCP VM (uncomment to deploy):
# "example-dhcp-vm" = {
# cpu_cores = 2
# memory = 2048
# disk_size = "20G"
# }
# Example Static IP VM (uncomment to deploy):
# "example-static-vm" = {
# ip = "10.69.13.50/24"
# cpu_cores = 4
# memory = 4096
# disk_size = "50G"
# }
# Example Minimal VM using all defaults (uncomment to deploy):
# "minimal-vm" = {}
}
# Compute VM configurations with defaults applied
vm_configs = {
for name, vm in local.vms : name => {
target_node = lookup(vm, "target_node", var.default_target_node)
template_name = lookup(vm, "template_name", var.default_template_name)
cpu_cores = lookup(vm, "cpu_cores", var.default_cpu_cores)
memory = lookup(vm, "memory", var.default_memory)
disk_size = lookup(vm, "disk_size", var.default_disk_size)
storage = lookup(vm, "storage", var.default_storage)
bridge = lookup(vm, "bridge", var.default_bridge)
vlan_tag = lookup(vm, "vlan_tag", var.default_vlan_tag)
ssh_public_key = lookup(vm, "ssh_public_key", var.default_ssh_public_key)
nameservers = lookup(vm, "nameservers", var.default_nameservers)
search_domain = lookup(vm, "search_domain", var.default_search_domain)
# Network configuration - detect DHCP vs static
ip = lookup(vm, "ip", null)
gateway = lookup(vm, "gateway", var.default_gateway)
}
}
}
# Deploy all VMs using for_each
resource "proxmox_vm_qemu" "vm" {
for_each = local.vm_configs
name = each.key
target_node = each.value.target_node
# Clone from template
clone = each.value.template_name
full_clone = true
# Boot configuration
boot = "order=virtio0"
scsihw = "virtio-scsi-single"
# VM settings
cpu {
cores = each.value.cpu_cores
}
memory = each.value.memory
# Network
network {
id = 0
model = "virtio"
bridge = each.value.bridge
tag = each.value.vlan_tag
}
# Disk settings
disks {
virtio {
virtio0 {
disk {
size = each.value.disk_size
storage = each.value.storage
}
}
}
}
# Start on boot
start_at_node_boot = true
# Agent
agent = 1
# Cloud-init configuration
ciuser = "root"
sshkeys = each.value.ssh_public_key
nameserver = each.value.nameservers
searchdomain = each.value.search_domain
# Network configuration - DHCP or static IP
ipconfig0 = each.value.ip != null ? "ip=${each.value.ip},gw=${each.value.gateway}" : "ip=dhcp"
# Skip IPv6 since we don't use it
skip_ipv6 = true
# RNG device for better entropy
rng {
source = "/dev/urandom"
period = 1000
}
}