Hello,
I have a Debian 12 packer template I’m trying to build. I have successfully created the template with a preseed.cfg file, but I’d also like to attach an iso with cd_files that include a templated cloud.cfg file.
Here’s the build file:
/*
DESCRIPTION:
Debian 12 (Bookworm) build definition.
Packer Plugin for Proxmox (`proxmox-iso` builder).
*/
// BLOCK: packer
// The Packer configuration.
packer {
required_plugins {
ansible = {
source = "github.com/hashicorp/ansible"
version = "~> 1"
}
proxmox = {
version = ">= 1.1.3"
source = "github.com/hashicorp/proxmox"
}
git = {
version = ">= 0.4.3"
source = "github.com/ethanmdavidson/git"
}
sshkey = {
version = ">= 1.0.1"
source = "github.com/ivoronin/sshkey"
}
}
}
// BLOCK: data
// Defines the data sources.
data "sshkey" "install" {
name = var.build_username
}
data "git-repository" "cwd" {}
// BLOCK: locals
// Defines the local variables.
locals {
ansible_password_encrypted = bcrypt(var.ansible_password)
build_password_encrypted = bcrypt(var.build_password)
additional_cd_files = ["./config/"]
boot_command = [
"<esc><wait>",
"auto preseed/url=http://${local.http_ip}:{{ .HTTPPort }}/preseed.cfg",
"<enter>"
]
build_by = "Built by: HashiCorp Packer ${packer.version}"
build_date = formatdate("YYYY-MM-DD hh:mm ZZZ", timestamp())
build_version = data.git-repository.cwd.head
build_description = "Version: ${local.build_version}\nBuilt on: ${local.build_date}\n${local.build_by}"
http_ip = var.http_bind_address == null ? "{{ .HTTPIP }}" : var.http_bind_address
iso_file = "debian-12.1.0-amd64-netinst.iso"
iso_target_path = "${path.root}"
iso_target_extension = "iso"
manifest_date = formatdate("YYYY-MM-DD hh:mm:ss", timestamp())
manifest_path = "${path.cwd}/manifests/"
manifest_output = "${local.manifest_path}${local.manifest_date}.json"
proxmox_username = !(var.proxmox_api_token == null) ? join("!", [var.proxmox_username, var.proxmox_api_token_id]) : var.proxmox_username
vm_guest_os_family = "linux"
vm_guest_os_name = "debian"
vm_guest_os_version = "12"
vm_name = "${local.vm_guest_os_family}.${local.vm_guest_os_name}${local.vm_guest_os_version}"
vm_iso_file = var.vm_iso_file == null ? join("/", ["local:iso", local.iso_file]) : null
data_source_content = {
"/preseed.cfg" = templatefile("${abspath(path.root)}/data/preseed.pkrtpl.hcl", {
build_username = var.build_username
build_password = var.build_password
build_password_encrypted = local.build_password_encrypted
build_key = var.build_key
temp_build_key = data.sshkey.install.public_key
vm_guest_os_language = var.vm_guest_os_language
vm_guest_os_keyboard = var.vm_guest_os_keyboard
vm_guest_os_timezone = var.vm_guest_os_timezone
common_data_source = var.common_data_source
})
}
data_source_command = var.common_data_source == "http" ? local.http_ip : "file=/media/preseed.cfg"
template_name = local.vm_name
template_description = "Base template for Debian 12"
}
source "file" "cloud-init" {
content = templatefile("${abspath(path.root)}/config/cloud.pkrtpl.cfg", {
ansible_username = var.ansible_username
ansible_password = local.ansible_password_encrypted
ansible_key = var.ansible_key != null ? var.ansible_key : ""
build_username = var.build_username
build_password = local.build_password_encrypted
build_key = var.build_key != null ? var.build_key : ""
vm_guest_os_language = var.vm_guest_os_language
vm_guest_os_keyboard = var.vm_guest_os_keyboard
vm_guest_os_timezone = var.vm_guest_os_timezone
})
target = "${path.root}/config/cloud.cfg"
}
source "proxmox-iso" "linux-debian" {
// Proxmox datacenter and credentials
proxmox_url = var.proxmox_url
username = local.proxmox_username
password = var.proxmox_api_token == null ? var.proxmox_password : null
token = var.proxmox_password == null ? var.proxmox_api_token : null
insecure_skip_tls_verify = var.proxmox_insecure_connection
// Proxmox settings
node = var.proxmox_node
pool = var.proxmox_resource_pool
task_timeout = var.proxmox_task_timeout
// Virtual Machine settings
vm_name = local.vm_name
vm_id = var.vm_id
memory = var.vm_mem_size
ballooning_minimum = var.vm_enable_ballooning ? var.vm_min_mem_size : 0
cores = var.vm_cpu_core_count
sockets = var.vm_cpu_count
os = var.vm_os
bios = var.vm_bios
qemu_agent = var.vm_enable_qemu_agent
scsi_controller = var.vm_scsi_controller
onboot = var.vm_start_on_boot
disable_kvm = var.vm_disable_kvm
vm_interface = var.vm_interface
network_adapters {
model = var.vm_nic_model
packet_queues = var.vm_enable_queues ? var.vm_number_of_queues : 0
mac_address = var.vm_nic_mac_address
mtu = var.vm_nic_mtu
bridge = var.vm_nic_bridge
vlan_tag = var.vm_nic_vlan
firewall = var.vm_enable_firewall
}
disks {
type = var.vm_disk_type
storage_pool = var.vm_storage_pool
disk_size = var.vm_disk_size
cache_mode = var.vm_cache_mode
format = var.vm_disk_format
io_thread = var.vm_enable_io_threading
discard = var.vm_enable_disk_discard
ssd = var.vm_enable_ssd
}
// Removable media settings
iso_file = local.vm_iso_file
unmount_iso = var.vm_unmount_iso
dynamic "additional_iso_files" {
for_each = var.enable_cloud_init ? [1] : [0]
content {
iso_storage_pool = var.cloud_init_storage_pool
cd_files = !(var.additional_cd_files == []) ? concat(["./config/cloud.cfg"], var.additional_cd_files) : ["./config/cloud.cfg"]
cd_label = "cidata"
}
}
// HTTP data
http_content = var.common_data_source == "http" ? local.data_source_content : null
http_port_max = var.http_port_max
http_port_min = var.http_port_min
http_bind_address = var.http_bind_address
http_interface = var.http_interface
// Cloud init settings
cloud_init = var.enable_cloud_init
cloud_init_storage_pool = var.enable_cloud_init ? var.cloud_init_storage_pool : null
// Boot settings
boot_wait = var.boot_wait
boot_command = [
"<esc><wait>",
"auto preseed/url=http://${local.http_ip}:{{ .HTTPPort }}/preseed.cfg",
"<enter>"
]
// Communicator settings and credentials
communicator = "ssh"
ssh_username = var.build_username
ssh_private_key_file = data.sshkey.install.private_key_path
// Template settings
template_name = var.common_create_template ? local.template_name : null
template_description = var.common_create_template ? local.template_description : null
}
build {
sources = [
"source.file.cloud-init",
"source.proxmox-iso.linux-debian"
]
# provisioning the vm template for cloud-init integration in Proxmox
provisioner "file" {
source = "./files/99-pve.cfg"
destination = "/tmp/99-pve.cfg"
}
provisioner "file" {
source = "./config/cloud.cfg"
destination = "/tmp/cloud.cfg"
}
provisioner "shell" {
inline = ["sudo cp /tmp/99-pve.cfg /etc/cloud/cloud.cfg.d/99-pve.cfg"]
}
}
When I don’t include the “additional_iso_files” the build runs successfully, however, the cloud init execution doesn’t work because there is no attached cloud init drive on the cloned VM. To resolve, I added a dynamic block for additional_iso_files, so that when enable_cloud_init == true, it’ll template out the cloud.cfg file, and add that to the additionally mounted .iso. However, the build fails here:
file.cloud-init: output will be in this color.
proxmox-iso.linux-<sensitive>: output will be in this color.
==> proxmox-iso.linux-<sensitive>: Creating CD disk...
==> file.cloud-init: Uploading ./files/99-pve.cfg => /tmp/99-pve.cfg
proxmox-iso.linux-<sensitive>: xorriso 1.5.4 : RockRidge filesystem manipulator, libburnia project.
file.cloud-init: 99-pve.cfg 39 B / 39 B [=======================================================================================================================================================] 100.00% 0s
proxmox-iso.linux-<sensitive>: Drive current: -outdev 'stdio:/tmp/packer180824401.iso'
proxmox-iso.linux-<sensitive>: Media current: stdio file, overwriteable
proxmox-iso.linux-<sensitive>: Media status : is blank
proxmox-iso.linux-<sensitive>: Media summary: 0 sessions, 0 data blocks, 0 data, 950g free
proxmox-iso.linux-<sensitive>: xorriso : WARNING : -volid text does not comply to ISO 9660 / ECMA 119 rules
proxmox-iso.linux-<sensitive>: Added to ISO image: directory '/'='/tmp/packer_to_cdrom2247504117'
proxmox-iso.linux-<sensitive>: xorriso : UPDATE : 1 files added in 1 seconds
proxmox-iso.linux-<sensitive>: xorriso : UPDATE : 1 files added in 1 seconds
==> file.cloud-init: Uploading ./config/cloud.cfg => /tmp/cloud.cfg
file.cloud-init: cloud.cfg 3.97 KiB / 3.97 KiB [================================================================================================================================================] 100.00% 0s
==> file.cloud-init: Provisioning with shell script: /tmp/packer-shell709328922
==> file.cloud-init: Provisioning with shell script: /tmp/packer-shell46206222
Build 'file.cloud-init' finished after 62 milliseconds 722 microseconds.
proxmox-iso.linux-<sensitive>: ISO image produced: 185 sectors
proxmox-iso.linux-<sensitive>: Written to medium : 185 sectors at LBA 0
proxmox-iso.linux-<sensitive>: Writing to 'stdio:/tmp/packer180824401.iso' completed successfully.
proxmox-iso.linux-<sensitive>: Done copying paths from CD_dirs
==> proxmox-iso.linux-<sensitive>: 501 write to temporary file failed -
==> proxmox-iso.linux-<sensitive>: 501 write to temporary file failed -
==> proxmox-iso.linux-<sensitive>: Step "stepUploadAdditionalISO" failed
The cloud init storage pool is a directory I created on the proxmox host, and I’ve added the Datastore.User role to both the API token and the API user.