From 6788f04d06fd19edfaeb3fd3f178bf8b7869dba1 Mon Sep 17 00:00:00 2001 From: subramanianaug@gmail.com Date: Fri, 26 Jun 2026 14:26:35 -0700 Subject: [PATCH 1/1] builder: add Ubuntu 24.04 cloud-image template builder Ubuntu 24.04 (noble) no longer publishes the legacy debian-installer netboot tree, so make-template.ml cannot build noble templates via preseed + virt-install. Add make-ubuntu-cloud-template.sh to build a virt-builder template from the official noble cloud image, detect-cloudimg-expand.sh for expand= partition detection, tests, and README documentation. Direct make-template ubuntu 24.04 to the cloud script with a clear error. Signed-off-by: subramanianaug@gmail.com diff --git a/builder/templates/Makefile.am b/builder/templates/Makefile.am index b4d06357..27ef20ec 100644 --- a/builder/templates/Makefile.am +++ b/builder/templates/Makefile.am @@ -24,7 +24,13 @@ EXTRA_DIST = \ *.ks \ *.virt-install-cmd \ debian.preseed \ + detect-cloudimg-expand.sh \ make-template.ml \ + make-ubuntu-cloud-template.sh \ + README-ubuntu-cloud.md \ + test-make-template-noble.sh \ + test-make-ubuntu-cloud-template-integration.sh \ + test-make-ubuntu-cloud-template.sh \ ubuntu.preseed \ validate.sh @@ -42,7 +48,15 @@ index: $(index_fragments) TESTS_ENVIRONMENT = \ top_srcdir="$(top_srcdir)" \ $(top_builddir)/run --test -TESTS = validate.sh +TESTS = \ + validate.sh \ + test-make-ubuntu-cloud-template.sh \ + test-make-template-noble.sh + +SLOW_TESTS = test-make-ubuntu-cloud-template-integration.sh + +check-slow: + $(MAKE) check TESTS="$(SLOW_TESTS)" SLOW=1 check-valgrind: $(MAKE) VG="@VG@" check diff --git a/builder/templates/README-ubuntu-cloud.md b/builder/templates/README-ubuntu-cloud.md new file mode 100644 index 00000000..15ec186f --- /dev/null +++ b/builder/templates/README-ubuntu-cloud.md @@ -0,0 +1,52 @@ +# Ubuntu cloud-image virt-builder templates + +Ubuntu **24.04 (noble)** and later no longer publish the legacy +debian-installer netboot tree: + +```text +http://archive.ubuntu.com/ubuntu/dists/noble/main/installer-amd64/ → 404 +``` + +`make-template.ml` depends on that netboot path (preseed + `virt-install +--location=.../installer-amd64`), so it cannot build noble templates. + +## Building ubuntu-24.04 + +From this directory, on a Linux host with libguestfs-tools installed: + +```bash +./make-ubuntu-cloud-template.sh 24.04 noble +``` + +This downloads the official noble server cloud image, customizes it to +match existing virt-builder Ubuntu templates (root password `root`, +cloud-init disabled, `builder` user removed), converts to raw, compresses +with xz, and writes `ubuntu-24.04.index-fragment`. + +Maintainers then concatenate the fragment into `index`, re-sign +`index.asc`, and upload the `.xz` next to the index on libguestfs.org. + +## Validation notes + +On noble cloud images the root filesystem is usually `/dev/sda1` with +label `cloudimg-rootfs`. `detect-cloudimg-expand.sh` implements the +expand-partition detection used by the builder script. + +Run the fast tests from a build tree: + +```bash +make -C builder/templates check +``` + +The integration test downloads the full cloud image (~600M) and is run +only as a slow test: + +```bash +make -C builder/templates check-slow +``` + +## ubuntu-22.04 + +Jammy still has installer-amd64; use `make-template.ml` if preseed install +works on your host. The cloud script also accepts `22.04 jammy` as a +fallback. diff --git a/builder/templates/detect-cloudimg-expand.sh b/builder/templates/detect-cloudimg-expand.sh new file mode 100644 index 00000000..ce7544b4 --- /dev/null +++ b/builder/templates/detect-cloudimg-expand.sh @@ -0,0 +1,67 @@ +#!/bin/bash - +# libguestfs virt-builder cloud-image helpers +# Copyright (C) 2026 Red Hat Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# detect_cloudimg_expand IMAGE +# +# Print the partition virt-builder should use for expand= on a raw +# Ubuntu cloud image. Returns 1 if no suitable partition is found. +detect_cloudimg_expand () +{ + local image="$1" + local expand + + expand="$( + virt-filesystems --long -a "$image" --parts --blkdevs --filesystems 2>/dev/null | + awk '$2 == "filesystem" && $4 == "cloudimg-rootfs" { print $1; exit }' + )" + if [ -n "$expand" ]; then + echo "$expand" + return 0 + fi + + expand="$( + virt-filesystems --long -a "$image" --parts --blkdevs --filesystems 2>/dev/null | + awk '$2 == "filesystem" && $3 == "ext4" && $1 ~ /^\/dev\/sd[a-z][0-9]+$/ { print $1; exit }' + )" + if [ -n "$expand" ]; then + echo "$expand" + return 0 + fi + + expand="$( + virt-filesystems --long -a "$image" --parts --blkdevs 2>/dev/null | + awk '$2 == "device" && $1 ~ /^\/dev\/sda[0-9]+$/ { print $1 }' | + tail -1 + )" + if [ -n "$expand" ]; then + echo "$expand" + return 0 + fi + + expand="$( + virt-filesystems --long -a "$image" --parts --blkdevs 2>/dev/null | + awk '$2 == "device" && $1 ~ /^\/dev\/vda[0-9]+$/ { print $1 }' | + tail -1 + )" + if [ -n "$expand" ]; then + echo "$expand" + return 0 + fi + + return 1 +} diff --git a/builder/templates/make-template.ml b/builder/templates/make-template.ml index c3df7ff2..9551d5f9 100755 --- a/builder/templates/make-template.ml +++ b/builder/templates/make-template.ml @@ -370,6 +370,11 @@ and os_of_string os ver = | "ubuntu", "18.04" -> Ubuntu (ver, "bionic") | "ubuntu", "20.04" -> Ubuntu (ver, "focal") | "ubuntu", "22.04" -> Ubuntu (ver, "jammy") + | "ubuntu", "24.04" -> + eprintf "%s: Ubuntu 24.04 (noble) has no debian-installer netboot.\n" + prog; + eprintf "Use builder/templates/make-ubuntu-cloud-template.sh instead.\n"; + exit 1 | "fedora", ver -> Fedora (int_of_string ver) | "freebsd", ver -> let maj, min = parse_major_minor ver in FreeBSD (maj, min) | "windows", ver -> parse_windows_version ver diff --git a/builder/templates/make-ubuntu-cloud-template.sh b/builder/templates/make-ubuntu-cloud-template.sh new file mode 100755 index 00000000..52d8c288 --- /dev/null +++ b/builder/templates/make-ubuntu-cloud-template.sh @@ -0,0 +1,165 @@ +#!/bin/bash - +# Build a virt-builder template from an official Ubuntu cloud image. +# +# Ubuntu 24.04 (noble) and later dropped the legacy debian-installer +# netboot under dists//main/installer-amd64, so make-template.ml +# cannot install them via preseed + virt-install. This script is the +# supported replacement for those releases. +# +# Usage: +# ./make-ubuntu-cloud-template.sh [version] [codename] +# Example: +# ./make-ubuntu-cloud-template.sh 24.04 noble +# +# Outputs (in the current directory): +# ubuntu-.img raw disk image +# ubuntu-.xz compressed template +# ubuntu-.index-fragment +# +# Copyright (C) 2026 Red Hat Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +export LANG=C +set -euo pipefail + +VER="${1:-24.04}" +CODENAME="${2:-noble}" +ARCH="${ARCH:-x86_64}" +DISK_GB="${DISK_GB:-6}" +WORKDIR="${WORKDIR:-.}" + +if [ "$ARCH" != x86_64 ]; then + echo "$0: only x86_64 is supported for now" >&2 + exit 1 +fi + +case "$VER:$CODENAME" in + 22.04:jammy|24.04:noble) ;; + *) + echo "$0: unsupported version/codename pair ($VER, $CODENAME)" >&2 + exit 1 + ;; +esac + +TEMPLATE="ubuntu-${VER}" +CLOUD_URL="https://cloud-images.ubuntu.com/${CODENAME}/current/${CODENAME}-server-cloudimg-amd64.img" +QCOW="${WORKDIR}/${TEMPLATE}.qcow2" +RAW="${WORKDIR}/${TEMPLATE}.img" +XZ="${WORKDIR}/${TEMPLATE}.xz" +FRAG="${WORKDIR}/${TEMPLATE}.index-fragment" + +cd "$WORKDIR" + +need() { + command -v "$1" >/dev/null 2>&1 || { + echo "$0: required command not found: $1" >&2 + exit 1 + } +} + +for cmd in wget qemu-img virt-customize virt-sysprep virt-filesystems xz sha512sum; do + need "$cmd" +done + +echo "Downloading ${CLOUD_URL} ..." +wget -q --show-progress -O "$QCOW" "$CLOUD_URL" + +echo "Resizing cloud image to ${DISK_GB}G ..." +qemu-img resize "$QCOW" "${DISK_GB}G" + +echo "Customizing cloud image ..." +virt-customize -a "$QCOW" \ + --root-password password:root \ + --run-command "userdel -f builder 2>/dev/null || true" \ + --run-command "groupdel builder 2>/dev/null || true" \ + --run-command "rm -f /etc/ssh/ssh_host_*" \ + --run-command "ln -sf /dev/null /etc/systemd/system/cloud-init.service" \ + --run-command "ln -sf /dev/null /etc/systemd/system/cloud-init-local.service" \ + --run-command "ln -sf /dev/null /etc/systemd/system/cloud-config.service" \ + --run-command "ln -sf /dev/null /etc/systemd/system/cloud-final.service" \ + --run-command "rm -f /etc/apt/apt.conf; touch /etc/apt/apt.conf" + +echo "Sysprepping template ..." +virt-sysprep -a "$QCOW" \ + --operations defaults,-ssh-hostkeys,-ssh-userdir,-udev-persistent-net + +echo "Converting to raw ..." +qemu-img convert -p -f qcow2 -O raw "$QCOW" "$RAW" + +echo "Detecting root partition for virt-builder expand= ..." +. "$(dirname "$0")/detect-cloudimg-expand.sh" +EXPAND="$(detect_cloudimg_expand "$RAW")" || { + echo "$0: could not detect expand partition; inspect with virt-filesystems" >&2 + exit 1 +} +echo "expand=${EXPAND}" + +echo "Compressing template ..." +xz -k -f "$RAW" +mv -f "${RAW}.xz" "$XZ" + +COMPRESSED_SIZE=$(stat -c%s "$XZ" 2>/dev/null || stat -f%z "$XZ") +VIRTUAL_SIZE=$(qemu-img info "$RAW" | awk -F': ' '/^disk size/ {print $2}') +# Normalize to bytes for index (qemu-img may print KiB/MiB/GiB). +case "$VIRTUAL_SIZE" in + *GiB) SIZE_BYTES=$(echo "$VIRTUAL_SIZE" | awk '{printf "%.0f", $1*1024*1024*1024}') ;; + *MiB) SIZE_BYTES=$(echo "$VIRTUAL_SIZE" | awk '{printf "%.0f", $1*1024*1024}') ;; + *) SIZE_BYTES=$(qemu-img info "$RAW" --output=json | python3 -c 'import json,sys; print(json.load(sys.stdin)["virtual-size"])') ;; +esac + +CHECKSUM=$(sha512sum "$XZ" | awk '{print $1}') + +cat > "$FRAG" </dev/null 2>&1; then + virt-index-validate "$FRAG" +fi + +echo "Created:" +echo " $RAW" +echo " $XZ" +echo " $FRAG" +echo +echo "Next steps for maintainers:" +echo " 1. Validate: virt-builder --source file://$WORKDIR --list" +echo " 2. Concatenate ${FRAG} into the builder index" +echo " 3. Upload ${XZ} next to index.asc on libguestfs.org" diff --git a/builder/templates/test-make-template-noble.sh b/builder/templates/test-make-template-noble.sh new file mode 100644 index 00000000..8b8474bc --- /dev/null +++ b/builder/templates/test-make-template-noble.sh @@ -0,0 +1,39 @@ +#!/bin/bash - +# libguestfs virt-builder make-template noble redirect test +# Copyright (C) 2026 Red Hat Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +export LANG=C +set -e + +if [ ! -x "$top_builddir/run" ]; then + echo "$0: test skipped because $top_builddir/run is not built yet" + exit 77 +fi + +set +e +out="$("$top_builddir/run" ./make-template.ml ubuntu 24.04 2>&1)" +rc=$? +set -e + +if [ "$rc" -ne 1 ]; then + echo "$0: expected make-template.ml ubuntu 24.04 to exit 1, got $rc" >&2 + echo "$out" >&2 + exit 1 +fi + +echo "$out" | grep -q 'debian-installer netboot' +echo "$out" | grep -q 'make-ubuntu-cloud-template.sh' diff --git a/builder/templates/test-make-ubuntu-cloud-template-integration.sh b/builder/templates/test-make-ubuntu-cloud-template-integration.sh new file mode 100644 index 00000000..ba2e0afd --- /dev/null +++ b/builder/templates/test-make-ubuntu-cloud-template-integration.sh @@ -0,0 +1,52 @@ +#!/bin/bash - +# libguestfs virt-builder ubuntu cloud template integration test +# Copyright (C) 2026 Red Hat Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +export LANG=C +set -e + +if [ -z "${SLOW}" ]; then + echo "$0: test skipped because SLOW is not set (downloads ~600M cloud image)" + exit 77 +fi + +for cmd in wget qemu-img virt-customize virt-sysprep virt-filesystems xz sha512sum virt-index-validate; do + if ! command -v "$cmd" >/dev/null 2>&1; then + echo "$0: test skipped because $cmd is not available" + exit 77 + fi +done + +work="$PWD/cloud-template-integration-$$" +mkdir -p "$work" +trap 'rm -rf "$work"' EXIT + +export WORKDIR="$work" +export DISK_GB=6 +"$srcdir/make-ubuntu-cloud-template.sh" 24.04 noble + +test -f "$work/ubuntu-24.04.img" +test -f "$work/ubuntu-24.04.xz" +test -f "$work/ubuntu-24.04.index-fragment" + +$VG virt-index-validate "$work/ubuntu-24.04.index-fragment" + +expand="$(grep '^expand=' "$work/ubuntu-24.04.index-fragment" | cut -d= -f2)" +test -n "$expand" + +$VG virt-ls -a "$work/ubuntu-24.04.img" / +$VG virt-cat -a "$work/ubuntu-24.04.img" /etc/os-release | grep -q 'VERSION_ID="24.04"' diff --git a/builder/templates/test-make-ubuntu-cloud-template.sh b/builder/templates/test-make-ubuntu-cloud-template.sh new file mode 100644 index 00000000..31a0ed98 --- /dev/null +++ b/builder/templates/test-make-ubuntu-cloud-template.sh @@ -0,0 +1,77 @@ +#!/bin/bash - +# libguestfs virt-builder ubuntu cloud template tests +# Copyright (C) 2026 Red Hat Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +export LANG=C +set -e + +script="$srcdir/make-ubuntu-cloud-template.sh" +helper="$srcdir/detect-cloudimg-expand.sh" + +bash -n "$script" +bash -n "$helper" + +# Unsupported version/codename pairs must fail before any download. +if "$script" 26.04 noble >/dev/null 2>&1; then + echo "$0: expected unsupported version to fail" >&2 + exit 1 +fi + +if "$script" 24.04 jammy >/dev/null 2>&1; then + echo "$0: expected mismatched codename to fail" >&2 + exit 1 +fi + +if ARCH=aarch64 "$script" 24.04 noble >/dev/null 2>&1; then + echo "$0: expected unsupported architecture to fail" >&2 + exit 1 +fi + +# Expand detection helper: mock virt-filesystems output for cloudimg-rootfs. +mock_bin="$PWD/mock-bin-$$" +mkdir -p "$mock_bin" +cat > "$mock_bin/virt-filesystems" <<'EOF' +#!/bin/bash - +case "$*" in + *cloudimg-rootfs*) + echo "/dev/sda1 filesystem ext4 cloudimg-rootfs" + exit 0 + ;; +esac +echo "$0: unexpected arguments: $*" >&2 +exit 1 +EOF +chmod +x "$mock_bin/virt-filesystems" +trap 'rm -rf "$mock_bin"' EXIT + +PATH="$mock_bin:$PATH" +. "$helper" +expand="$(detect_cloudimg_expand /dev/null)" +test "$expand" = /dev/sda1 + +# Cloud image URL used by the builder must exist (HEAD only, no download). +url="https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img" +if ! wget -S --spider "$url" 2>&1 | grep -q '200 OK'; then + echo "$0: cloud image URL is not reachable: $url" >&2 + exit 1 +fi + +# Legacy debian-installer netboot used by make-template.ml is gone on noble. +if wget -S --spider "http://archive.ubuntu.com/ubuntu/dists/noble/main/installer-amd64/" 2>&1 | grep -q '200 OK'; then + echo "$0: expected noble installer-amd64 to be unavailable" >&2 + exit 1 +fi