feat: Implement complete Zero OS Alpine Initramfs Builder

- Complete bash framework with strict error handling
- Modular library system (docker, alpine, components, initramfs, kernel, testing)
- Rust component integration (zinit, rfs, mycelium) with musl targeting
- Rootless Docker/Podman support for GitHub Actions
- Centralized configuration in config/build.conf
- 2-stage module loading system
- Strip + UPX optimization for minimal size
- Complete zinit integration replacing OpenRC
- GitHub Actions CI/CD pipeline
- Comprehensive documentation and usage guides

Components:
- Latest stable kernel 6.12.44
- Alpine Linux 3.22 base
- ThreeFold components: zinit, mycelium, rfs, corex
- Target: ~8-12MB final initramfs.cpio.xz
This commit is contained in:
2025-08-31 12:31:49 +02:00
commit 860b9aa161
81 changed files with 30118 additions and 0 deletions

367
scripts/lib/testing.sh Normal file
View File

@@ -0,0 +1,367 @@
#!/bin/bash
# Testing with QEMU and cloud-hypervisor
# Source common functions
LIB_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${LIB_SCRIPT_DIR}/common.sh"
# Testing configuration
QEMU_MEMORY="${QEMU_MEMORY:-512M}"
QEMU_TIMEOUT="${QEMU_TIMEOUT:-60}"
CLOUD_HYPERVISOR_MEMORY="${CLOUD_HYPERVISOR_MEMORY:-512M}"
# Test kernel boot with QEMU
function testing_qemu_boot() {
local kernel_file="$1"
local test_type="${2:-basic}"
local timeout="${3:-$QEMU_TIMEOUT}"
section_header "Testing with QEMU"
if [[ ! -f "$kernel_file" ]]; then
log_error "Kernel file not found: ${kernel_file}"
return 1
fi
# Check if QEMU is available
if ! command_exists "qemu-system-x86_64"; then
log_error "QEMU not found. Install with: apt-get install qemu-system-x86"
return 1
fi
log_info "Kernel file: ${kernel_file}"
log_info "Memory: ${QEMU_MEMORY}"
log_info "Test type: ${test_type}"
log_info "Timeout: ${timeout}s"
case "$test_type" in
"basic")
testing_qemu_basic_boot "$kernel_file" "$timeout"
;;
"serial")
testing_qemu_serial_boot "$kernel_file" "$timeout"
;;
"interactive")
testing_qemu_interactive_boot "$kernel_file"
;;
*)
log_error "Unknown QEMU test type: ${test_type}"
return 1
;;
esac
}
# Basic QEMU boot test (automated)
function testing_qemu_basic_boot() {
local kernel_file="$1"
local timeout="$2"
log_info "Running basic QEMU boot test (${timeout}s timeout)"
# QEMU command for automated testing
local qemu_cmd="qemu-system-x86_64 \
-kernel $kernel_file \
-m $QEMU_MEMORY \
-nographic \
-serial mon:stdio \
-append 'console=ttyS0,115200 console=tty1 loglevel=7 panic=10' \
-no-reboot"
log_info "QEMU command: ${qemu_cmd}"
# Run with timeout
if timeout "$timeout" $qemu_cmd 2>&1 | tee /tmp/qemu-boot.log; then
log_info "QEMU boot test completed"
else
local exit_code=$?
if [[ $exit_code -eq 124 ]]; then
log_info "QEMU boot test timed out (${timeout}s) - this may be normal"
else
log_error "QEMU boot test failed with exit code: ${exit_code}"
return 1
fi
fi
# Check boot log for success indicators
testing_analyze_boot_log "/tmp/qemu-boot.log"
}
# QEMU serial console test
function testing_qemu_serial_boot() {
local kernel_file="$1"
local timeout="$2"
log_info "Running QEMU serial console test"
# QEMU command optimized for serial console
local qemu_cmd="qemu-system-x86_64 \
-kernel $kernel_file \
-m $QEMU_MEMORY \
-nographic \
-serial stdio \
-append 'console=ttyS0,115200n8 console=tty1 consoleblank=0 earlyprintk=serial,ttyS0,115200n8 loglevel=7'"
log_info "QEMU serial command: ${qemu_cmd}"
# Run with timeout and capture output
timeout "$timeout" $qemu_cmd 2>&1 | tee /tmp/qemu-serial.log
# Analyze serial output
testing_analyze_boot_log "/tmp/qemu-serial.log"
}
# Interactive QEMU boot (no timeout)
function testing_qemu_interactive_boot() {
local kernel_file="$1"
log_info "Starting interactive QEMU session"
log_info "Use Ctrl+A, X to exit QEMU"
# Interactive QEMU command
local qemu_cmd="qemu-system-x86_64 \
-kernel $kernel_file \
-m $QEMU_MEMORY \
-nographic \
-serial mon:stdio \
-append 'console=ttyS0,115200 console=tty1 loglevel=7'"
log_info "QEMU command: ${qemu_cmd}"
# Run interactively
safe_execute $qemu_cmd
}
# Test kernel boot with cloud-hypervisor
function testing_cloud_hypervisor_boot() {
local kernel_file="$1"
local test_type="${2:-basic}"
local timeout="${3:-$QEMU_TIMEOUT}"
section_header "Testing with cloud-hypervisor"
if [[ ! -f "$kernel_file" ]]; then
log_error "Kernel file not found: ${kernel_file}"
return 1
fi
# Check if cloud-hypervisor is available
if ! command_exists "cloud-hypervisor"; then
log_error "cloud-hypervisor not found. Install from: https://github.com/cloud-hypervisor/cloud-hypervisor"
return 1
fi
log_info "Kernel file: ${kernel_file}"
log_info "Memory: ${CLOUD_HYPERVISOR_MEMORY}"
log_info "Test type: ${test_type}"
case "$test_type" in
"basic")
testing_cloud_hypervisor_basic "$kernel_file" "$timeout"
;;
"serial")
testing_cloud_hypervisor_serial "$kernel_file" "$timeout"
;;
*)
log_error "Unknown cloud-hypervisor test type: ${test_type}"
return 1
;;
esac
}
# Basic cloud-hypervisor test
function testing_cloud_hypervisor_basic() {
local kernel_file="$1"
local timeout="$2"
log_info "Running basic cloud-hypervisor test"
# cloud-hypervisor command
local ch_cmd="cloud-hypervisor \
--kernel $kernel_file \
--memory size=${CLOUD_HYPERVISOR_MEMORY} \
--serial tty \
--console off \
--cmdline 'console=ttyS0,115200 loglevel=7 panic=10'"
log_info "cloud-hypervisor command: ${ch_cmd}"
# Run with timeout
if timeout "$timeout" $ch_cmd 2>&1 | tee /tmp/cloud-hypervisor-boot.log; then
log_info "cloud-hypervisor test completed"
else
local exit_code=$?
if [[ $exit_code -eq 124 ]]; then
log_info "cloud-hypervisor test timed out (${timeout}s)"
else
log_error "cloud-hypervisor test failed with exit code: ${exit_code}"
return 1
fi
fi
# Analyze boot log
testing_analyze_boot_log "/tmp/cloud-hypervisor-boot.log"
}
# cloud-hypervisor serial test
function testing_cloud_hypervisor_serial() {
local kernel_file="$1"
local timeout="$2"
log_info "Running cloud-hypervisor serial test"
# cloud-hypervisor command with serial focus
local ch_cmd="cloud-hypervisor \
--kernel $kernel_file \
--memory size=${CLOUD_HYPERVISOR_MEMORY} \
--serial tty \
--console off \
--cmdline 'console=ttyS0,115200n8 earlyprintk=serial loglevel=7'"
log_info "cloud-hypervisor serial command: ${ch_cmd}"
timeout "$timeout" $ch_cmd 2>&1 | tee /tmp/cloud-hypervisor-serial.log
testing_analyze_boot_log "/tmp/cloud-hypervisor-serial.log"
}
# Analyze boot log for success/failure indicators
function testing_analyze_boot_log() {
local log_file="$1"
section_header "Analyzing Boot Log"
if [[ ! -f "$log_file" ]]; then
log_warn "Boot log file not found: ${log_file}"
return 1
fi
local log_size=$(get_file_size "$log_file")
log_info "Boot log size: ${log_size}"
# Success indicators
local success_patterns=(
"zinit.*starting"
"zinit.*initialized"
"login:"
"zero-os.*login:"
"Alpine Linux"
"Welcome to Alpine"
)
# Error indicators
local error_patterns=(
"Kernel panic"
"kernel BUG"
"Unable to mount root"
"VFS: Cannot open root device"
"not syncing"
"Attempted to kill init"
)
local success_count=0
local error_count=0
# Check for success patterns
for pattern in "${success_patterns[@]}"; do
if grep -i "$pattern" "$log_file" >/dev/null 2>&1; then
log_info "✓ Found success indicator: ${pattern}"
((success_count++))
fi
done
# Check for error patterns
for pattern in "${error_patterns[@]}"; do
if grep -i "$pattern" "$log_file" >/dev/null 2>&1; then
log_error "✗ Found error indicator: ${pattern}"
((error_count++))
fi
done
# Summary
log_info "Boot log analysis:"
log_info " Success indicators: ${success_count}"
log_info " Error indicators: ${error_count}"
if [[ $error_count -gt 0 ]]; then
log_error "Boot test failed - errors detected in log"
log_info "Check full log at: ${log_file}"
return 1
elif [[ $success_count -gt 0 ]]; then
log_info "Boot test successful - system appears to be working"
return 0
else
log_warn "Boot test inconclusive - no clear success/error indicators"
return 2
fi
}
# Run comprehensive test suite
function testing_run_all() {
local kernel_file="$1"
local test_timeout="${2:-60}"
section_header "Running Comprehensive Test Suite"
local test_results=()
# Test with QEMU
log_info "Running QEMU tests..."
if testing_qemu_boot "$kernel_file" "basic" "$test_timeout"; then
test_results+=("QEMU-basic: PASS")
else
test_results+=("QEMU-basic: FAIL")
fi
if testing_qemu_boot "$kernel_file" "serial" "$test_timeout"; then
test_results+=("QEMU-serial: PASS")
else
test_results+=("QEMU-serial: FAIL")
fi
# Test with cloud-hypervisor (if available)
if command_exists "cloud-hypervisor"; then
log_info "Running cloud-hypervisor tests..."
if testing_cloud_hypervisor_boot "$kernel_file" "basic" "$test_timeout"; then
test_results+=("cloud-hypervisor-basic: PASS")
else
test_results+=("cloud-hypervisor-basic: FAIL")
fi
else
log_warn "cloud-hypervisor not available, skipping tests"
test_results+=("cloud-hypervisor: SKIPPED")
fi
# Report results
section_header "Test Results Summary"
local passed=0
local failed=0
local skipped=0
for result in "${test_results[@]}"; do
if [[ "$result" =~ PASS ]]; then
log_info "$result"
((passed++))
elif [[ "$result" =~ FAIL ]]; then
log_error "$result"
((failed++))
else
log_warn "$result"
((skipped++))
fi
done
log_info "Test summary: ${passed} passed, ${failed} failed, ${skipped} skipped"
if [[ $failed -eq 0 ]]; then
log_info "All tests passed successfully"
return 0
else
log_error "Some tests failed"
return 1
fi
}
# Export functions
export -f testing_qemu_boot testing_qemu_basic_boot testing_qemu_serial_boot testing_qemu_interactive_boot
export -f testing_cloud_hypervisor_boot testing_cloud_hypervisor_basic testing_cloud_hypervisor_serial
export -f testing_analyze_boot_log testing_run_all