Every server has an imaging NIC (static, the only one that serves DHCP/TFTP/HTTP boot/SMB) and a GE corporate NIC (DHCP client, SSH and the webapp on 9009). The playbook guessed the PXE NIC and the installer put 172.16.9.1/24 on every en* NIC, so a two-NIC box could answer on the GE network. - New per-site vars pxe_nic_mac / corp_nic_mac (required, from playbook/site-vars.yml or -e; template site-vars.example.yml), stable names pxe_nic_name / corp_nic_name (default pxe0 / corp0, overridable), pxe_server_ip, pxe_subnet, DHCP range. pxe_imaging_mac / pxe_ge_mac are derived from them. The play stops before touching anything if a MAC is unset, malformed, duplicated or not on the box (lists the box's NICs). - Heuristic NIC detection and the single-NIC netplan task replaced by a two-NIC netplan template (match macaddress + set-name), installed by pxe-netplan-apply.sh: validate in a scratch root, back up, generate, rename, apply, restore the previous config on any failure. cloud-init network config disabled so it cannot rewrite it. - dnsmasq: /etc/dnsmasq.d/pxe-nic-only.conf from the vars (interface=, except-interface=, no-dhcp-interface=); dnsmasq.conf IP/range from vars. - UFW per interface: imaging NIC 22, 67/udp, 69/udp, 80, 4433, 445, 139, 137/udp, 138/udp, 9009; GE NIC 22 and 9009 only. Old any-interface rules and the stale 9011 rule removed after the new ones are in. - sysctl drop-in: IPv4/IPv6 forwarding off; ip_nonlocal_bind so Apache can bind the imaging IP before the address is up. - Samba [global]: interfaces = 127.0.0.0/8 <imaging NIC>, bind interfaces only. Apache 80 and 4433 on the imaging IP only; 9009 stays on all (TODO: the webapp has no auth). - autoinstall: DHCP only on en*, no static 172.16.9.1; apt geoip off and offline-install fallback now that the corp NIC may have a lease. - Blancco UEFI/Secure Boot: blancco_kver (7.0.0-34-generic) drives the kernel, initramfs and modules builds instead of the running kernel; outputs vmlinuz-ubuntu-70, kexec-initrd-70.img, kmod-<kver>.tar.gz as the menu and blancco-init.sh expect; creates: guards keyed on the full kver. Ubuntu's shimx64.efi.signed published as blancco/shimx64.efi. download-packages.sh adds shim-signed, linux-generic-hwe-24.04 and the pinned linux-image/modules/modules-extra for BLANCCO_KVER. Rendered with the live MACs and names, netplan generate output is identical to the live config; pxe-nic-only.conf and the Samba binding match live directive for directive.
164 lines
5.5 KiB
Bash
Executable File
164 lines
5.5 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# download-packages.sh - Download all .deb packages needed for offline PXE server setup
|
|
#
|
|
# 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]
|
|
#
|
|
# Default output: ./offline-packages/
|
|
|
|
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="$(cd "$(dirname "$SCRIPT_PATH")"/.. && pwd)"
|
|
mkdir -p "$OUT_DIR_ABS"
|
|
|
|
docker run --rm -i \
|
|
-v "$REPO_DIR:/repo" \
|
|
-v "$OUT_DIR_ABS:/out" \
|
|
-e IN_DOCKER=1 \
|
|
-e BLANCCO_KVER="${BLANCCO_KVER:-}" \
|
|
-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/scripts/download-packages.sh /out"
|
|
|
|
echo ""
|
|
echo "============================================"
|
|
echo "Container build complete. Files in: $OUT_DIR_ABS"
|
|
echo "============================================"
|
|
exit 0
|
|
fi
|
|
|
|
mkdir -p "$OUT_DIR"
|
|
|
|
# Kernel the Blancco UEFI path boots (playbook var blancco_kver; keep the two
|
|
# in step). The playbook builds vmlinuz-ubuntu-70, kexec-initrd-70.img and
|
|
# kmod-<kver>.tar.gz from this kernel's /boot and /lib/modules, and the
|
|
# Canonical-signed image is what Ubuntu's shim starts with Secure Boot on.
|
|
# The versioned packages pin it; the HWE metapackage keeps the box on the
|
|
# HWE line. Override: BLANCCO_KVER=7.0.0-40-generic ./download-packages.sh
|
|
BLANCCO_KVER="${BLANCCO_KVER:-7.0.0-34-generic}"
|
|
|
|
# Packages installed by the Ansible playbook (pxe_server_setup.yml)
|
|
PLAYBOOK_PACKAGES=(
|
|
ansible
|
|
dnsmasq
|
|
apache2
|
|
samba
|
|
unzip
|
|
ufw
|
|
cron
|
|
wimtools
|
|
p7zip-full
|
|
grub-efi-amd64-bin
|
|
grub-common
|
|
conntrack
|
|
busybox-static
|
|
zstd
|
|
cpio
|
|
# Updates pages in the webapp (iPXE signature check, Dell pack zips, downloads)
|
|
sbsigntool
|
|
zip
|
|
curl
|
|
# Blancco with Secure Boot on: shimx64.efi.signed + the HWE kernel
|
|
shim-signed
|
|
linux-generic-hwe-24.04
|
|
"linux-image-${BLANCCO_KVER}"
|
|
"linux-modules-${BLANCCO_KVER}"
|
|
"linux-modules-extra-${BLANCCO_KVER}"
|
|
)
|
|
|
|
# Packages installed during autoinstall late-commands (NetworkManager, WiFi, etc.)
|
|
AUTOINSTALL_PACKAGES=(
|
|
network-manager
|
|
wpasupplicant
|
|
wireless-tools
|
|
linux-firmware
|
|
firmware-sof-signed
|
|
)
|
|
|
|
ALL_PACKAGES=("${PLAYBOOK_PACKAGES[@]}" "${AUTOINSTALL_PACKAGES[@]}")
|
|
|
|
echo "============================================"
|
|
echo "Offline Package Downloader (Ubuntu 24.04 noble)"
|
|
echo "============================================"
|
|
echo "Output directory: $OUT_DIR"
|
|
echo ""
|
|
echo "Packages to resolve:"
|
|
printf ' - %s\n' "${ALL_PACKAGES[@]}"
|
|
echo ""
|
|
|
|
# Update package cache
|
|
echo "[1/4] Updating package cache..."
|
|
sudo apt-get update -qq
|
|
|
|
# Simulate install to find all dependencies
|
|
echo "[2/4] Resolving dependencies..."
|
|
EXPLICIT_DEPS=$(apt-get install --simulate "${ALL_PACKAGES[@]}" 2>&1 \
|
|
| grep "^Inst " \
|
|
| 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 (explicit + baseline upgrades)"
|
|
|
|
# Download all packages
|
|
echo "[3/4] Downloading .deb packages to $OUT_DIR..."
|
|
cd "$OUT_DIR"
|
|
apt-get download $DEPS 2>&1 | tail -5
|
|
|
|
DEB_COUNT=$(ls -1 *.deb 2>/dev/null | wc -l)
|
|
TOTAL_SIZE=$(du -sh . | cut -f1)
|
|
|
|
echo " $DEB_COUNT packages ($TOTAL_SIZE)"
|
|
|
|
# Download pip wheels for Flask webapp (offline install)
|
|
echo "[4/4] Downloading Python wheels for webapp..."
|
|
# Place pip-wheels next to the script (or /repo when in docker), not next to OUT_DIR
|
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")"/.. && pwd)"
|
|
PIP_DIR="$REPO_ROOT/pip-wheels"
|
|
mkdir -p "$PIP_DIR"
|
|
pip3 download -d "$PIP_DIR" flask lxml 2>&1 | tail -5
|
|
|
|
WHL_COUNT=$(ls -1 "$PIP_DIR"/*.whl "$PIP_DIR"/*.tar.gz 2>/dev/null | wc -l)
|
|
echo " $WHL_COUNT Python packages downloaded to pip-wheels/"
|
|
|
|
echo ""
|
|
echo "============================================"
|
|
echo "Download complete!"
|
|
echo "============================================"
|
|
echo " .deb packages: $DEB_COUNT ($TOTAL_SIZE) in $OUT_DIR/"
|
|
echo " Python wheels: $WHL_COUNT in $PIP_DIR/"
|
|
echo ""
|