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 eb30d2e92a fix(xcat-core): the Genesis build-root package list and payload check can only be read by evaluating shell
builddeb-genesis-base built its package list inline, between apt-get
update and apt-get install. A test could reach the list only by cutting
the REQUIRED_PACKAGES assignment out of the script and evaluating it.
It could not reach the choice between renamed packages (bind9-dnsutils
or dnsutils, util-linux-extra or util-linux) at all. The payload check
in verify-genesis-payload was bash, so a test could only run the script
and read its stderr.

XCAT::GenesisBuildRoot::required_packages() now returns the list for a
dpkg architecture. A code ref says which packages the release carries;
the default asks apt-cache. builddeb-genesis-base calls it at the same
point in the build and installs the same packages.

XCAT::GenesisPayload holds the mandatory-command list and the payload
check. verify-genesis-payload runs its main() and keeps the same
arguments, exit codes and messages. buildrpms.pl stages the module
beside the script. Both modules use core Perl only, because the build
root has perl-base and nothing more.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-24 17:28:04 -03:00

260 lines
9.4 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.
#
# 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
echo "Installing build dependencies..."
apt-get update -qq
# XCAT::GenesisBuildRoot holds the package list, so the unit tests can call it.
REQUIRED_PACKAGES=$(perl -I"$DIR/lib" -MXCAT::GenesisBuildRoot=required_packages \
-e 'print "$_\n" for required_packages(@ARGV)' "$BUILDARCH" "$CODENAME")
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)
# ncurses-base put its terminfo entries under /lib/terminfo before 24.04, and both dracut's own
# terminfo module and the 97xcat module ask for /usr/share/terminfo. On jammy the build stopped
# on /usr/share/terminfo/l/linux. Give this build root the path they ask for; the chroot is
# thrown away when the build ends.
if [ -d /lib/terminfo ]; then
mkdir -p /usr/share/terminfo
cp -an /lib/terminfo/. /usr/share/terminfo/ 2>/dev/null || true
fi
# 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