migrate ISO build from Alpine to Debian 12 (Bookworm)

Replace the entire live CD build pipeline:
- Alpine SDK + mkimage + genapkovl → Debian live-build (lb config/build)
- OpenRC init scripts → systemd service units
- dropbear → openssh-server (native to Debian live)
- udhcpc → dhclient for DHCP
- apk → apt-get in setup-builder.sh and build-nvidia-module.sh
- Add auto/config (lb config options) and auto/build wrapper
- Add config/package-lists/bee.list.chroot replacing Alpine apks
- Add config/hooks/normal/9000-bee-setup.hook.chroot to enable services
- Add bee-nvidia-load and bee-sshsetup helper scripts
- Keep NVIDIA pre-compile pipeline (Option B): compile on builder VM against
  pinned Debian kernel headers (DEBIAN_KERNEL_ABI), inject .ko into includes.chroot
- Fixes: native glibc (no gcompat shims), proper udev, writable /lib/modules,
  no Alpine modloop read-only constraint, no stale apk cache issues

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Mikhail Chusavitin
2026-03-08 18:01:38 +03:00
parent d952e10dbb
commit 345a93512a
26 changed files with 362 additions and 582 deletions
+2 -1
View File
@@ -1,4 +1,5 @@
ALPINE_VERSION=3.21 DEBIAN_VERSION=12
DEBIAN_KERNEL_ABI=6.1.0-28
NVIDIA_DRIVER_VERSION=590.48.01 NVIDIA_DRIVER_VERSION=590.48.01
GO_VERSION=1.23.6 GO_VERSION=1.23.6
AUDIT_VERSION=0.1.0 AUDIT_VERSION=0.1.0
+5
View File
@@ -0,0 +1,5 @@
#!/bin/sh
# auto/build — live-build build wrapper for bee ISO
set -e
lb build noauto "${@}" 2>&1
+30
View File
@@ -0,0 +1,30 @@
#!/bin/sh
# auto/config — live-build configuration for bee ISO
# Runs automatically when lb config is called.
# See: man lb_config
set -e
. "$(dirname "$0")/../VERSIONS"
lb config noauto \
--distribution bookworm \
--architectures amd64 \
--binary-images iso-hybrid \
--bootloaders "grub-efi,syslinux" \
--debian-installer none \
--archive-areas "main contrib non-free non-free-firmware" \
--mirror-bootstrap "https://deb.debian.org/debian" \
--mirror-chroot "https://deb.debian.org/debian" \
--mirror-binary "https://deb.debian.org/debian" \
--security true \
--linux-flavours "amd64" \
--linux-packages "linux-image-${DEBIAN_KERNEL_ABI}" \
--memtest none \
--iso-volume "BEE-DEBUG" \
--iso-application "Bee Hardware Audit" \
--hostname "bee-debug" \
--username "root" \
--bootappend-live "boot=live components quiet splash" \
--apt-recommends false \
"${@}"
+27 -41
View File
@@ -1,5 +1,5 @@
#!/bin/sh #!/bin/sh
# build-nvidia-module.sh — install NVIDIA proprietary driver into ISO overlay # build-nvidia-module.sh — compile NVIDIA proprietary driver modules for Debian 12
# #
# Downloads the official NVIDIA .run installer, extracts kernel modules and # Downloads the official NVIDIA .run installer, extracts kernel modules and
# userspace tools (nvidia-smi, libnvidia-ml). Everything is proprietary NVIDIA. # userspace tools (nvidia-smi, libnvidia-ml). Everything is proprietary NVIDIA.
@@ -16,33 +16,25 @@ set -e
NVIDIA_VERSION="$1" NVIDIA_VERSION="$1"
DIST_DIR="$2" DIST_DIR="$2"
ALPINE_VERSION="$3" DEBIAN_KERNEL_ABI="$3"
[ -n "$NVIDIA_VERSION" ] || { echo "usage: $0 <nvidia-version> <dist-dir> <alpine-version>"; exit 1; } [ -n "$NVIDIA_VERSION" ] || { echo "usage: $0 <nvidia-version> <dist-dir> <debian-kernel-abi>"; exit 1; }
[ -n "$DIST_DIR" ] || { echo "usage: $0 <nvidia-version> <dist-dir> <alpine-version>"; exit 1; } [ -n "$DIST_DIR" ] || { echo "usage: $0 <nvidia-version> <dist-dir> <debian-kernel-abi>"; exit 1; }
[ -n "$ALPINE_VERSION" ] || { echo "usage: $0 <nvidia-version> <dist-dir> <alpine-version>"; exit 1; } [ -n "$DEBIAN_KERNEL_ABI" ] || { echo "usage: $0 <nvidia-version> <dist-dir> <debian-kernel-abi>"; exit 1; }
# Install linux-lts-dev (no version pin — always use whatever is current in Alpine 3.21 main). KVER="${DEBIAN_KERNEL_ABI}-amd64"
# This ensures modules are compiled for the same kernel that mkimage will install in the ISO.
# Both use dl-cdn.alpinelinux.org, so they see the same package state at build time.
echo "=== installing linux-lts-dev (latest from dl-cdn) ==="
apk add --quiet --update \
--repository "https://dl-cdn.alpinelinux.org/alpine/v${ALPINE_VERSION}/main" \
linux-lts-dev
# Detect kernel version from installed headers (pick highest version if multiple).
detect_kver() {
ls /usr/src/ 2>/dev/null \
| grep '^linux-headers-' \
| sed 's/linux-headers-//' \
| sort -V \
| tail -1
}
KVER="$(detect_kver)"
KDIR="/usr/src/linux-headers-${KVER}" KDIR="/usr/src/linux-headers-${KVER}"
echo "=== NVIDIA ${NVIDIA_VERSION} (proprietary) for kernel ${KVER} ===" echo "=== NVIDIA ${NVIDIA_VERSION} (proprietary) for kernel ${KVER} ==="
if [ ! -d "$KDIR" ]; then
echo "=== installing linux-headers-${KVER} ==="
DEBIAN_FRONTEND=noninteractive apt-get install -y \
"linux-headers-${KVER}" \
gcc make perl
fi
echo "kernel headers: $KDIR"
CACHE_DIR="${DIST_DIR}/nvidia-${NVIDIA_VERSION}-${KVER}" CACHE_DIR="${DIST_DIR}/nvidia-${NVIDIA_VERSION}-${KVER}"
if [ -d "$CACHE_DIR/modules" ] && [ -f "$CACHE_DIR/bin/nvidia-smi" ]; then if [ -d "$CACHE_DIR/modules" ] && [ -f "$CACHE_DIR/bin/nvidia-smi" ]; then
echo "=== NVIDIA cached, skipping build ===" echo "=== NVIDIA cached, skipping build ==="
@@ -51,12 +43,7 @@ if [ -d "$CACHE_DIR/modules" ] && [ -f "$CACHE_DIR/bin/nvidia-smi" ]; then
exit 0 exit 0
fi fi
# Install build dependencies (linux-lts-dev already at correct version from above) # Download official NVIDIA .run installer with sha256 verification
apk add --quiet \
--repository "https://dl-cdn.alpinelinux.org/alpine/v${ALPINE_VERSION}/main" \
gcc make perl linux-lts-dev wget
# Download official NVIDIA .run installer (proprietary) with sha256 verification
BASE_URL="https://download.nvidia.com/XFree86/Linux-x86_64/${NVIDIA_VERSION}" BASE_URL="https://download.nvidia.com/XFree86/Linux-x86_64/${NVIDIA_VERSION}"
RUN_FILE="/var/tmp/NVIDIA-Linux-x86_64-${NVIDIA_VERSION}.run" RUN_FILE="/var/tmp/NVIDIA-Linux-x86_64-${NVIDIA_VERSION}.run"
SHA_FILE="/var/tmp/NVIDIA-Linux-x86_64-${NVIDIA_VERSION}.run.sha256sum" SHA_FILE="/var/tmp/NVIDIA-Linux-x86_64-${NVIDIA_VERSION}.run.sha256sum"
@@ -96,7 +83,7 @@ done
[ -n "$KERNEL_SRC" ] || { echo "ERROR: kernel source dir not found in:"; ls "$EXTRACT_DIR/"; exit 1; } [ -n "$KERNEL_SRC" ] || { echo "ERROR: kernel source dir not found in:"; ls "$EXTRACT_DIR/"; exit 1; }
echo "kernel source: $KERNEL_SRC" echo "kernel source: $KERNEL_SRC"
# Build kernel modules from extracted source # Build kernel modules
echo "=== building kernel modules ($(nproc) cores) ===" echo "=== building kernel modules ($(nproc) cores) ==="
cd "$KERNEL_SRC" cd "$KERNEL_SRC"
make -j$(nproc) KERNEL_UNAME="$KVER" SYSSRC="$KDIR" modules 2>&1 | tail -5 make -j$(nproc) KERNEL_UNAME="$KVER" SYSSRC="$KDIR" modules 2>&1 | tail -5
@@ -112,32 +99,31 @@ done
cp "$EXTRACT_DIR/nvidia-smi" "$CACHE_DIR/bin/" cp "$EXTRACT_DIR/nvidia-smi" "$CACHE_DIR/bin/"
cp "$EXTRACT_DIR/nvidia-bug-report.sh" "$CACHE_DIR/bin/" 2>/dev/null || true cp "$EXTRACT_DIR/nvidia-bug-report.sh" "$CACHE_DIR/bin/" 2>/dev/null || true
# Copy userspace libraries — use find to handle any versioning scheme (libnvidia-ml.so.X.Y.Z or .so.1) # Copy ALL userspace library files
for lib in libnvidia-ml libcuda; do for lib in libnvidia-ml libcuda; do
found=$(find "$EXTRACT_DIR" -maxdepth 1 -name "${lib}.so.*" | head -1) count=0
if [ -z "$found" ]; then for f in $(find "$EXTRACT_DIR" -maxdepth 1 -name "${lib}.so.*" 2>/dev/null); do
cp "$f" "$CACHE_DIR/lib/" && count=$((count+1))
done
if [ "$count" -eq 0 ]; then
echo "ERROR: ${lib}.so.* not found in $EXTRACT_DIR" echo "ERROR: ${lib}.so.* not found in $EXTRACT_DIR"
ls "$EXTRACT_DIR/"*.so* 2>/dev/null | head -20 || true ls "$EXTRACT_DIR/"*.so* 2>/dev/null | head -20 || true
exit 1 exit 1
fi fi
cp "$found" "$CACHE_DIR/lib/"
done done
# Verify .ko files were actually built # Verify .ko files were built
ko_count=$(ls "$CACHE_DIR/modules/"*.ko 2>/dev/null | wc -l) ko_count=$(ls "$CACHE_DIR/modules/"*.ko 2>/dev/null | wc -l)
[ "$ko_count" -gt 0 ] || { echo "ERROR: no .ko files built in $CACHE_DIR/modules/"; exit 1; } [ "$ko_count" -gt 0 ] || { echo "ERROR: no .ko files built in $CACHE_DIR/modules/"; exit 1; }
# Create soname symlinks required by nvidia-smi on Alpine (musl/glibc via gcompat + libc6-compat) # Create soname symlinks: use [0-9][0-9]* to avoid circular symlink (.so.1 has single digit)
for lib in libnvidia-ml libcuda; do for lib in libnvidia-ml libcuda; do
versioned=$(ls "$CACHE_DIR/lib/${lib}.so."* 2>/dev/null | grep -v '\.so\.1$' | head -1) versioned=$(ls "$CACHE_DIR/lib/${lib}.so."[0-9][0-9]* 2>/dev/null | head -1)
[ -n "$versioned" ] || versioned=$(ls "$CACHE_DIR/lib/${lib}.so."* 2>/dev/null | head -1)
[ -n "$versioned" ] || continue [ -n "$versioned" ] || continue
base=$(basename "$versioned") base=$(basename "$versioned")
# Only create .so.1 if versioned file is not already named .so.1
if [ "$base" != "${lib}.so.1" ]; then
ln -sf "$base" "$CACHE_DIR/lib/${lib}.so.1" ln -sf "$base" "$CACHE_DIR/lib/${lib}.so.1"
fi
ln -sf "${lib}.so.1" "$CACHE_DIR/lib/${lib}.so" 2>/dev/null || true ln -sf "${lib}.so.1" "$CACHE_DIR/lib/${lib}.so" 2>/dev/null || true
echo "${lib}: .so.1 -> $base"
done done
echo "=== NVIDIA build complete ===" echo "=== NVIDIA build complete ==="
+52 -71
View File
@@ -1,9 +1,9 @@
#!/bin/sh #!/bin/sh
# build.sh — build bee ISO # build.sh — build bee ISO (Debian 12 / live-build)
# #
# Single build script. Produces a bootable live ISO with SSH access, TUI, NVIDIA drivers. # Single build script. Produces a bootable live ISO with SSH access, TUI, NVIDIA drivers.
# #
# Run on Alpine builder VM as root after setup-builder.sh. # Run on Debian 12 builder VM as root after setup-builder.sh.
# Usage: # Usage:
# sh iso/builder/build.sh [--authorized-keys /path/to/authorized_keys] # sh iso/builder/build.sh [--authorized-keys /path/to/authorized_keys]
@@ -27,15 +27,11 @@ done
. "${BUILDER_DIR}/VERSIONS" . "${BUILDER_DIR}/VERSIONS"
export PATH="$PATH:/usr/local/go/bin" export PATH="$PATH:/usr/local/go/bin"
# NOTE: lz4 compression for modloop is disabled — Alpine initramfs may not support lz4 squashfs.
# Default xz compression is used until lz4 support is confirmed.
echo "=== bee ISO build ===" echo "=== bee ISO build ==="
echo "Alpine: ${ALPINE_VERSION}, Go: ${GO_VERSION}" echo "Debian: ${DEBIAN_VERSION}, Kernel ABI: ${DEBIAN_KERNEL_ABI}, Go: ${GO_VERSION}"
echo "" echo ""
# --- compile audit binary (static, Linux amd64) --- # --- compile audit binary (static, Linux amd64) ---
# Skip rebuild if binary is newer than all Go source files.
AUDIT_BIN="${DIST_DIR}/bee-audit-linux-amd64" AUDIT_BIN="${DIST_DIR}/bee-audit-linux-amd64"
NEED_BUILD=1 NEED_BUILD=1
if [ -f "$AUDIT_BIN" ]; then if [ -f "$AUDIT_BIN" ]; then
@@ -58,8 +54,6 @@ else
fi fi
# --- inject authorized_keys for SSH access --- # --- inject authorized_keys for SSH access ---
# Uses the same Ed25519 keys as release signing (from git.mchus.pro/mchus/keys).
# SSH public keys are stored alongside signing keys as ~/.keys/<name>.key.pub
AUTHORIZED_KEYS_FILE="${OVERLAY_DIR}/root/.ssh/authorized_keys" AUTHORIZED_KEYS_FILE="${OVERLAY_DIR}/root/.ssh/authorized_keys"
mkdir -p "${OVERLAY_DIR}/root/.ssh" mkdir -p "${OVERLAY_DIR}/root/.ssh"
@@ -68,7 +62,6 @@ if [ -n "$AUTH_KEYS" ]; then
chmod 600 "$AUTHORIZED_KEYS_FILE" chmod 600 "$AUTHORIZED_KEYS_FILE"
echo "SSH authorized_keys: installed from $AUTH_KEYS" echo "SSH authorized_keys: installed from $AUTH_KEYS"
else else
# auto-collect all developer SSH public keys from ~/.keys/*.key.pub
> "$AUTHORIZED_KEYS_FILE" > "$AUTHORIZED_KEYS_FILE"
FOUND=0 FOUND=0
for ssh_pub in "$HOME"/.keys/*.key.pub; do for ssh_pub in "$HOME"/.keys/*.key.pub; do
@@ -82,15 +75,15 @@ else
echo "SSH authorized_keys: $FOUND key(s) from ~/.keys/*.key.pub" echo "SSH authorized_keys: $FOUND key(s) from ~/.keys/*.key.pub"
else else
echo "WARNING: no SSH public keys found — falling back to password auth" echo "WARNING: no SSH public keys found — falling back to password auth"
echo " SSH login: bee / eeb (user created by bee-sshsetup at boot)" echo " SSH login: bee / eeb"
echo " (generate a key with: sh keys/scripts/keygen.sh <your-name>)"
USE_PASSWORD_FALLBACK=1 USE_PASSWORD_FALLBACK=1
fi fi
fi fi
# --- password fallback: write marker file read by init script ---
if [ "${USE_PASSWORD_FALLBACK:-0}" = "1" ]; then if [ "${USE_PASSWORD_FALLBACK:-0}" = "1" ]; then
touch "${OVERLAY_DIR}/etc/bee-ssh-password-fallback" touch "${OVERLAY_DIR}/etc/bee-ssh-password-fallback"
else
rm -f "${OVERLAY_DIR}/etc/bee-ssh-password-fallback"
fi fi
# --- copy audit binary into overlay --- # --- copy audit binary into overlay ---
@@ -113,20 +106,15 @@ for tool in storcli64 sas2ircu sas3ircu mstflint; do
fi fi
done done
# --- build NVIDIA kernel modules and inject into overlay --- # --- build NVIDIA kernel modules ---
echo "" echo ""
echo "=== building NVIDIA ${NVIDIA_DRIVER_VERSION} modules ===" echo "=== building NVIDIA ${NVIDIA_DRIVER_VERSION} modules ==="
sh "${BUILDER_DIR}/build-nvidia-module.sh" "${NVIDIA_DRIVER_VERSION}" "${DIST_DIR}" "${ALPINE_VERSION}" sh "${BUILDER_DIR}/build-nvidia-module.sh" "${NVIDIA_DRIVER_VERSION}" "${DIST_DIR}" "${DEBIAN_KERNEL_ABI}"
# Detect kernel version from installed headers (set by build-nvidia-module.sh above)
KVER=$(ls /usr/src/ 2>/dev/null | grep '^linux-headers-' | sed 's/linux-headers-//' | sort -V | tail -1)
[ -n "$KVER" ] || { echo "ERROR: linux-lts-dev not installed — no headers in /usr/src/"; exit 1; }
echo "=== kernel version: ${KVER} ==="
KVER="${DEBIAN_KERNEL_ABI}-amd64"
NVIDIA_CACHE="${DIST_DIR}/nvidia-${NVIDIA_DRIVER_VERSION}-${KVER}" NVIDIA_CACHE="${DIST_DIR}/nvidia-${NVIDIA_DRIVER_VERSION}-${KVER}"
# Inject .ko files into overlay at /usr/local/lib/nvidia/ (not /lib/modules/ — modloop squashfs # Inject .ko files into overlay at /usr/local/lib/nvidia/
# mounts over that path at boot and makes it read-only, so overlay content there is inaccessible)
OVERLAY_KMOD_DIR="${OVERLAY_DIR}/usr/local/lib/nvidia" OVERLAY_KMOD_DIR="${OVERLAY_DIR}/usr/local/lib/nvidia"
mkdir -p "${OVERLAY_KMOD_DIR}" mkdir -p "${OVERLAY_KMOD_DIR}"
cp "${NVIDIA_CACHE}/modules/"*.ko "${OVERLAY_KMOD_DIR}/" cp "${NVIDIA_CACHE}/modules/"*.ko "${OVERLAY_KMOD_DIR}/"
@@ -139,7 +127,6 @@ cp "${NVIDIA_CACHE}/bin/nvidia-bug-report.sh" "${OVERLAY_DIR}/usr/local/bin/" 2>
chmod +x "${OVERLAY_DIR}/usr/local/bin/nvidia-bug-report.sh" 2>/dev/null || true chmod +x "${OVERLAY_DIR}/usr/local/bin/nvidia-bug-report.sh" 2>/dev/null || true
cp "${NVIDIA_CACHE}/lib/"* "${OVERLAY_DIR}/usr/lib/" 2>/dev/null || true cp "${NVIDIA_CACHE}/lib/"* "${OVERLAY_DIR}/usr/lib/" 2>/dev/null || true
# --- embed build metadata --- # --- embed build metadata ---
mkdir -p "${OVERLAY_DIR}/etc" mkdir -p "${OVERLAY_DIR}/etc"
BUILD_DATE="$(date +%Y-%m-%d)" BUILD_DATE="$(date +%Y-%m-%d)"
@@ -149,60 +136,54 @@ BEE_ISO_VERSION=${AUDIT_VERSION}
BEE_AUDIT_VERSION=${AUDIT_VERSION} BEE_AUDIT_VERSION=${AUDIT_VERSION}
BUILD_DATE=${BUILD_DATE} BUILD_DATE=${BUILD_DATE}
GIT_COMMIT=${GIT_COMMIT} GIT_COMMIT=${GIT_COMMIT}
ALPINE_VERSION=${ALPINE_VERSION} DEBIAN_VERSION=${DEBIAN_VERSION}
DEBIAN_KERNEL_ABI=${DEBIAN_KERNEL_ABI}
NVIDIA_DRIVER_VERSION=${NVIDIA_DRIVER_VERSION} NVIDIA_DRIVER_VERSION=${NVIDIA_DRIVER_VERSION}
EOF EOF
# --- export build info for genapkovl to inject into motd --- # Patch motd with build info
BUILD_DATE=$(date +%Y-%m-%d) BEE_BUILD_INFO="${BUILD_DATE} git:${GIT_COMMIT} debian:${DEBIAN_VERSION} nvidia:${NVIDIA_DRIVER_VERSION}"
GIT_COMMIT=$(git -C "${REPO_ROOT}" rev-parse --short HEAD 2>/dev/null || echo "unknown") if [ -f "${OVERLAY_DIR}/etc/motd" ]; then
export BEE_BUILD_INFO="${BUILD_DATE} git:${GIT_COMMIT} alpine:${ALPINE_VERSION} nvidia:${NVIDIA_DRIVER_VERSION}" sed "s/%%BUILD_INFO%%/${BEE_BUILD_INFO}/" "${OVERLAY_DIR}/etc/motd" \
> "${OVERLAY_DIR}/etc/motd.patched"
# --- build ISO using mkimage --- mv "${OVERLAY_DIR}/etc/motd.patched" "${OVERLAY_DIR}/etc/motd"
mkdir -p "${DIST_DIR}"
echo ""
echo "=== building ISO ==="
# Install our mkimage profile where mkimage.sh can find it.
# ~/.mkimage is the user plugin directory loaded by mkimage.sh.
# Clear ~/.mkimage to avoid stale profiles from previous builds being picked up
rm -rf "${HOME}/.mkimage"
mkdir -p "${HOME}/.mkimage"
cp "${BUILDER_DIR}/mkimg.bee.sh" "${HOME}/.mkimage/"
cp "${BUILDER_DIR}/genapkovl-bee.sh" "${HOME}/.mkimage/"
# Export overlay dir so the profile script can find it regardless of SRCDIR.
export BEE_OVERLAY_DIR="${OVERLAY_DIR}"
# Clean workdir: always nuke apks_* (stale packages from old mirror/version cause "unable to select" errors).
# Keep kernel_*, syslinux_*, grub_* — these are large but stable; they only change when KERNEL_PKG_VERSION changes.
if [ -d /var/tmp/bee-iso-work ]; then
find /var/tmp/bee-iso-work -maxdepth 1 -mindepth 1 \
-not -name 'kernel_*' \
-not -name 'syslinux_*' -not -name 'grub_*' \
-exec rm -rf {} + 2>/dev/null || true
fi fi
# Run from /var/tmp: mkimage.sh calls git internally; running from inside /root/bee causes # --- sync overlay into live-build includes.chroot ---
# "outside repository" errors. /var/tmp is outside the git repo and has enough scratch space. LB_DIR="${BUILDER_DIR}"
# genapkovl-bee.sh is found by mkimage via ~/.mkimage/. LB_INCLUDES="${LB_DIR}/config/includes.chroot"
# Remove any stale genapkovl from /var/tmp — mkimage checks CWD first, stale files override ~/.mkimage/. mkdir -p "${LB_INCLUDES}"
rm -f /var/tmp/genapkovl-*.sh rsync -a "${OVERLAY_DIR}/" "${LB_INCLUDES}/"
export TMPDIR=/var/tmp
cd /var/tmp
sh /usr/share/aports/scripts/mkimage.sh \
--tag "v${ALPINE_VERSION}" \
--outdir "${DIST_DIR}" \
--arch x86_64 \
--repository "https://dl-cdn.alpinelinux.org/alpine/v${ALPINE_VERSION}/main" \
--repository "https://dl-cdn.alpinelinux.org/alpine/v${ALPINE_VERSION}/community" \
--workdir /var/tmp/bee-iso-work \
--profile bee
ISO="${DIST_DIR}/alpine-bee-${ALPINE_VERSION}-x86_64.iso" # Ensure SSH authorized_keys perms are correct (rsync may alter)
if [ -f "${LB_INCLUDES}/root/.ssh/authorized_keys" ]; then
chmod 700 "${LB_INCLUDES}/root/.ssh"
chmod 600 "${LB_INCLUDES}/root/.ssh/authorized_keys"
fi
# --- build ISO using live-build ---
mkdir -p "${DIST_DIR}"
echo "" echo ""
echo "=== done ===" echo "=== building ISO (live-build) ==="
echo "ISO: $ISO"
echo "Size: $(du -sh "$ISO" 2>/dev/null | cut -f1 || echo 'not found')" cd "${LB_DIR}"
lb clean 2>&1 | tail -3
lb config 2>&1 | tail -5
lb build 2>&1
# live-build outputs live-image-amd64.hybrid.iso in LB_DIR
ISO_RAW="${LB_DIR}/live-image-amd64.hybrid.iso"
ISO_OUT="${DIST_DIR}/bee-debian${DEBIAN_VERSION}-v${AUDIT_VERSION}-amd64.iso"
if [ -f "$ISO_RAW" ]; then
cp "$ISO_RAW" "$ISO_OUT"
echo ""
echo "=== done ==="
echo "ISO: $ISO_OUT"
echo "Size: $(du -sh "$ISO_OUT" | cut -f1)"
else
echo "ERROR: ISO not found at $ISO_RAW"
exit 1
fi
echo "" echo ""
echo "Boot via BMC virtual media and SSH to the server IP on port 22 as root." echo "Boot via BMC virtual media and SSH to the server IP on port 22 as root."
+29
View File
@@ -0,0 +1,29 @@
#!/bin/sh
# 9000-bee-setup.hook.chroot — runs inside Debian chroot during live-build
# Enables bee systemd services and configures the live environment.
set -e
echo "=== bee chroot setup ==="
# Enable bee services
systemctl enable bee-network.service
systemctl enable bee-nvidia.service
systemctl enable bee-audit.service
systemctl enable bee-sshsetup.service
systemctl enable ssh.service
# Ensure scripts are executable
chmod +x /usr/local/bin/bee-network.sh 2>/dev/null || true
chmod +x /usr/local/bin/bee-nvidia-load 2>/dev/null || true
chmod +x /usr/local/bin/bee-sshsetup 2>/dev/null || true
chmod +x /usr/local/bin/bee-smoketest 2>/dev/null || true
chmod +x /usr/local/bin/bee-tui 2>/dev/null || true
chmod +x /usr/local/bin/audit 2>/dev/null || true
# Reload udev rules
udevadm control --reload-rules 2>/dev/null || true
# Create log directory
mkdir -p /var/log
echo "=== bee chroot setup complete ==="
@@ -0,0 +1,12 @@
# Generated at build time — do not commit
usr/local/bin/audit
usr/local/bin/bee-smoketest
usr/local/bin/nvidia-smi
usr/local/bin/nvidia-bug-report.sh
usr/local/lib/
usr/lib/libnvidia-ml*
usr/lib/libcuda*
root/.ssh/authorized_keys
etc/bee-release
etc/bee-ssh-password-fallback
etc/motd
@@ -0,0 +1,35 @@
# Hardware audit tools
dmidecode
smartmontools
nvme-cli
pciutils
ipmitool
util-linux
e2fsprogs
lshw
lsblk
# Network
iproute2
dhclient
iputils-ping
# SSH
openssh-server
# Utilities
procps
lsof
file
less
vim-tiny
dialog
# QR codes (for displaying audit results)
qrencode
# Firmware
firmware-linux-free
# glibc compat helpers (for any external binaries that need it)
libc6
-108
View File
@@ -1,108 +0,0 @@
#!/bin/sh -e
HOSTNAME="$1"
[ -n "$HOSTNAME" ] || { echo "usage: $0 hostname"; exit 1; }
OVERLAY="${BEE_OVERLAY_DIR}"
[ -n "$OVERLAY" ] || { echo "ERROR: BEE_OVERLAY_DIR not set"; exit 1; }
cleanup() { rm -rf "$tmp"; }
tmp="$(mktemp -d)"
trap cleanup EXIT
makefile() { OWNER="$1" PERMS="$2" FILENAME="$3"; cat > "$FILENAME"; chown "$OWNER" "$FILENAME"; chmod "$PERMS" "$FILENAME"; }
rc_add() { mkdir -p "$tmp/etc/runlevels/$2"; ln -sf /etc/init.d/"$1" "$tmp/etc/runlevels/$2/$1"; }
mkdir -p "$tmp/etc"
makefile root:root 0644 "$tmp/etc/hostname" <<EOF
$HOSTNAME
EOF
# Empty interfaces file — prevents ifupdown from erroring, bee-network handles DHCP
mkdir -p "$tmp/etc/network"
makefile root:root 0644 "$tmp/etc/network/interfaces" <<EOF
auto lo
iface lo inet loopback
EOF
mkdir -p "$tmp/etc/apk"
makefile root:root 0644 "$tmp/etc/apk/world" <<EOF
alpine-base
dmidecode
smartmontools
nvme-cli
pciutils
ipmitool
util-linux
lsblk
e2fsprogs
lshw
dropbear
libqrencode-tools
tzdata
ca-certificates
strace
procps
lsof
file
less
vim
dialog
gcompat
libc6-compat
EOF
rc_add devfs sysinit
rc_add dmesg sysinit
rc_add mdev sysinit
rc_add hwdrivers sysinit
rc_add modloop sysinit
rc_add hwclock boot
rc_add modules boot
rc_add sysctl boot
rc_add hostname boot
rc_add bootmisc boot
rc_add syslog boot
rc_add mount-ro shutdown
rc_add killprocs shutdown
rc_add savecache shutdown
rc_add bee-sshsetup default
rc_add bee-network default
rc_add dropbear default
rc_add bee-nvidia default
rc_add bee-audit default
if [ -d "$OVERLAY/etc" ]; then
cp -r "$OVERLAY/etc/." "$tmp/etc/"
chmod +x "$tmp/etc/init.d/"* 2>/dev/null || true
[ -n "$BEE_BUILD_INFO" ] && sed -i "s/%%BUILD_INFO%%/${BEE_BUILD_INFO}/" "$tmp/etc/motd" 2>/dev/null || true
fi
mkdir -p "$tmp/usr"
if [ -d "$OVERLAY/usr" ]; then
cp -r "$OVERLAY/usr/." "$tmp/usr/"
chmod +x "$tmp/usr/local/bin/"* 2>/dev/null || true
fi
if [ -d "$OVERLAY/root" ]; then
mkdir -p "$tmp/root"
cp -r "$OVERLAY/root/." "$tmp/root/"
chmod 700 "$tmp/root/.ssh" 2>/dev/null || true
chmod 600 "$tmp/root/.ssh/authorized_keys" 2>/dev/null || true
fi
if [ -d "$OVERLAY/lib" ]; then
mkdir -p "$tmp/lib"
cp -r "$OVERLAY/lib/." "$tmp/lib/"
fi
mkdir -p "$tmp/etc/dropbear" "$tmp/etc/conf.d"
# -R: auto-generate host keys if missing
# no dependency on networking service — bee-network handles DHCP independently
makefile root:root 0644 "$tmp/etc/conf.d/dropbear" <<EOF
DROPBEAR_OPTS="-R -B"
EOF
tar -c -C "$tmp" etc usr root lib 2>/dev/null | gzip -9n > "$HOSTNAME.apkovl.tar.gz"
-58
View File
@@ -1,58 +0,0 @@
#!/bin/sh
# Alpine mkimage profile: bee
profile_bee() {
title="Bee Hardware Audit"
desc="Hardware audit LiveCD"
arch="x86_64"
hostname="alpine-bee"
apkovl="genapkovl-bee.sh"
image_ext="iso"
output_format="iso"
kernel_flavors="lts"
kernel_addons=""
initfs_cmdline="modules=loop,squashfs,sd-mod,usb-storage modloop=/boot/modloop-lts quiet"
initfs_features="ata base cdrom ext4 mmc nvme raid scsi squashfs usb virtio nfit"
grub_mod="all_video disk part_gpt part_msdos linux normal configfile search search_label efi_gop fat iso9660 cat echo ls test true help gzio multiboot2 efi_uga"
syslinux_serial="0 115200"
apks="
alpine-base
linux-firmware-none
linux-firmware-rtl_nic
linux-firmware-bnx2
linux-firmware-bnx2x
linux-firmware-tigon
linux-firmware-qlogic
linux-firmware-netronome
linux-firmware-mellanox
linux-firmware-intel
linux-firmware-other
dmidecode
smartmontools
nvme-cli
pciutils
ipmitool
util-linux
lsblk
e2fsprogs
lshw
dropbear
openrc
libqrencode-tools
tzdata
ca-certificates
strace
procps
lsof
file
less
vim
dialog
gcompat
libc6-compat
"
}
+25 -81
View File
@@ -1,10 +1,10 @@
#!/bin/sh #!/bin/sh
# setup-builder.sh — prepare Alpine VM as bee ISO builder # setup-builder.sh — prepare Debian 12 VM as bee ISO builder
# #
# Run once on a fresh Alpine 3.21 VM as root. # Run once on a fresh Debian 12 (Bookworm) VM as root.
# After this script completes, the VM can build ISO images. # After this script completes, the VM can build bee ISO images.
# #
# Usage (on Alpine VM): # Usage (on Debian VM):
# wget -O- https://git.mchus.pro/mchus/bee/raw/branch/main/iso/builder/setup-builder.sh | sh # wget -O- https://git.mchus.pro/mchus/bee/raw/branch/main/iso/builder/setup-builder.sh | sh
# or: sh setup-builder.sh # or: sh setup-builder.sh
@@ -12,65 +12,41 @@ set -e
. "$(dirname "$0")/VERSIONS" 2>/dev/null || true . "$(dirname "$0")/VERSIONS" 2>/dev/null || true
GO_VERSION="${GO_VERSION:-1.23.6}" GO_VERSION="${GO_VERSION:-1.23.6}"
DEBIAN_VERSION="${DEBIAN_VERSION:-12}"
DEBIAN_KERNEL_ABI="${DEBIAN_KERNEL_ABI:-6.1.0-28}"
echo "=== bee builder setup ===" echo "=== bee builder setup ==="
echo "Alpine: $(cat /etc/alpine-release)" echo "Debian: $(cat /etc/debian_version)"
echo "Go target: ${GO_VERSION}" echo "Go target: ${GO_VERSION}"
echo "Kernel ABI: ${DEBIAN_KERNEL_ABI}"
echo "" echo ""
# --- system packages --- # --- system packages ---
apk update export DEBIAN_FRONTEND=noninteractive
# enable community repo if not already enabled apt-get update -qq
sed -i 's|^#\(.*community\)|\1|' /etc/apk/repositories
apk update apt-get install -y \
apk add \ live-build \
alpine-sdk \ debootstrap \
abuild \
squashfs-tools \ squashfs-tools \
xorriso \ xorriso \
grub-pc-bin \
grub-efi-amd64-bin \
mtools \ mtools \
grub \
grub-efi \
grub-bios \
git \ git \
wget \ wget \
curl \ curl \
tar \ tar \
xz \ xz-utils \
screen screen \
rsync \
build-essential \
gcc \
make \
perl \
"linux-headers-${DEBIAN_KERNEL_ABI}-amd64"
# --- audit runtime packages (verify they exist in Alpine repos) --- echo "linux-headers installed: $(dpkg -l "linux-headers-${DEBIAN_KERNEL_ABI}-amd64" | awk '/^ii/{print $3}')"
echo ""
echo "=== verifying audit runtime packages ==="
RUNTIME_PKGS="
dmidecode
smartmontools
nvme-cli
pciutils
ipmitool
util-linux
e2fsprogs
qrencode
dropbear
udhcpc
pciutils-libs
lshw
"
MISSING=""
for pkg in $RUNTIME_PKGS; do
if apk info --quiet "$pkg" 2>/dev/null || apk search --quiet "$pkg" 2>/dev/null | grep -q "^${pkg}-"; then
echo " OK: $pkg"
else
echo " MISSING: $pkg"
MISSING="$MISSING $pkg"
fi
done
if [ -n "$MISSING" ]; then
echo ""
echo "WARNING: missing packages:$MISSING"
echo "These will not be available in the ISO."
fi
# --- Go toolchain --- # --- Go toolchain ---
echo "" echo ""
@@ -93,38 +69,6 @@ fi
export PATH="$PATH:/usr/local/go/bin" export PATH="$PATH:/usr/local/go/bin"
echo "Go: $(go version)" echo "Go: $(go version)"
# --- alpine-conf for mkimage ---
apk add alpine-conf
# --- aports for mkimage.sh ---
if [ ! -d /usr/share/aports ]; then
echo ""
echo "=== cloning aports ==="
git clone --depth=1 --branch "v${ALPINE_VERSION:-3.21}.0" \
https://gitlab.alpinelinux.org/alpine/aports.git \
/usr/share/aports
fi
# --- abuild signing key (required by mkimage.sh) ---
if [ ! -f "${HOME}/.abuild/abuild.conf" ]; then
echo ""
echo "=== generating abuild signing key ==="
mkdir -p "${HOME}/.abuild"
abuild-keygen -a -n 2>/dev/null || true
# abuild-keygen requires doas to install the key system-wide; do it manually
PUB=$(ls "${HOME}/.abuild/"*.pub 2>/dev/null | head -1)
if [ -n "$PUB" ]; then
cp "$PUB" /etc/apk/keys/
PRIV="${PUB%.pub}"
echo "PACKAGER_PRIVKEY=\"${PRIV}\"" > "${HOME}/.abuild/abuild.conf"
echo "abuild key: $PRIV"
else
echo "WARNING: abuild key generation failed"
fi
fi
# NOTE: lz4 compression for modloop is disabled — Alpine initramfs may not support lz4 squashfs.
echo "" echo ""
echo "=== builder setup complete ===" echo "=== builder setup complete ==="
echo "Next: sh iso/builder/build-debug.sh" echo "Next: sh iso/builder/build.sh"
+10 -24
View File
@@ -24,11 +24,10 @@ echo " date: $(date -u)"
echo "========================================" echo "========================================"
echo "" echo ""
# --- kernel version ---
KVER=$(uname -r) KVER=$(uname -r)
info "kernel: $KVER" info "kernel: $KVER"
# --- PATH --- # --- PATH & binaries ---
echo "-- PATH & binaries --" echo "-- PATH & binaries --"
for tool in dmidecode smartctl nvme ipmitool lspci audit; do for tool in dmidecode smartctl nvme ipmitool lspci audit; do
if p=$(PATH="/usr/local/bin:$PATH" command -v "$tool" 2>/dev/null); then if p=$(PATH="/usr/local/bin:$PATH" command -v "$tool" 2>/dev/null); then
@@ -96,30 +95,21 @@ for lib in libnvidia-ml libcuda; do
done done
echo "" echo ""
echo "-- gcompat (glibc compat for nvidia-smi) --" echo "-- systemd services --"
if [ -L /lib64/ld-linux-x86-64.so.2 ] || [ -f /lib64/ld-linux-x86-64.so.2 ]; then
ok "gcompat: /lib64/ld-linux-x86-64.so.2 present"
else
fail "gcompat: /lib64/ld-linux-x86-64.so.2 MISSING — nvidia-smi will fail to exec"
fi
echo ""
echo "-- openrc services --"
for svc in bee-nvidia bee-network bee-audit; do for svc in bee-nvidia bee-network bee-audit; do
if rc-service "$svc" status >/dev/null 2>&1; then if systemctl is-active --quiet "$svc" 2>/dev/null; then
ok "service running: $svc" ok "service active: $svc"
else else
fail "service NOT running: $svc" fail "service NOT active: $svc"
fi fi
done done
for svc in dropbear bee-sshsetup; do for svc in ssh bee-sshsetup; do
if [ -f "/etc/init.d/$svc" ]; then if systemctl is-active --quiet "$svc" 2>/dev/null \
if rc-service "$svc" status >/dev/null 2>&1; then || systemctl show "$svc" --property=ActiveState 2>/dev/null | grep -q "inactive\|exited"; then
ok "service running: $svc" ok "service ok: $svc"
else else
warn "service not running: $svc (may be one-shot)" warn "service status unknown: $svc"
fi
fi fi
done done
@@ -136,8 +126,6 @@ fi
echo "" echo ""
echo "-- audit last run --" echo "-- audit last run --"
# audit binary logs via slog to stderr (bee-audit.log); JSON output goes to bee-audit.json.
# slog format: time=... level=INFO msg="audit output written" path=...
if [ -f /var/log/bee-audit.json ] && [ -s /var/log/bee-audit.json ]; then if [ -f /var/log/bee-audit.json ] && [ -s /var/log/bee-audit.json ]; then
ok "audit: bee-audit.json present and non-empty" ok "audit: bee-audit.json present and non-empty"
info "size: $(du -sh /var/log/bee-audit.json | cut -f1)" info "size: $(du -sh /var/log/bee-audit.json | cut -f1)"
@@ -148,13 +136,11 @@ fi
if [ -f /var/log/bee-audit.log ]; then if [ -f /var/log/bee-audit.log ]; then
last_line=$(tail -1 /var/log/bee-audit.log) last_line=$(tail -1 /var/log/bee-audit.log)
info "last log line: $last_line" info "last log line: $last_line"
# slog writes: msg="audit output written" on success
if grep -q "audit output written" /var/log/bee-audit.log 2>/dev/null; then if grep -q "audit output written" /var/log/bee-audit.log 2>/dev/null; then
ok "audit: completed successfully" ok "audit: completed successfully"
else else
warn "audit: 'audit output written' not found in log — may have failed" warn "audit: 'audit output written' not found in log — may have failed"
fi fi
# check for nvidia enrichment skip (slog message from nvidia collector)
if grep -q "nvidia: enrichment skipped\|nvidia.*skipped\|enrichment skipped" /var/log/bee-audit.log 2>/dev/null; then if grep -q "nvidia: enrichment skipped\|nvidia.*skipped\|enrichment skipped" /var/log/bee-audit.log 2>/dev/null; then
reason=$(grep -E "nvidia.*skipped|enrichment skipped" /var/log/bee-audit.log | tail -1) reason=$(grep -E "nvidia.*skipped|enrichment skipped" /var/log/bee-audit.log | tail -1)
fail "audit: nvidia enrichment skipped — $reason" fail "audit: nvidia enrichment skipped — $reason"
-1
View File
@@ -1 +0,0 @@
DROPBEAR_OPTS="-p 22 -R -B"
-21
View File
@@ -1,21 +0,0 @@
#!/sbin/openrc-run
description="Bee: run hardware audit"
depend() {
need localmount
after bee-network bee-nvidia
}
start() {
ebegin "Running hardware audit"
/usr/local/bin/audit --output "file:/var/log/bee-audit.json" 2>/var/log/bee-audit.log
local rc=$?
if [ $rc -eq 0 ]; then
einfo "Audit complete: /var/log/bee-audit.json"
einfo "SSH in and inspect results. Dropbear is running."
else
ewarn "Audit finished with errors — check /var/log/bee-audit.log"
fi
eend 0
}
-14
View File
@@ -1,14 +0,0 @@
#!/sbin/openrc-run
description="Bee: bring up network interfaces via DHCP"
depend() {
need localmount
before bee-audit
}
start() {
ebegin "Bringing up network interfaces"
/usr/local/bin/bee-network.sh >> /var/log/bee-network.log 2>&1
eend 0
}
-79
View File
@@ -1,79 +0,0 @@
#!/sbin/openrc-run
description="Bee: load NVIDIA kernel modules"
NVIDIA_KO_DIR="/usr/local/lib/nvidia"
depend() {
need localmount
before bee-audit
}
start() {
ebegin "Loading NVIDIA modules"
einfo "kernel: $(uname -r)"
if [ ! -d "$NVIDIA_KO_DIR" ]; then
ewarn "NVIDIA module dir missing: $NVIDIA_KO_DIR"
eend 1
return 1
fi
einfo "module dir: $NVIDIA_KO_DIR"
ls "$NVIDIA_KO_DIR"/*.ko 2>/dev/null | sed 's/^/ /' || true
# Create libnvidia-ml soname symlinks needed by nvidia-smi (glibc binary on Alpine/musl)
for lib in libnvidia-ml libcuda; do
versioned=$(ls /usr/lib/${lib}.so.[0-9]* 2>/dev/null | head -1)
[ -n "$versioned" ] || continue
base=$(basename "$versioned")
ln -sf "$base" "/usr/lib/${lib}.so.1" 2>/dev/null || true
ln -sf "${lib}.so.1" "/usr/lib/${lib}.so" 2>/dev/null || true
done
# Load modules via insmod (bypasses modules.dep — modloop squashfs is read-only)
for mod in nvidia nvidia-modeset nvidia-uvm; do
ko="$NVIDIA_KO_DIR/${mod}.ko"
[ -f "$ko" ] || ko="$NVIDIA_KO_DIR/${mod//-/_}.ko"
if [ -f "$ko" ]; then
if insmod "$ko" 2>/dev/null; then
einfo "loaded: $mod"
else
ewarn "failed to load: $mod"
dmesg | tail -n 5 | sed 's/^/ dmesg: /' || true
fi
else
ewarn "not found: $ko"
fi
done
# Create /dev/nvidia* device nodes — mdev on Alpine does not have NVIDIA rules,
# so the kernel hotplug events are not handled and nodes are never created.
# Without /dev/nvidiactl nvidia-smi returns NVML_ERROR_LIBRARY_NOT_FOUND (exit 12).
nvidia_major=$(grep -m1 ' nvidiactl$' /proc/devices 2>/dev/null | awk '{print $1}')
if [ -n "$nvidia_major" ]; then
mknod -m 666 /dev/nvidiactl c "$nvidia_major" 255 2>/dev/null \
&& einfo "created /dev/nvidiactl (major $nvidia_major)" \
|| ewarn "/dev/nvidiactl already exists or mknod failed"
for i in 0 1 2 3 4 5 6 7; do
mknod -m 666 "/dev/nvidia$i" c "$nvidia_major" "$i" 2>/dev/null || true
done
einfo "created /dev/nvidia{0-7}"
else
ewarn "/dev/nvidiactl: nvidia not in /proc/devices — no GPU hardware present?"
eend 0
return 0
fi
uvm_major=$(grep -m1 ' nvidia-uvm$' /proc/devices 2>/dev/null | awk '{print $1}')
if [ -n "$uvm_major" ]; then
mknod -m 666 /dev/nvidia-uvm c "$uvm_major" 0 2>/dev/null \
&& einfo "created /dev/nvidia-uvm (major $uvm_major)" \
|| ewarn "/dev/nvidia-uvm already exists or mknod failed"
mknod -m 666 /dev/nvidia-uvm-tools c "$uvm_major" 1 2>/dev/null || true
else
ewarn "/dev/nvidia-uvm: nvidia-uvm not in /proc/devices"
fi
eend 0
}
-28
View File
@@ -1,28 +0,0 @@
#!/sbin/openrc-run
description="Bee: configure SSH access (keys or password fallback)"
depend() {
need localmount
before dropbear
}
start() {
# Always create dedicated 'bee' user for password fallback.
# If no SSH keys embedded: login with bee / eeb
if ! id bee > /dev/null 2>&1; then
adduser -D -s /bin/sh bee > /dev/null 2>&1
fi
printf 'eeb\neeb\n' | passwd bee > /dev/null 2>&1
if [ -f /etc/bee-ssh-password-fallback ]; then
ebegin "SSH key auth unavailable — password fallback active"
ewarn "Login: bee / eeb"
ewarn "Generate a key: sh keys/scripts/keygen.sh <name>"
eend 0
else
ebegin "SSH key auth configured"
# bee user exists but password login less useful when keys work
eend 0
fi
}
-37
View File
@@ -1,37 +0,0 @@
#!/sbin/openrc-run
description="Dropbear SSH server"
depend() {
need localmount
after bee-sshsetup
use logger
}
check_config() {
if [ ! -e /etc/dropbear/dropbear_rsa_host_key ]; then
einfo "Generating RSA host key..."
/usr/bin/dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key
fi
if [ ! -e /etc/dropbear/dropbear_ecdsa_host_key ]; then
einfo "Generating ECDSA host key..."
/usr/bin/dropbearkey -t ecdsa -f /etc/dropbear/dropbear_ecdsa_host_key
fi
if [ ! -e /etc/dropbear/dropbear_ed25519_host_key ]; then
einfo "Generating ED25519 host key..."
/usr/bin/dropbearkey -t ed25519 -f /etc/dropbear/dropbear_ed25519_host_key
fi
}
start() {
check_config || return 1
ebegin "Starting dropbear"
/usr/sbin/dropbear ${DROPBEAR_OPTS}
eend $?
}
stop() {
ebegin "Stopping dropbear"
start-stop-daemon --stop --pidfile /var/run/dropbear.pid
eend $?
}
-13
View File
@@ -1,13 +0,0 @@
::sysinit:/sbin/openrc sysinit
::sysinit:/sbin/openrc boot
::wait:/sbin/openrc default
# Autologin on tty1
tty1::respawn:/sbin/agetty --autologin root --noclear tty1 linux
tty2::respawn:/sbin/getty 38400 tty2
tty3::respawn:/sbin/getty 38400 tty3
ttyS0::respawn:/sbin/getty -L 115200 ttyS0 vt100
::ctrlaltdel:/sbin/reboot
::shutdown:/sbin/openrc shutdown
@@ -0,0 +1,14 @@
[Unit]
Description=Bee: run hardware audit
After=bee-network.service bee-nvidia.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/audit --output file:/var/log/bee-audit.json
StandardOutput=append:/var/log/bee-audit.log
StandardError=append:/var/log/bee-audit.log
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,14 @@
[Unit]
Description=Bee: bring up network interfaces via DHCP
After=local-fs.target
Before=network-online.target bee-audit.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/bee-network.sh
StandardOutput=append:/var/log/bee-network.log
StandardError=append:/var/log/bee-network.log
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,14 @@
[Unit]
Description=Bee: load NVIDIA kernel modules and create device nodes
After=local-fs.target udev.service
Before=bee-audit.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/bee-nvidia-load
StandardOutput=journal
StandardError=journal
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,12 @@
[Unit]
Description=Bee: configure SSH access (keys or password fallback)
After=local-fs.target
Before=ssh.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/bee-sshsetup
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
+2 -3
View File
@@ -22,9 +22,8 @@ for iface in $interfaces; do
log "bringing up $iface" log "bringing up $iface"
ip link set "$iface" up 2>/dev/null || { log "WARN: could not bring up $iface"; continue; } ip link set "$iface" up 2>/dev/null || { log "WARN: could not bring up $iface"; continue; }
# DHCP in background: -b forks if no immediate lease, & ensures non-blocking always. # DHCP in background — non-blocking, retries indefinitely
# -t 0: unlimited retries, -T 3: 3s per attempt. No -q: stay running to renew lease. dhclient -nw "$iface" 2>/dev/null &
udhcpc -i "$iface" -b -t 0 -T 3 &
log "DHCP started for $iface (pid $!)" log "DHCP started for $iface (pid $!)"
done done
+59
View File
@@ -0,0 +1,59 @@
#!/bin/sh
# bee-nvidia-load — load NVIDIA kernel modules and create device nodes
# Called by bee-nvidia.service at boot.
NVIDIA_KO_DIR="/usr/local/lib/nvidia"
log() { echo "[bee-nvidia] $*"; }
log "kernel: $(uname -r)"
if [ ! -d "$NVIDIA_KO_DIR" ]; then
log "ERROR: NVIDIA module dir missing: $NVIDIA_KO_DIR"
exit 1
fi
log "module dir: $NVIDIA_KO_DIR"
ls "$NVIDIA_KO_DIR"/*.ko 2>/dev/null | sed 's/^/ /' || true
# Load modules via insmod (direct load — no depmod needed)
for mod in nvidia nvidia-modeset nvidia-uvm; do
ko="$NVIDIA_KO_DIR/${mod}.ko"
[ -f "$ko" ] || ko="$NVIDIA_KO_DIR/${mod//-/_}.ko"
if [ -f "$ko" ]; then
if insmod "$ko" 2>/dev/null; then
log "loaded: $mod"
else
log "WARN: failed to load: $mod"
dmesg | tail -n 5 | sed 's/^/ dmesg: /' || true
fi
else
log "WARN: not found: $ko"
fi
done
# Create /dev/nvidia* device nodes (udev rules absent since we use .run installer)
nvidia_major=$(grep -m1 ' nvidiactl$' /proc/devices 2>/dev/null | awk '{print $1}')
if [ -n "$nvidia_major" ]; then
mknod -m 666 /dev/nvidiactl c "$nvidia_major" 255 2>/dev/null \
&& log "created /dev/nvidiactl (major $nvidia_major)" \
|| log "WARN: /dev/nvidiactl already exists or mknod failed"
for i in 0 1 2 3 4 5 6 7; do
mknod -m 666 "/dev/nvidia$i" c "$nvidia_major" "$i" 2>/dev/null || true
done
log "created /dev/nvidia{0-7}"
else
log "WARN: nvidiactl not in /proc/devices — no GPU hardware present?"
fi
uvm_major=$(grep -m1 ' nvidia-uvm$' /proc/devices 2>/dev/null | awk '{print $1}')
if [ -n "$uvm_major" ]; then
mknod -m 666 /dev/nvidia-uvm c "$uvm_major" 0 2>/dev/null \
&& log "created /dev/nvidia-uvm (major $uvm_major)" \
|| log "WARN: /dev/nvidia-uvm already exists"
mknod -m 666 /dev/nvidia-uvm-tools c "$uvm_major" 1 2>/dev/null || true
else
log "WARN: nvidia-uvm not in /proc/devices"
fi
log "done"
+18
View File
@@ -0,0 +1,18 @@
#!/bin/sh
# bee-sshsetup — configure SSH access
# Called by bee-sshsetup.service before SSH starts.
log() { echo "[bee-sshsetup] $*"; }
# Always create dedicated 'bee' user for password fallback.
if ! id bee > /dev/null 2>&1; then
useradd -m -s /bin/sh bee > /dev/null 2>&1
fi
echo "bee:eeb" | chpasswd > /dev/null 2>&1
if [ -f /etc/bee-ssh-password-fallback ]; then
log "SSH key auth unavailable — password fallback active"
log "Login: bee / eeb"
else
log "SSH key auth configured"
fi