2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-09-30 14:55:16 +00:00
Files
xcat-core/xCAT-genesis-builder/builddeb-genesis-base
T
Daniel Hilst 5ff9b941b5 fix(xcat-core): the Genesis image is published into releases it cannot boot
builddebs.pl publishes every Architecture:all deb into every release, because
every other xcat-core deb is the same file for all of them. The Genesis image is
not: it carries the kernel of the root that built it. All three images therefore
landed in all three suites, and apt serves the newest, which belongs to another
release.

deb_belongs_to_dist reads the codename back from the version and keeps an image
out of any other suite. A deb with no codename in its version is unaffected.

The jammy build also stopped on /usr/share/terminfo/l/linux and v/vt100:
ncurses-base installs terminfo under /lib, and the module asks for the
/usr/share copies, which come from ncurses-term. noble happened to have it.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-12 09:13:26 -03:00

281 lines
9.9 KiB
Bash
Executable File

#!/bin/bash
# Build the xcat-genesis-base .deb for ONE Ubuntu codename.
#
# dracut copies the kernel, the kernel modules and every command out of the root it runs
# in, so this must run inside a root of the target codename. builddebs.pl --genesis starts
# it in that codename's <codename>-<arch>-sbuild chroot, one build per codename.
# --expect-codename is what stops a run on the build host: a single build there gives every
# Ubuntu release the build host's kernel, which is how the EL-built image reached Ubuntu
# management nodes in the first place.
#
# Parallel to xCAT-genesis-base.spec, which does the same for EL.
set -euo pipefail
DIR=$(readlink -f "$(dirname "$0")")
OS_RELEASE=${OS_RELEASE:-/etc/os-release}
expect_codename=""
outdir=""
while [ $# -gt 0 ]; do
case "$1" in
--expect-codename) expect_codename=${2:-}; shift 2 ;;
--expect-codename=*) expect_codename=${1#*=}; shift ;;
--outdir) outdir=${2:-}; shift 2 ;;
--outdir=*) outdir=${1#*=}; shift ;;
-h|--help)
echo "usage: builddeb-genesis-base [--expect-codename <codename>] [--outdir <dir>]"
exit 0 ;;
*) echo "ERROR: unknown argument: $1" >&2; exit 2 ;;
esac
done
BUILDARCH=$(dpkg --print-architecture)
case "$BUILDARCH" in
amd64) TARCH=x86_64 ;;
ppc64el) TARCH=ppc64 ;;
*) echo "ERROR: unsupported architecture: $BUILDARCH" >&2; exit 1 ;;
esac
# The Genesis debs carry the architecture in the package name, so the packages an upgrade has
# to displace carry it too. 2.19 renames the ppc64 debs to ppc64el; dpkg keeps the old package,
# and its copy of the same files, unless the new one replaces it by name.
rewrite_control() {
local control=$1 arch=$2 superseded
case "$arch" in
ppc64el) superseded="xcat-genesis-ppc64, xcat-genesis-base-ppc64" ;;
*) superseded="xcat-genesis-$arch" ;;
esac
sed -i -e "s/xcat-genesis-base-amd64/xcat-genesis-base-$arch/g" \
-e "s/xcat-genesis-scripts-amd64/xcat-genesis-scripts-$arch/g" \
-e "s/xcat-genesis-amd64/$superseded/g" "$control"
}
VERSION=$(cat "$DIR/../Version" 2>/dev/null || echo "2.18.0")
RELEASE=$(cat "$DIR/../Release" 2>/dev/null || echo "snap$(date +%Y%m%d%H%M)")
CODENAME=$(. "$OS_RELEASE" && echo "${VERSION_CODENAME:-}")
if [ -z "$CODENAME" ]; then
echo "ERROR: $OS_RELEASE names no VERSION_CODENAME" >&2
exit 1
fi
# The image is only valid for the release whose kernel it carries. Refuse to build a
# codename's image anywhere but in that codename's root.
if [ -n "$expect_codename" ] && [ "$expect_codename" != "$CODENAME" ]; then
echo "ERROR: this root is $CODENAME, not $expect_codename." >&2
echo " The image would carry the $CODENAME kernel and boot under $expect_codename." >&2
exit 1
fi
echo "Building xcat-genesis-base for $BUILDARCH ($TARCH) on Ubuntu $CODENAME"
export DEBIAN_FRONTEND=noninteractive
REQUIRED_PACKAGES="
dracut linux-image-generic
ipmitool lldpad ethtool iproute2 kexec-tools screen
openssh-server openssh-client rsyslog chrony
nfs-common rpcbind pciutils usbutils parted
dosfstools e2fsprogs lvm2 mdadm net-tools
bc psmisc rsync wget cpio
isc-dhcp-client ifenslave
systemd-sysv hwdata btrfs-progs netcat-openbsd iputils-ping fdisk ncurses-term
dpkg-dev debhelper fakeroot devscripts vim-tiny
"
if [ "$BUILDARCH" = "amd64" ]; then
REQUIRED_PACKAGES="$REQUIRED_PACKAGES dmidecode efibootmgr"
fi
echo "Installing build dependencies..."
apt-get update -qq
# Two commands the image needs changed package between releases: nslookup left dnsutils for
# bind9-dnsutils in 22.04, and hwclock left util-linux for util-linux-extra in 23.04. Ask apt
# which name this release carries rather than branch on the codename.
add_first_available() {
local p
for p in "$@"; do
if apt-cache show "$p" >/dev/null 2>&1; then
REQUIRED_PACKAGES="$REQUIRED_PACKAGES $p"
return 0
fi
done
echo "ERROR: $CODENAME carries none of these packages: $*" >&2
exit 1
}
add_first_available bind9-dnsutils dnsutils
add_first_available util-linux-extra util-linux
apt-get install -y --no-install-recommends $REQUIRED_PACKAGES
# dpkg-architecture comes from dpkg-dev, which the line above installs.
TRIPLET=$(dpkg-architecture -qDEB_HOST_MULTIARCH)
# Set up dracut module
if [ -d /usr/lib/dracut/modules.d ]; then
DRACUT_PARENT=/usr/lib/dracut/modules.d
elif [ -d /usr/share/dracut/modules.d ]; then
DRACUT_PARENT=/usr/share/dracut/modules.d
else
echo "ERROR: cannot find dracut modules directory" >&2
exit 1
fi
DRACUTMODDIR=$DRACUT_PARENT/97xcat
GENESIS_TMPDIR=$(mktemp -d /tmp/xcat-genesis-deb.XXXXXX)
GENESIS_ROOT=$GENESIS_TMPDIR/opt/xcat/share/xcat/netboot/genesis/$TARCH
GENESIS_FS=$GENESIS_ROOT/fs
DRACUT_IMAGE=$GENESIS_TMPDIR/genesis.rfs
cleanup() {
rm -rf "$GENESIS_TMPDIR" "$DRACUTMODDIR"
}
trap cleanup EXIT
rm -rf "$DRACUTMODDIR"
mkdir -p "$DRACUTMODDIR"
cp -a "$DIR/dracut_105/ubuntu/." "$DRACUTMODDIR/"
chmod 0755 "$DRACUTMODDIR/module-setup.sh" "$DRACUTMODDIR/xcatroot" "$DRACUTMODDIR/dhclient-script"
if [ "$BUILDARCH" != "amd64" ]; then
sed -i '/efibootmgr dmidecode/d' "$DRACUTMODDIR/module-setup.sh"
fi
# linux-image-generic pulls exactly one kernel into this root, and this root belongs to
# $CODENAME, so this is the target release's kernel.
KERNELVERSION=$(ls -1 /lib/modules | sort -V | tail -n 1)
if [ -z "$KERNELVERSION" ]; then
echo "ERROR: no kernel modules found in /lib/modules" >&2
exit 1
fi
echo "Using kernel $KERNELVERSION"
mkdir -p "$GENESIS_FS/etc/ssh"
mkdir -p /run/rpcbind
echo "Running dracut..."
dracut --compress gzip -m "xcat base" --no-early-microcode -N -f "$DRACUT_IMAGE" "$KERNELVERSION"
echo "Extracting initramfs..."
(cd "$GENESIS_FS" && zcat "$DRACUT_IMAGE" | cpio -dumi)
for script in \
"$GENESIS_FS/sbin/dhclient-script" \
"$GENESIS_FS/usr/sbin/dhclient-script" \
"$GENESIS_FS/sbin/xcatroot"
do
[ -f "$script" ] && chmod 0755 "$script"
done
for perl_dir in \
/usr/share/perl5 \
"/usr/lib/$TRIPLET/perl5" \
/usr/local/share/perl5 \
"/usr/local/lib/$TRIPLET/perl5"
do
if [ -d "$perl_dir" ]; then
echo "Adding perl library $perl_dir"
mkdir -p "$GENESIS_FS$perl_dir"
cp -a "$perl_dir/." "$GENESIS_FS$perl_dir/"
fi
done
mkdir -p "$GENESIS_FS/lib/udev/rules.d"
if [ -e /usr/lib/udev/rules.d/80-net-name-slot.rules ]; then
cp /usr/lib/udev/rules.d/80-net-name-slot.rules "$GENESIS_FS/lib/udev/rules.d/"
elif [ -e /lib/udev/rules.d/80-net-name-slot.rules ]; then
cp /lib/udev/rules.d/80-net-name-slot.rules "$GENESIS_FS/lib/udev/rules.d/"
elif [ -e "$DIR/80-net-name-slot.rules" ]; then
cp "$DIR/80-net-name-slot.rules" "$GENESIS_FS/lib/udev/rules.d/"
fi
KERNEL_IMAGE=/boot/vmlinuz-$KERNELVERSION
if [ ! -e "$KERNEL_IMAGE" ]; then
for candidate in \
"/boot/vmlinux-$KERNELVERSION" \
"/usr/lib/modules/$KERNELVERSION/vmlinuz" \
"/lib/modules/$KERNELVERSION/vmlinuz"
do
if [ -e "$candidate" ]; then
KERNEL_IMAGE="$candidate"
break
fi
done
fi
if [ ! -e "$KERNEL_IMAGE" ]; then
echo "ERROR: cannot find the image of kernel $KERNELVERSION" >&2
exit 1
fi
echo "Adding kernel $KERNEL_IMAGE"
cp "$KERNEL_IMAGE" "$GENESIS_ROOT/kernel"
# dracut_install reports a missing command and returns, so a hole reaches the .deb with
# nothing in the log but one line. Read the commands back from the module and check them
# against the payload, the way xCAT-genesis-base.spec does for EL.
bash "$DIR/verify-genesis-payload" --commands-from "$DRACUTMODDIR/module-setup.sh" "$GENESIS_FS" \
usr/sbin/dhclient bin/sh sbin/xcatroot sbin/dhclient-script etc/rsyslog.conf
# What the verifier cannot know: that this image belongs to this chroot's kernel. An image
# built against another root's /lib/modules boots and then finds no driver for its NIC.
if [ ! -d "$GENESIS_FS/lib/modules/$KERNELVERSION" ]; then
echo "ERROR: the image carries no /lib/modules/$KERNELVERSION" >&2
ls -1 "$GENESIS_FS/lib/modules" 2>/dev/null >&2 || true
exit 1
fi
if [ -z "$(find "$GENESIS_FS/lib/modules/$KERNELVERSION" -name '*.ko*' -print -quit)" ]; then
echo "ERROR: /lib/modules/$KERNELVERSION in the image holds no kernel module" >&2
exit 1
fi
for stray in "$GENESIS_FS"/lib/modules/*; do
[ -d "$stray" ] || continue
if [ "$(basename "$stray")" != "$KERNELVERSION" ]; then
echo "ERROR: the image carries $(basename "$stray"), not the $KERNELVERSION of this root" >&2
exit 1
fi
done
# The 97xcat hooks are what makes the image xCAT's. dracut drops a module whose check()
# fails without a word, and the image then boots to a plain dracut shell.
if [ -z "$(find "$GENESIS_FS" -path '*/hooks/cmdline/*xcat-cmdline.sh' -print -quit)" ]; then
echo "ERROR: the image carries no 97xcat cmdline hook" >&2
exit 1
fi
find "$GENESIS_TMPDIR" -type c -delete
# Stage for dpkg-buildpackage
rm -rf "$DIR/opt"
cp -a "$GENESIS_TMPDIR/opt" "$DIR/"
# Adjust control file for target arch
rewrite_control "$DIR/debian/control" "$BUILDARCH"
# debian/dirs names the image directory, which is the rpm architecture.
echo "/opt/xcat/share/xcat/netboot/genesis/$TARCH/" > "$DIR/debian/dirs"
# dch reads debian/control from the current directory, not from the file it writes.
cd "$DIR"
PKG_VERSION="${VERSION}-${RELEASE}~${CODENAME}"
rm -f "$DIR/debian/changelog"
dch --create --package "xcat-genesis-base-$BUILDARCH" \
--newversion "$PKG_VERSION" --distribution "$CODENAME" \
--controlmaint -c "$DIR/debian/changelog" \
"Native Ubuntu build on $CODENAME $BUILDARCH"
echo "Building .deb package..."
dpkg-buildpackage -rfakeroot -uc -us -b
if [ -n "$outdir" ]; then
mkdir -p "$outdir"
mv "$DIR/../"xcat-genesis-base-*_*.deb "$outdir/"
echo "Build complete. .deb files in $outdir:"
ls -la "$outdir"
else
echo "Build complete. .deb files:"
ls -la "$DIR/../"xcat-genesis-base*.deb 2>/dev/null || echo "Check parent directory for .deb files"
fi