- Add CLAUDE.md with project architecture and build documentation - Add verify-image.sh script to validate generated netboot images - Fix boot.ipxe kernel parameters: - Add boot=netboot to invoke custom initramfs script - Add console=tty0 for VGA output alongside serial console - Fix earlyprintk serial specification - Remove dead symlink creation in build-image.sh (http/latest pointed to non-existent directory) The boot=netboot parameter is critical - without it, initramfs falls back to local boot and fails with /dev/root errors. The console changes enable viewing boot messages on monitor instead of only serial port.
260 lines
7.4 KiB
Bash
Executable File
260 lines
7.4 KiB
Bash
Executable File
#!/bin/bash
|
|
# Verify netboot image build completeness and correctness
|
|
# Run this after 'make build' to validate the generated image
|
|
|
|
set -e
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
HTTP_DIR="$SCRIPT_DIR/http"
|
|
TMPDIR=$(mktemp -d)
|
|
EXIT_CODE=0
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m' # No Color
|
|
|
|
error() {
|
|
echo -e "${RED}✗${NC} $1"
|
|
EXIT_CODE=1
|
|
}
|
|
|
|
success() {
|
|
echo -e "${GREEN}✓${NC} $1"
|
|
}
|
|
|
|
warning() {
|
|
echo -e "${YELLOW}!${NC} $1"
|
|
}
|
|
|
|
info() {
|
|
echo " $1"
|
|
}
|
|
|
|
cleanup() {
|
|
rm -rf "$TMPDIR"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
echo "Verifying netboot image build..."
|
|
echo ""
|
|
|
|
# Check 1: Required files exist
|
|
echo "Checking required files..."
|
|
for file in vmlinuz initrd-netboot.img filesystem.squashfs version.txt boot.ipxe; do
|
|
if [ -f "$HTTP_DIR/$file" ]; then
|
|
success "$file exists"
|
|
else
|
|
error "$file missing"
|
|
fi
|
|
done
|
|
echo ""
|
|
|
|
# Check 2: File types are correct
|
|
echo "Checking file types..."
|
|
if file "$HTTP_DIR/vmlinuz" | grep -q "Linux kernel"; then
|
|
success "vmlinuz is a valid Linux kernel"
|
|
else
|
|
error "vmlinuz is not a valid kernel"
|
|
fi
|
|
|
|
if file "$HTTP_DIR/initrd-netboot.img" | grep -q "cpio archive"; then
|
|
success "initrd-netboot.img is a valid initramfs"
|
|
else
|
|
error "initrd-netboot.img is not a valid initramfs"
|
|
fi
|
|
|
|
if file "$HTTP_DIR/filesystem.squashfs" | grep -q "Squashfs filesystem"; then
|
|
success "filesystem.squashfs is a valid squashfs image"
|
|
else
|
|
error "filesystem.squashfs is not a valid squashfs"
|
|
fi
|
|
echo ""
|
|
|
|
# Check 3: File permissions for HTTP serving
|
|
echo "Checking file permissions..."
|
|
for file in vmlinuz initrd-netboot.img filesystem.squashfs; do
|
|
PERMS=$(stat -c "%a" "$HTTP_DIR/$file")
|
|
if [ "$PERMS" = "644" ]; then
|
|
success "$file has correct permissions (644)"
|
|
else
|
|
warning "$file has permissions $PERMS (expected 644)"
|
|
fi
|
|
done
|
|
echo ""
|
|
|
|
# Check 4: File sizes are reasonable
|
|
echo "Checking file sizes..."
|
|
KERNEL_SIZE=$(stat -c %s "$HTTP_DIR/vmlinuz")
|
|
INITRD_SIZE=$(stat -c %s "$HTTP_DIR/initrd-netboot.img")
|
|
SQUASHFS_SIZE=$(stat -c %s "$HTTP_DIR/filesystem.squashfs")
|
|
|
|
if [ "$KERNEL_SIZE" -gt 5000000 ] && [ "$KERNEL_SIZE" -lt 50000000 ]; then
|
|
success "vmlinuz size reasonable: $(numfmt --to=iec-i --suffix=B $KERNEL_SIZE)"
|
|
else
|
|
warning "vmlinuz size unusual: $(numfmt --to=iec-i --suffix=B $KERNEL_SIZE)"
|
|
fi
|
|
|
|
if [ "$INITRD_SIZE" -gt 10000000 ] && [ "$INITRD_SIZE" -lt 100000000 ]; then
|
|
success "initrd size reasonable: $(numfmt --to=iec-i --suffix=B $INITRD_SIZE)"
|
|
else
|
|
warning "initrd size unusual: $(numfmt --to=iec-i --suffix=B $INITRD_SIZE)"
|
|
fi
|
|
|
|
if [ "$SQUASHFS_SIZE" -gt 500000000 ] && [ "$SQUASHFS_SIZE" -lt 2000000000 ]; then
|
|
success "squashfs size reasonable: $(numfmt --to=iec-i --suffix=B $SQUASHFS_SIZE)"
|
|
else
|
|
warning "squashfs size unusual: $(numfmt --to=iec-i --suffix=B $SQUASHFS_SIZE)"
|
|
fi
|
|
echo ""
|
|
|
|
# Check 5: Initramfs contains custom netboot script and binaries
|
|
echo "Checking initramfs contents..."
|
|
unmkinitramfs "$HTTP_DIR/initrd-netboot.img" "$TMPDIR/initramfs" 2>/dev/null
|
|
|
|
if [ -f "$TMPDIR/initramfs/main/scripts/netboot" ]; then
|
|
success "Custom netboot script present in initramfs"
|
|
|
|
# Verify it matches source
|
|
if diff -q "$SCRIPT_DIR/initramfs/scripts/netboot" "$TMPDIR/initramfs/main/scripts/netboot" >/dev/null 2>&1; then
|
|
success "netboot script matches source"
|
|
else
|
|
warning "netboot script differs from source"
|
|
fi
|
|
else
|
|
error "Custom netboot script missing from initramfs"
|
|
fi
|
|
|
|
# Check required binaries
|
|
for binary in wget curl unsquashfs awk; do
|
|
if [ -f "$TMPDIR/initramfs/main/usr/bin/$binary" ]; then
|
|
success "$binary binary present"
|
|
else
|
|
error "$binary binary missing from initramfs"
|
|
fi
|
|
done
|
|
|
|
if [ -f "$TMPDIR/initramfs/main/usr/sbin/switch_root" ]; then
|
|
success "switch_root binary present"
|
|
else
|
|
error "switch_root binary missing from initramfs"
|
|
fi
|
|
echo ""
|
|
|
|
# Check 6: Required kernel modules configured
|
|
echo "Checking kernel modules configuration..."
|
|
if [ -f "$TMPDIR/initramfs/main/conf/modules" ]; then
|
|
MODULES_FILE="$TMPDIR/initramfs/main/conf/modules"
|
|
|
|
for module in squashfs overlay r8125 ext4 isofs af_packet nls_iso8859-1; do
|
|
if grep -q "^$module" "$MODULES_FILE"; then
|
|
success "Module $module configured"
|
|
else
|
|
error "Module $module not configured"
|
|
fi
|
|
done
|
|
else
|
|
warning "modules configuration file not found"
|
|
fi
|
|
echo ""
|
|
|
|
# Check 7: Squashfs root filesystem contents
|
|
echo "Checking squashfs root filesystem..."
|
|
|
|
# Check critical paths exist (handle usr-merge symlinks)
|
|
for path in boot etc root usr var; do
|
|
if unsquashfs -ll "$HTTP_DIR/filesystem.squashfs" | grep -q "squashfs-root/$path$"; then
|
|
success "/$path directory exists"
|
|
else
|
|
error "/$path directory missing"
|
|
fi
|
|
done
|
|
|
|
# Check bin and lib (may be symlinks due to usr-merge)
|
|
for path in bin lib; do
|
|
if unsquashfs -ll "$HTTP_DIR/filesystem.squashfs" | grep -qE "squashfs-root/$path( |->|$)"; then
|
|
success "/$path exists (directory or symlink)"
|
|
else
|
|
error "/$path missing"
|
|
fi
|
|
done
|
|
|
|
# Check SSH authorized_keys
|
|
if unsquashfs -cat "$HTTP_DIR/filesystem.squashfs" root/.ssh/authorized_keys >/dev/null 2>&1; then
|
|
KEY_COUNT=$(unsquashfs -cat "$HTTP_DIR/filesystem.squashfs" root/.ssh/authorized_keys 2>/dev/null | grep -c "^ssh-")
|
|
success "SSH authorized_keys present ($KEY_COUNT keys)"
|
|
else
|
|
error "SSH authorized_keys missing or invalid"
|
|
fi
|
|
|
|
# Check netplan config
|
|
if unsquashfs -cat "$HTTP_DIR/filesystem.squashfs" etc/netplan/01-netcfg.yaml >/dev/null 2>&1; then
|
|
success "Netplan configuration present"
|
|
else
|
|
error "Netplan configuration missing"
|
|
fi
|
|
|
|
# Check K3s dependencies
|
|
for pkg in containerd runc; do
|
|
if unsquashfs -ll "$HTTP_DIR/filesystem.squashfs" | grep -q "usr/bin/$pkg"; then
|
|
success "K3s dependency: $pkg"
|
|
else
|
|
warning "K3s dependency missing: $pkg (may be in /usr/sbin)"
|
|
fi
|
|
done
|
|
echo ""
|
|
|
|
# Check 8: Version info
|
|
echo "Build information:"
|
|
if [ -f "$HTTP_DIR/version.txt" ]; then
|
|
cat "$HTTP_DIR/version.txt" | sed 's/^/ /'
|
|
else
|
|
warning "version.txt not found"
|
|
fi
|
|
echo ""
|
|
|
|
# Check 9: iPXE boot configuration
|
|
echo "Checking iPXE configuration..."
|
|
if [ -f "$HTTP_DIR/boot.ipxe" ]; then
|
|
success "boot.ipxe present"
|
|
|
|
# Extract server URL from boot.ipxe
|
|
SERVER_URL=$(grep "http://" "$HTTP_DIR/boot.ipxe" | head -1 | grep -oP 'http://[^/]+')
|
|
if [ -n "$SERVER_URL" ]; then
|
|
info "Boot server configured: $SERVER_URL"
|
|
fi
|
|
|
|
# Check if all required files are referenced
|
|
for file in vmlinuz initrd-netboot.img filesystem.squashfs; do
|
|
if grep -q "$file" "$HTTP_DIR/boot.ipxe"; then
|
|
success "boot.ipxe references $file"
|
|
else
|
|
error "boot.ipxe missing reference to $file"
|
|
fi
|
|
done
|
|
|
|
# Check for required kernel parameters
|
|
if grep -q "overlayroot=tmpfs" "$HTTP_DIR/boot.ipxe"; then
|
|
success "boot.ipxe configures overlayroot"
|
|
else
|
|
warning "boot.ipxe missing overlayroot parameter"
|
|
fi
|
|
else
|
|
error "boot.ipxe missing"
|
|
fi
|
|
echo ""
|
|
|
|
# Summary
|
|
echo "========================================="
|
|
if [ $EXIT_CODE -eq 0 ]; then
|
|
echo -e "${GREEN}✓ All checks passed!${NC}"
|
|
echo "Image is ready for deployment."
|
|
else
|
|
echo -e "${RED}✗ Some checks failed${NC}"
|
|
echo "Review errors above before deploying."
|
|
fi
|
|
echo "========================================="
|
|
|
|
exit $EXIT_CODE
|