terraform { required_providers { proxmox = { source = "bpg/proxmox" version = "~> 0.61.0" } truenas = { source = "deevus/truenas" version = "~> 0.1.0" } } } variable "vm_id" { description = "The ID of the VM to create (should be unique per PR)" type = number } variable "pr_number" { description = "The Pull Request number for this staging environment" type = string } variable "truenas_snapshot_id" { description = "The ID of the TrueNAS snapshot to clone" type = string } provider "proxmox" { # Relies on PROXMOX_VE_ENDPOINT and PROXMOX_VE_API_TOKEN environment variables } provider "truenas" { # Relies on TRUENAS_API_KEY and TRUENAS_BASE_URL environment variables } resource "truenas_dataset" "staging_clone" { pool = "tank" path = "production/staging-pr-${var.pr_number}" snapshot_id = var.truenas_snapshot_id } resource "proxmox_virtual_environment_vm" "staging_vm" { name = "staging-pr-${var.pr_number}" description = "Ephemeral staging environment for PR #${var.pr_number}" node_name = "pve" vm_id = var.vm_id # Clone from the latest golden image template clone { vm_id = 9000 full = true } agent { enabled = true } cpu { cores = 2 } memory { dedicated = 2048 } network_device { bridge = "vmbr0" firewall = true } # Cloud-Init configuration to inject the staging age key and set up networking initialization { ip_config { ipv4 { address = "dhcp" } } user_data_file_id = "local:snippets/staging-key.yaml" } } resource "proxmox_virtual_environment_firewall_options" "staging_vm_fw_options" { vm_id = proxmox_virtual_environment_vm.staging_vm.vm_id node_name = proxmox_virtual_environment_vm.staging_vm.node_name enable = true policy_in = "ACCEPT" policy_out = "DROP" } resource "proxmox_virtual_environment_firewall_rules" "staging_vm_rules" { vm_id = proxmox_virtual_environment_vm.staging_vm.vm_id node_name = proxmox_virtual_environment_vm.staging_vm.node_name rule { action = "ACCEPT" type = "out" dest = "192.168.0.11" comment = "Allow traffic to TrueNAS" } rule { action = "ACCEPT" type = "out" dest = "192.168.0.1" comment = "Allow traffic to Gateway/DNS" } rule { action = "DROP" type = "out" dest = "192.168.0.0/24" comment = "Drop traffic to local homelab" } rule { action = "ACCEPT" type = "out" dest = "0.0.0.0/0" comment = "Allow outbound internet traffic" } } output "staging_vm_ip" { value = proxmox_virtual_environment_vm.staging_vm.ipv4_addresses[1][0] # Adjust index based on actual returned interfaces description = "The IP address of the newly spun up staging VM." }