mirror of
https://github.com/xcat2/xcat-core.git
synced 2026-09-30 14:55:16 +00:00
eb30d2e92a
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>
260 lines
9.4 KiB
Bash
Executable File
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
|