Files
the-custodian/infra/build-machines/haskell/haskell-build.pkr.hcl
tegwick 9bc761c2b5 feat(railiance): implement CUST-WP-0032 Haskell build machine infra
Packer build definition, cloud-init autoinstall, GHCup toolchain script,
boot-time registration agent (state-hub + autossh dual tunnel), systemd
unit, key injection, remote-build Makefile, smoke test, and deployment
README. All 15 tasks complete.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 12:01:30 +02:00

148 lines
3.5 KiB
HCL

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<wait>",
"linux /casper/vmlinuz --- autoinstall ds='nocloud;s=http://{{.HTTPIP}}:{{.HTTPPort}}/'<enter><wait>",
"initrd /casper/initrd<enter><wait>",
"boot<enter>",
]
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",
]
}
}