packer { required_plugins { virtualbox = { version = ">= 1.1.0" source = "github.com/hashicorp/virtualbox" } } } variable "vm_name" { type = string default = "haskell-build" } variable "disk_size" { type = number default = 40960 } variable "memory" { type = number default = 8192 } variable "cpus" { type = number default = 4 } variable "ghc_primary_version" { type = string default = "9.8.4" } variable "ghc_secondary_version" { type = string default = "9.6.6" } variable "cabal_version" { type = string default = "3.12.1.0" } variable "iso_url" { type = string default = "https://releases.ubuntu.com/24.04/ubuntu-24.04.2-live-server-amd64.iso" } variable "iso_checksum" { type = string default = "sha256:d6dab0c3a657988501b4bd76f1297c053df710e06e0c3aece60dead24f270b4d" } locals { timestamp = formatdate("YYYYMMDD", timestamp()) } source "virtualbox-iso" "haskell-build" { vm_name = var.vm_name guest_os_type = "Ubuntu_64" disk_size = var.disk_size hard_drive_interface = "sata" memory = var.memory cpus = var.cpus iso_url = var.iso_url iso_checksum = var.iso_checksum # NAT during build — Packer needs internet for ISO + packages. # Bridged networking is set post-import by setup-vm.sh (adapter names # are laptop-specific and cannot be baked into the image). vboxmanage = [ ["modifyvm", "{{.Name}}", "--nat-localhostreachable1", "on"], ] http_directory = "files/cloud-init" boot_wait = "5s" boot_command = [ "c", "linux /casper/vmlinuz --- autoinstall ds='nocloud;s=http://{{.HTTPIP}}:{{.HTTPPort}}/'", "initrd /casper/initrd", "boot", ] ssh_username = "build" ssh_password = "build" ssh_timeout = "30m" ssh_handshake_attempts = 100 shutdown_command = "echo 'build' | sudo -S shutdown -P now" # File provisioners — stage agent files before install script runs # (Packer uploads to /tmp by default for file provisioners) output_directory = "output-${var.vm_name}" output_filename = "${var.vm_name}" } build { sources = ["source.virtualbox-iso.haskell-build"] # Stage agent files to /tmp (install-agent.sh moves them into place) provisioner "file" { source = "files/build-agent.py" destination = "/tmp/build-agent.py" } provisioner "file" { source = "files/build-agent.service" destination = "/tmp/build-agent.service" } provisioner "file" { source = "files/build-agent.env.template" destination = "/tmp/build-agent.env.template" } # Install Haskell toolchain (GHCup + GHC + Cabal) provisioner "shell" { execute_command = "echo 'build' | sudo -S env {{ .Vars }} bash '{{ .Path }}'" script = "scripts/install-haskell.sh" environment_vars = [ "GHC_PRIMARY_VERSION=${var.ghc_primary_version}", "GHC_SECONDARY_VERSION=${var.ghc_secondary_version}", "CABAL_VERSION=${var.cabal_version}", ] } # Install build-agent + systemd unit provisioner "shell" { execute_command = "echo 'build' | sudo -S env {{ .Vars }} bash '{{ .Path }}'" script = "scripts/install-agent.sh" } # Export as OVA post-processor "vagrant" { only = [] # disabled — we use the raw OVA below } post-processor "shell-local" { inline = [ "cd output-${var.vm_name} && mv ${var.vm_name}.ova ../haskell-build-${local.timestamp}.ova || true", ] } }