Fix netboot initialization and add documentation tooling
- 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.
This commit is contained in:
259
verify-image.sh
Executable file
259
verify-image.sh
Executable file
@@ -0,0 +1,259 @@
|
||||
#!/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
|
||||
Reference in New Issue
Block a user