diff --git a/zroc-ova/packer/ubuntu-2404.pkr.hcl b/zroc-ova/packer/ubuntu-2404.pkr.hcl index 6b0b2f4..636c484 100644 --- a/zroc-ova/packer/ubuntu-2404.pkr.hcl +++ b/zroc-ova/packer/ubuntu-2404.pkr.hcl @@ -1,10 +1,6 @@ packer { required_version = ">= 1.10.0" required_plugins { - vmware = { - source = "github.com/hashicorp/vmware" - version = "~> 1.0" - } qemu = { source = "github.com/hashicorp/qemu" version = "~> 1.0" @@ -14,12 +10,12 @@ packer { variable "ubuntu_iso_url" { type = string - default = "https://releases.ubuntu.com/24.04/ubuntu-24.04.2-live-server-amd64.iso" + default = "https://releases.ubuntu.com/24.04/ubuntu-24.04.4-live-server-amd64.iso" } variable "ubuntu_iso_checksum" { type = string - default = "file:https://releases.ubuntu.com/24.04/SHA256SUMS" + default = "sha256:e907d92eeec9df64163a7e454cbc8d7755e8ddc7ed42f99dbc80c40f1a138433" } variable "vm_name" { @@ -52,56 +48,13 @@ variable "output_dir" { default = "../output" } -variable "headless" { - type = bool - default = true -} - -source "vmware-iso" "ubuntu2404" { - vm_name = "${var.vm_name}-${var.vm_version}" - guest_os_type = "ubuntu-64" - headless = var.headless - iso_url = var.ubuntu_iso_url - iso_checksum = var.ubuntu_iso_checksum - disk_size = var.disk_size_mb - disk_adapter_type = "pvscsi" - memory = var.memory_mb - cpus = var.cpus - network_adapter_type = "vmxnet3" - network = "nat" - disk_type_id = 0 - http_directory = "http" - http_port_min = 8100 - http_port_max = 8199 - boot_wait = "5s" - boot_command = [ - "e", - "", - " autoinstall ds=nocloud-net;seedfrom=http://{{.HTTPIP}}:{{.HTTPPort}}/", - "", - ] - ssh_username = "zroc" - ssh_password = "zroc-setup-temp" - ssh_timeout = "30m" - ssh_port = 22 - shutdown_command = "echo 'zroc-setup-temp' | sudo -S shutdown -P now" - output_directory = "${var.output_dir}/vmware" - skip_export = false - format = "ovf" - vmx_data = { - "virtualHW.version" = "19" - "tools.syncTime" = "TRUE" - "annotation" = "zROC Appliance v${var.vm_version}" - "guestOS" = "ubuntu-64" - } -} - source "qemu" "ubuntu2404" { vm_name = "${var.vm_name}-${var.vm_version}" iso_url = var.ubuntu_iso_url iso_checksum = var.ubuntu_iso_checksum disk_size = "${var.disk_size_mb}M" disk_interface = "virtio" + format = "qcow2" memory = var.memory_mb cpus = var.cpus accelerator = "kvm" @@ -121,14 +74,13 @@ source "qemu" "ubuntu2404" { ssh_timeout = "45m" shutdown_command = "echo 'zroc-setup-temp' | sudo -S shutdown -P now" output_directory = "${var.output_dir}/qemu" - format = "qcow2" } build { name = "zroc-appliance" - sources = ["source.vmware-iso.ubuntu2404"] + sources = ["source.qemu.ubuntu2404"] - # Copy overlay files (setup wizard, etc.) into the VM before provisioning + # Copy overlay files (setup wizard binary, etc.) into the VM provisioner "file" { source = "../overlays/" destination = "/tmp/overlays/" @@ -166,14 +118,17 @@ build { execute_command = "echo 'zroc-setup-temp' | sudo -S bash {{.Path}}" } + # Convert qcow2 → VMDK → OVA (no ovftool required) post-processor "shell-local" { - only = ["vmware-iso.ubuntu2404"] inline = [ - "cd ${var.output_dir}/vmware", - "ovftool --compress=9 *.ovf ../${var.vm_name}-${var.vm_version}-ubuntu-24.04-amd64.ova", - "cd ..", - "sha256sum ${var.vm_name}-${var.vm_version}-ubuntu-24.04-amd64.ova > ${var.vm_name}-${var.vm_version}-ubuntu-24.04-amd64.ova.sha256", - "echo 'OVA packaged successfully'", + "bash ../scripts/qcow2-to-ova.sh ${var.output_dir}/qemu/${var.vm_name}-${var.vm_version} ${var.output_dir}/${var.vm_name}-${var.vm_version}-ubuntu-24.04-amd64.ova ${var.vm_name} ${var.vm_version}", + ] + } + + # Produce a KVM/libvirt/Proxmox-compatible qcow2 artifact + post-processor "shell-local" { + inline = [ + "bash ../scripts/qcow2-to-kvm.sh ${var.output_dir}/qemu/${var.vm_name}-${var.vm_version} ${var.output_dir}/${var.vm_name}-${var.vm_version}-ubuntu-24.04-amd64.qcow2", ] } } diff --git a/zroc-ova/packer/variables.pkrvars.hcl b/zroc-ova/packer/variables.pkrvars.hcl index 17fe9f8..b5da886 100644 --- a/zroc-ova/packer/variables.pkrvars.hcl +++ b/zroc-ova/packer/variables.pkrvars.hcl @@ -1,12 +1,11 @@ # zroc-ova/packer/variables.pkrvars.hcl vm_version = "1.0.0" -ubuntu_iso_url = "https://releases.ubuntu.com/24.04/ubuntu-24.04.2-live-server-amd64.iso" -ubuntu_iso_checksum = "file:https://releases.ubuntu.com/24.04/SHA256SUMS" +ubuntu_iso_url = "https://releases.ubuntu.com/24.04/ubuntu-24.04.4-live-server-amd64.iso" +ubuntu_iso_checksum = "sha256:e907d92eeec9df64163a7e454cbc8d7755e8ddc7ed42f99dbc80c40f1a138433" memory_mb = 8192 cpus = 4 disk_size_mb = 102400 -headless = true output_dir = "../output" diff --git a/zroc-ova/scripts/qcow2-to-kvm.sh b/zroc-ova/scripts/qcow2-to-kvm.sh new file mode 100755 index 0000000..2b66e39 --- /dev/null +++ b/zroc-ova/scripts/qcow2-to-kvm.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# qcow2-to-kvm.sh — Package a QEMU qcow2 image as a KVM/libvirt/Proxmox artifact. +# +# Usage: qcow2-to-kvm.sh +# +# Example: +# qcow2-to-kvm.sh ../output/qemu/zroc-appliance-1.0.0 \ +# ../output/zroc-appliance-1.0.0-ubuntu-24.04-amd64.qcow2 + +set -euo pipefail + +QEMU_VM_PATH="$1" # path to qcow2 (without extension) or directory +QCOW2_OUT="$2" # destination .qcow2 file + +# ── Locate the source qcow2 ─────────────────────────────────────────────────── +if [[ -f "${QEMU_VM_PATH}.qcow2" ]]; then + QCOW2_SRC="${QEMU_VM_PATH}.qcow2" +elif [[ -d "$QEMU_VM_PATH" ]]; then + QCOW2_SRC=$(find "$QEMU_VM_PATH" -name "*.qcow2" | head -1) +else + QCOW2_SRC="$QEMU_VM_PATH" +fi + +if [[ -z "$QCOW2_SRC" || ! -f "$QCOW2_SRC" ]]; then + echo "ERROR: could not find qcow2 image at ${QEMU_VM_PATH}" >&2 + exit 1 +fi + +echo "==> [qcow2-to-kvm] Source qcow2: $QCOW2_SRC" +echo "==> [qcow2-to-kvm] Output qcow2: $QCOW2_OUT" + +mkdir -p "$(dirname "$QCOW2_OUT")" + +# Re-encode with qemu-img to compact/sparsify and ensure compatibility. +# subformat=compressed produces a space-efficient image suitable for distribution. +echo "==> [qcow2-to-kvm] Compacting qcow2 for distribution…" +qemu-img convert \ + -f qcow2 \ + -O qcow2 \ + -o compression_type=zlib,preallocation=off \ + "$QCOW2_SRC" \ + "$QCOW2_OUT" + +SIZE=$(du -sh "$QCOW2_OUT" | cut -f1) +SHA=$(sha256sum "$QCOW2_OUT" | awk '{print $1}') + +echo "==> [qcow2-to-kvm] qcow2 complete: $QCOW2_OUT ($SIZE)" +echo "==> [qcow2-to-kvm] SHA256: $SHA" +echo "$SHA $(basename "$QCOW2_OUT")" > "${QCOW2_OUT}.sha256" +echo "==> [qcow2-to-kvm] Done" diff --git a/zroc-ova/scripts/qcow2-to-ova.sh b/zroc-ova/scripts/qcow2-to-ova.sh new file mode 100755 index 0000000..c679056 --- /dev/null +++ b/zroc-ova/scripts/qcow2-to-ova.sh @@ -0,0 +1,177 @@ +#!/usr/bin/env bash +# qcow2-to-ova.sh — Convert a QEMU qcow2 disk image to a VMware-compatible OVA +# without requiring ovftool. +# +# Usage: qcow2-to-ova.sh +# +# Example: +# qcow2-to-ova.sh ../output/qemu/zroc-appliance-1.0.0 \ +# ../output/zroc-appliance-1.0.0-ubuntu-24.04-amd64.ova \ +# zroc-appliance 1.0.0 + +set -euo pipefail + +QEMU_VM_PATH="$1" # path to the qcow2 file (without extension) or directory +OVA_OUT="$2" # destination .ova file +VM_NAME="$3" # display name inside the OVF +VM_VERSION="$4" # version string + +# ── Locate the qcow2 ────────────────────────────────────────────────────────── +if [[ -f "${QEMU_VM_PATH}.qcow2" ]]; then + QCOW2="${QEMU_VM_PATH}.qcow2" +elif [[ -d "$QEMU_VM_PATH" ]]; then + QCOW2=$(find "$QEMU_VM_PATH" -name "*.qcow2" | head -1) +else + # Packer QEMU plugin writes (no extension) as the output file + QCOW2="$QEMU_VM_PATH" +fi + +if [[ -z "$QCOW2" || ! -f "$QCOW2" ]]; then + echo "ERROR: could not find qcow2 image at ${QEMU_VM_PATH}" >&2 + exit 1 +fi + +echo "==> [qcow2-to-ova] Source qcow2: $QCOW2" +echo "==> [qcow2-to-ova] Output OVA: $OVA_OUT" + +WORK_DIR=$(mktemp -d) +trap 'rm -rf "$WORK_DIR"' EXIT + +VMDK_NAME="${VM_NAME}-disk1.vmdk" +OVF_NAME="${VM_NAME}.ovf" +MF_NAME="${VM_NAME}.mf" + +# ── 1. Convert qcow2 → stream-optimised VMDK ───────────────────────────────── +echo "==> [qcow2-to-ova] Converting qcow2 → VMDK (stream-optimised)…" +qemu-img convert \ + -f qcow2 \ + -O vmdk \ + -o subformat=streamOptimized,adapter_type=lsilogic,compat6 \ + "$QCOW2" \ + "${WORK_DIR}/${VMDK_NAME}" + +DISK_SIZE_BYTES=$(qemu-img info --output=json "${WORK_DIR}/${VMDK_NAME}" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['virtual-size'])") +DISK_SIZE_GB=$(( (DISK_SIZE_BYTES + 1073741823) / 1073741824 )) +DISK_FILE_BYTES=$(stat -c%s "${WORK_DIR}/${VMDK_NAME}") + +echo "==> [qcow2-to-ova] VMDK: virtual=${DISK_SIZE_GB}GB, file=${DISK_FILE_BYTES} bytes" + +# ── 2. Generate OVF descriptor ──────────────────────────────────────────────── +echo "==> [qcow2-to-ova] Generating OVF descriptor…" +cat > "${WORK_DIR}/${OVF_NAME}" << OVFEOF + + + + + + + Virtual disk information + + + + The list of logical networks + + VM Network + + + + zROC Observability Console Appliance v${VM_VERSION} + ${VM_NAME} + + A human-readable annotation + zROC Appliance v${VM_VERSION} — https://github.com/recklessop/zroc + + + The kind of installed guest operating system + Ubuntu Linux (64-bit) + + + Virtual hardware requirements + + Virtual Hardware Family + 0 + ${VM_NAME} + vmx-19 + + + hertz * 10^6 + Number of virtual CPUs + 4 virtual CPU(s) + 1 + 3 + 4 + + + byte * 2^20 + Memory Size + 8192 MB of memory + 2 + 4 + 8192 + + + 0 + SCSI Controller + SCSI Controller 0 + 3 + lsilogic + 6 + + + 0 + Hard Disk 1 + ovf:/disk/vmdisk1 + 4 + 3 + 17 + + + 7 + true + VM Network + VmxNet3 ethernet adapter + Network Adapter 1 + 5 + VmxNet3 + 10 + + + + +OVFEOF + +# ── 3. Generate manifest (.mf) with SHA256 checksums ───────────────────────── +echo "==> [qcow2-to-ova] Generating manifest…" +OVF_SHA=$(sha256sum "${WORK_DIR}/${OVF_NAME}" | awk '{print $1}') +VMDK_SHA=$(sha256sum "${WORK_DIR}/${VMDK_NAME}" | awk '{print $1}') +cat > "${WORK_DIR}/${MF_NAME}" << MFEOF +SHA256(${OVF_NAME})= ${OVF_SHA} +SHA256(${VMDK_NAME})= ${VMDK_SHA} +MFEOF + +# ── 4. Package as OVA (tar, OVF first per spec) ─────────────────────────────── +echo "==> [qcow2-to-ova] Packaging OVA…" +mkdir -p "$(dirname "$OVA_OUT")" +tar -C "$WORK_DIR" \ + --format=ustar \ + -cf "$OVA_OUT" \ + "${OVF_NAME}" \ + "${VMDK_NAME}" \ + "${MF_NAME}" + +OVA_SIZE=$(du -sh "$OVA_OUT" | cut -f1) +OVA_SHA=$(sha256sum "$OVA_OUT" | awk '{print $1}') + +echo "==> [qcow2-to-ova] OVA complete: $OVA_OUT ($OVA_SIZE)" +echo "==> [qcow2-to-ova] SHA256: $OVA_SHA" +echo "$OVA_SHA $(basename "$OVA_OUT")" > "${OVA_OUT}.sha256" +echo "==> [qcow2-to-ova] Done"