Fix USB install reliability: bash, LV resize, deps, idempotency

- autoinstall/user-data: move lvextend/growpart/pvresize BEFORE playbook
  so 130GB of drivers+PPKGs fits during first-boot copy. Use
  tr -d "[:space:]" to avoid breaking outer bash -c single-quote wrap.
- playbook: add executable: /bin/bash to Dell driver deploy (process
  substitution) and Blancco initramfs builder (brace expansion).
- playbook: make "Ensure Samba user for Blancco reports" idempotent via
  pdbedit check so re-runs don't abort the play.
- download-packages.sh: also download dist-upgrade package set. Explicit
  --simulate misses transitive version bumps (e.g. gnupg 17.4 needs
  matching gpgv 17.4) causing offline dpkg "dependency problems" when
  ISO baseline is older than noble-updates.
This commit is contained in:
cproudlock
2026-04-14 12:57:28 -04:00
parent 855af7312b
commit ade2f3b5ff
3 changed files with 136 additions and 35 deletions

View File

@@ -1,10 +1,10 @@
#!/bin/bash
#
# download-packages.sh Download all .deb packages needed for offline PXE server setup
# download-packages.sh - Download all .deb packages needed for offline PXE server setup
#
# Run this on a machine with internet access running Ubuntu 24.04 (Noble).
# It downloads every .deb needed by the Ansible playbook into a local directory,
# which then gets bundled onto the installer USB.
# The PXE server installs Ubuntu 24.04 (Noble), so all packages MUST come from the
# 24.04 archive. If this script is run on a non-24.04 host (e.g. Zorin 17 / 22.04),
# it auto-spawns an Ubuntu 24.04 docker container to do the download.
#
# Usage:
# ./download-packages.sh [output_directory]
@@ -14,6 +14,40 @@
set -euo pipefail
OUT_DIR="${1:-./offline-packages}"
OUT_DIR_ABS="$(cd "$(dirname "$OUT_DIR")" 2>/dev/null && pwd)/$(basename "$OUT_DIR")"
# Detect host Ubuntu codename. Run inside the container if not Noble (24.04).
HOST_CODENAME="$(. /etc/os-release && echo "${UBUNTU_CODENAME:-${VERSION_CODENAME:-}}")"
if [ "${IN_DOCKER:-}" != "1" ] && [ "$HOST_CODENAME" != "noble" ]; then
echo "Host is '$HOST_CODENAME', not 'noble' (Ubuntu 24.04)."
echo "Re-running inside ubuntu:24.04 docker container..."
echo ""
if ! command -v docker >/dev/null; then
echo "ERROR: docker not installed. Install docker or run on a real Ubuntu 24.04 host."
exit 1
fi
SCRIPT_PATH="$(readlink -f "$0")"
REPO_DIR="$(dirname "$SCRIPT_PATH")"
mkdir -p "$OUT_DIR_ABS"
docker run --rm -i \
-v "$REPO_DIR:/repo" \
-v "$OUT_DIR_ABS:/out" \
-e IN_DOCKER=1 \
-w /repo \
ubuntu:24.04 \
bash -c "apt-get update -qq && apt-get install -y --no-install-recommends sudo python3-pip python3-setuptools python3-wheel ca-certificates >/dev/null && /repo/download-packages.sh /out"
echo ""
echo "============================================"
echo "Container build complete. Files in: $OUT_DIR_ABS"
echo "============================================"
exit 0
fi
mkdir -p "$OUT_DIR"
# Packages installed by the Ansible playbook (pxe_server_setup.yml)
@@ -30,10 +64,12 @@ PLAYBOOK_PACKAGES=(
grub-efi-amd64-bin
grub-common
conntrack
busybox-static
zstd
cpio
)
# Packages installed during autoinstall late-commands (NetworkManager, WiFi, etc.)
# These are already in your ubuntu_playbook/*.deb files, but we can refresh them here too.
AUTOINSTALL_PACKAGES=(
network-manager
wpasupplicant
@@ -45,7 +81,7 @@ AUTOINSTALL_PACKAGES=(
ALL_PACKAGES=("${PLAYBOOK_PACKAGES[@]}" "${AUTOINSTALL_PACKAGES[@]}")
echo "============================================"
echo "Offline Package Downloader"
echo "Offline Package Downloader (Ubuntu 24.04 noble)"
echo "============================================"
echo "Output directory: $OUT_DIR"
echo ""
@@ -54,18 +90,29 @@ printf ' - %s\n' "${ALL_PACKAGES[@]}"
echo ""
# Update package cache
echo "[1/3] Updating package cache..."
echo "[1/4] Updating package cache..."
sudo apt-get update -qq
# Simulate install to find all dependencies
echo "[2/3] Resolving dependencies..."
DEPS=$(apt-get install --simulate "${ALL_PACKAGES[@]}" 2>&1 \
echo "[2/4] Resolving dependencies..."
EXPLICIT_DEPS=$(apt-get install --simulate "${ALL_PACKAGES[@]}" 2>&1 \
| grep "^Inst " \
| awk '{print $2}' \
| sort -u)
| awk '{print $2}')
# ALSO pull every package that would upgrade in a dist-upgrade. This is
# critical: the Ubuntu ISO ships a point-in-time baseline, but our explicit
# packages (from noble-updates) may depend on *newer* versions of ISO-baseline
# packages (e.g. gnupg 17.4 needs matching gpgv 17.4). Without this, offline
# install fails with dpkg "dependency problems" because transitive version
# bumps aren't captured by --simulate on the explicit list.
UPGRADE_DEPS=$(apt-get dist-upgrade --simulate 2>&1 \
| grep "^Inst " \
| awk '{print $2}')
DEPS=$(printf '%s\n%s\n' "$EXPLICIT_DEPS" "$UPGRADE_DEPS" | sort -u | grep -v '^$')
DEP_COUNT=$(echo "$DEPS" | wc -l)
echo " Found $DEP_COUNT packages (including dependencies)"
echo " Found $DEP_COUNT packages (explicit + baseline upgrades)"
# Download all packages
echo "[3/4] Downloading .deb packages to $OUT_DIR..."
@@ -79,7 +126,9 @@ echo " $DEB_COUNT packages ($TOTAL_SIZE)"
# Download pip wheels for Flask webapp (offline install)
echo "[4/4] Downloading Python wheels for webapp..."
PIP_DIR="$(dirname "$OUT_DIR")/pip-wheels"
# Place pip-wheels next to the script (or /repo when in docker), not next to OUT_DIR
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PIP_DIR="$SCRIPT_DIR/pip-wheels"
mkdir -p "$PIP_DIR"
pip3 download -d "$PIP_DIR" flask lxml 2>&1 | tail -5