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