first commit

This commit is contained in:
robojerk 2025-08-21 07:31:52 -07:00
commit a61c0e9e0b
20 changed files with 2905 additions and 0 deletions

55
.gitignore vendored Normal file
View file

@ -0,0 +1,55 @@
# Build and temporary directories
build/
work-*/
work/
# Output files and images
output/
*.raw
*.qcow2
*.img
*.iso
*.vmdk
*.vdi
# Container images and tarballs
*.tar
*.tar.gz
*.tar.bz2
# Loop devices and mounts
/dev/loop*
# VM state files
*.xml.bak
*.xml~
# Log files
*.log
*.out
*.err
# Temporary files
*.tmp
*.temp
*~
# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# IDE files
.vscode/
.idea/
*.swp
*.swo
# Package manager files
*.deb
*.rpm
*.pkg

57
bootc-compat.sh Executable file
View file

@ -0,0 +1,57 @@
#!/bin/bash
set -euo pipefail
if [ ! -d "/ostree/repo/objects" ]; then
echo "Initializing ostree repository..."
ostree admin init-fs / || true
ostree admin stateroot-init debian || true
fi
setup_boot() {
echo "Setting up boot configuration..."
if command -v bootctl &> /dev/null; then
bootctl install --path=/boot || true
fi
if command -v update-grub &> /dev/null; then
update-grub || true
fi
}
setup_deployment() {
echo "Setting up deployment structure..."
mkdir -p /var/lib/containers /etc/containers /usr/lib/bootc
cat > /usr/lib/bootc/status.json << EOJSON
{
"apiVersion": "org.containers.bootc/v1alpha1",
"kind": "BootcHost",
"spec": {
"image": {
"image": "localhost/debian-bootc:latest"
}
},
"status": {
"booted": {
"image": {
"image": "localhost/debian-bootc:latest"
}
}
}
}
EOJSON
}
main() {
echo "Starting Debian bootc compatibility layer..."
setup_deployment
setup_boot
echo "Bootc compatibility setup complete."
if [ "${1:-}" = "--init" ]; then
exec /sbin/init
else
exec "$@"
fi
}
main "$@"

283
build-with-cache.sh Executable file
View file

@ -0,0 +1,283 @@
#!/bin/bash
# build-with-cache.sh - Enhanced build script with apt-cacher-ng support
set -euo pipefail
# Configuration
IMAGE_NAME="${CONTAINER_IMAGE:-localhost/debian-bootc:ostree-transformed-v2}"
IMAGE_TAG="latest"
OUTPUT_DIR="./output"
BUILD_DIR="."
# apt-cacher-ng configuration
APT_CACHER_NG_URL="${APT_CACHER_NG_URL:-}"
APT_CACHER_NG_DISCOVERY=true
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_debug() {
echo -e "${BLUE}[DEBUG]${NC} $1"
}
# Detect apt-cacher-ng automatically
detect_apt_cacher_ng() {
if [ -n "$APT_CACHER_NG_URL" ]; then
log_info "Using apt-cacher-ng from environment: $APT_CACHER_NG_URL"
return 0
fi
if [ "$APT_CACHER_NG_DISCOVERY" = true ]; then
log_info "Auto-detecting apt-cacher-ng..."
# Common apt-cacher-ng URLs to try
local urls=(
"http://192.168.1.101:3142"
"http://localhost:3142"
"http://apt-cacher-ng:3142"
"http://cache:3142"
"http://192.168.1.100:3142"
)
for url in "${urls[@]}"; do
if curl -s --connect-timeout 5 "$url/acng-report.html" > /dev/null 2>&1; then
APT_CACHER_NG_URL="$url"
log_info "Found apt-cacher-ng at: $APT_CACHER_NG_URL"
return 0
fi
done
log_warn "No apt-cacher-ng found, using direct connections"
return 1
fi
return 1
}
# Check prerequisites
check_prerequisites() {
log_info "Checking prerequisites..."
local missing_tools=()
for tool in podman buildah qemu-img curl; do
if ! command -v "$tool" &> /dev/null; then
missing_tools+=("$tool")
fi
done
if [ ${#missing_tools[@]} -ne 0 ]; then
log_error "Missing required tools: ${missing_tools[*]}"
log_info "Install them with:"
log_info " sudo apt install podman buildah qemu-utils curl"
exit 1
fi
log_info "All prerequisites satisfied."
}
# Create build directory structure
setup_build_environment() {
log_info "Setting up build environment..."
mkdir -p "$OUTPUT_DIR"
# Check if Dockerfile exists in current directory
if [ ! -f "debian_bootc_dockerfile.txt" ]; then
log_error "debian_bootc_dockerfile.txt not found in current directory"
exit 1
fi
log_info "Using existing debian_bootc_dockerfile.txt"
# Create the compatibility script
cat > "$BUILD_DIR/bootc-compat.sh" << 'EOF'
#!/bin/bash
set -euo pipefail
if [ ! -d "/ostree/repo/objects" ]; then
echo "Initializing ostree repository..."
ostree admin init-fs / || true
ostree admin stateroot-init debian || true
fi
setup_boot() {
echo "Setting up boot configuration..."
if command -v bootctl &> /dev/null; then
bootctl install --path=/boot || true
fi
if command -v update-grub &> /dev/null; then
update-grub || true
fi
}
setup_deployment() {
echo "Setting up deployment structure..."
mkdir -p /var/lib/containers /etc/containers /usr/lib/bootc
cat > /usr/lib/bootc/status.json << EOJSON
{
"apiVersion": "org.containers.bootc/v1alpha1",
"kind": "BootcHost",
"spec": {
"image": {
"image": "localhost/debian-bootc:latest"
}
},
"status": {
"booted": {
"image": {
"image": "localhost/debian-bootc:latest"
}
}
}
}
EOJSON
}
main() {
echo "Starting Debian bootc compatibility layer..."
setup_deployment
setup_boot
echo "Bootc compatibility setup complete."
if [ "${1:-}" = "--init" ]; then
exec /sbin/init
else
exec "$@"
fi
}
main "$@"
EOF
# Create configuration file
cat > "$BUILD_DIR/config.toml" << 'EOF'
[[users]]
name = "debian"
password = "$6$salt123$zKz/hA0eCEjVpNJC4T.nD/OXucJwPh5z9BRNDguk3EAU4isYPV3hEppKfCgZ/XZnSDdk2jxngc05ejbo.FLxV."
groups = ["wheel", "sudo"]
[customizations]
hostname = "debian-bootc"
[customizations.kernel]
append = "console=ttyS0,115200n8 console=tty0"
[customizations.disk]
root_fs_type = "ext4"
[customizations.services]
enabled = ["sshd", "systemd-resolved"]
EOF
log_info "Build environment ready in $BUILD_DIR"
}
# Build container image with apt-cacher-ng support
build_container_image() {
log_info "Building container image with apt-cacher-ng support..."
local build_args=""
if [ -n "$APT_CACHER_NG_URL" ]; then
build_args="--build-arg APT_CACHER_NG_URL=$APT_CACHER_NG_URL"
log_info "Building with apt-cacher-ng: $APT_CACHER_NG_URL"
else
log_info "Building without apt-cacher-ng (direct connections)"
fi
# Extract image name without tag for podman build
local image_name_only=$(echo "$IMAGE_NAME" | cut -d':' -f1)
podman build $build_args -t "$image_name_only" -f debian_bootc_dockerfile.txt .
log_info "Container image built: $image_name_only"
}
# Create QCOW2 image using bootc-image-builder
create_qcow2_image() {
log_info "Creating QCOW2 image using bootc-image-builder..."
# Check if bootc-image-builder is available
if ! podman image exists quay.io/centos-bootc/bootc-image-builder; then
log_info "Pulling bootc-image-builder..."
podman pull quay.io/centos-bootc/bootc-image-builder
fi
# Create the bootable image
sudo podman run --rm -it --privileged \
-v ./output:/output \
-v ./build/config.toml:/config/config.toml:ro \
-v /var/lib/containers/storage:/var/lib/containers/storage \
quay.io/centos-bootc/bootc-image-builder \
--type qcow2 \
localhost/debian-bootc:latest
log_info "QCOW2 image created successfully!"
}
# Export container image
export_container_image() {
log_info "Exporting container image..."
podman save -o "$OUTPUT_DIR/debian-bootc-container.tar" "$IMAGE_NAME:$IMAGE_TAG"
log_info "Container image exported to $OUTPUT_DIR/debian-bootc-container.tar"
}
# Show build information
show_build_info() {
log_info "=== Build Information ==="
log_info "Image: $IMAGE_NAME:$IMAGE_TAG"
log_info "Output Directory: $OUTPUT_DIR"
log_info "Build Directory: $BUILD_DIR"
if [ -n "$APT_CACHER_NG_URL" ]; then
log_info "apt-cacher-ng: $APT_CACHER_NG_URL"
log_info "Cache Status: Enabled"
else
log_info "apt-cacher-ng: Not configured"
log_info "Cache Status: Disabled (direct connections)"
fi
log_info "========================"
}
# Main execution
main() {
log_info "Starting Debian bootc container build with apt-cacher-ng support..."
# Detect apt-cacher-ng
detect_apt_cacher_ng
# Show build information
show_build_info
check_prerequisites
setup_build_environment
build_container_image
log_info "Container build process completed!"
if [ -n "$APT_CACHER_NG_URL" ]; then
log_info "Container built with apt-cacher-ng caching enabled!"
log_info "Cache URL: $APT_CACHER_NG_URL"
fi
}
# Run main function
main "$@"

16
config.toml Normal file
View file

@ -0,0 +1,16 @@
[[users]]
name = "debian"
password = "$6$salt123$zKz/hA0eCEjVpNJC4T.nD/OXucJwPh5z9BRNDguk3EAU4isYPV3hEppKfCgZ/XZnSDdk2jxngc05ejbo.FLxV."
groups = ["wheel", "sudo"]
[customizations]
hostname = "debian-bootc"
[customizations.kernel]
append = "console=ttyS0,115200n8 console=tty0"
[customizations.disk]
root_fs_type = "ext4"
[customizations.services]
enabled = ["sshd", "systemd-resolved"]

171
config/defaults.sh Normal file
View file

@ -0,0 +1,171 @@
#!/bin/bash
# Default configuration for bootc image creation
# This file sets default values that can be overridden by user configuration
# Container configuration
export CONTAINER_IMAGE="${CONTAINER_IMAGE:-localhost/debian-bootc:ostree-transformed-v2}"
export CONTAINER_TAG="${CONTAINER_TAG:-latest}"
# Output configuration
export OUTPUT_DIR="${OUTPUT_DIR:-./output}"
export IMAGE_SIZE_GB="${IMAGE_SIZE_GB:-10}"
export IMAGE_NAME="${IMAGE_NAME:-debian-bootc}"
# Build configuration
export BUILD_TYPE="${BUILD_TYPE:-container}" # container or chroot
export USE_APT_CACHER="${USE_APT_CACHER:-true}"
export APT_CACHER_URL="${APT_CACHER_URL:-http://localhost:3142}"
# OSTree configuration
export OSTREE_BRANCH="${OSTREE_BRANCH:-debian/trixie/x86_64}"
export OSTREE_SUBJECT="${OSTREE_SUBJECT:-Debian trixie system}"
export OSTREE_MODE="${OSTREE_MODE:-bare-user}"
# Bootloader configuration
export BOOTLOADER_TYPE="${BOOTLOADER_TYPE:-grub}" # grub or systemd-boot
export KERNEL_VERSION="${KERNEL_VERSION:-6.12.41+deb13-amd64}"
export CONSOLE_OPTIONS="${CONSOLE_OPTIONS:-console=tty0 console=ttyS0,115200n8}"
# User configuration
export DEFAULT_USER="${DEFAULT_USER:-debian}"
export DEFAULT_PASSWORD="${DEFAULT_PASSWORD:-debian123}"
export USER_UID="${USER_UID:-1000}"
export USER_GID="${USER_GID:-1000}"
# Network configuration
export ENABLE_SSH="${ENABLE_SSH:-true}"
export ENABLE_NETWORK="${ENABLE_NETWORK:-true}"
# Output formats
export OUTPUT_FORMATS="${OUTPUT_FORMATS:-qcow2}" # qcow2, iso, img, vmdk, vdi, all
export KEEP_RAW="${KEEP_RAW:-true}"
# Performance configuration
export PARALLEL_JOBS="${PARALLEL_JOBS:-$(nproc)}"
export COMPRESSION_LEVEL="${COMPRESSION_LEVEL:-6}"
# Validation configuration
export VERIFY_IMAGE="${VERIFY_IMAGE:-true}"
export VERIFY_FILESYSTEM="${VERIFY_FILESYSTEM:-true}"
export VERIFY_BOOTLOADER="${VERIFY_BOOTLOADER:-true}"
# Cleanup configuration
export CLEANUP_WORK_DIR="${CLEANUP_WORK_DIR:-true}"
export CLEANUP_TEMP_FILES="${CLEANUP_TEMP_FILES:-true}"
# Logging configuration
export LOG_LEVEL="${LOG_LEVEL:-info}" # debug, info, warn, error
export VERBOSE="${VERBOSE:-false}"
# Security configuration
export SIGN_IMAGES="${SIGN_IMAGES:-false}"
export GPG_KEY="${GPG_KEY:-}"
# Architecture configuration
export TARGET_ARCH="${TARGET_ARCH:-amd64}"
export TARGET_DEBIAN_RELEASE="${TARGET_DEBIAN_RELEASE:-trixie}"
# Package configuration
export BASE_PACKAGES="${BASE_PACKAGES:-systemd systemd-sysv linux-image-amd64 grub-pc ostree ostree-boot openssh-server sudo}"
export ADDITIONAL_PACKAGES="${ADDITIONAL_PACKAGES:-curl wget vim less man-db}"
# Debian release configuration
export DEBIAN_RELEASE="${DEBIAN_RELEASE:-trixie}" # Default to trixie (Debian 13)
export DEBIAN_RELEASES="trixie forky sid"
export DEBIAN_RELEASE_NAMES="trixie=Debian 13 forky=Debian 14 sid=Debian Unstable"
export DEBIAN_RELEASE_DESCRIPTIONS="trixie=Debian 13 (Trixie) - Testing forky=Debian 14 (Forky) - Unstable sid=Debian Sid - Always Unstable"
# Set TARGET_DEBIAN_RELEASE based on DEBIAN_RELEASE
export TARGET_DEBIAN_RELEASE="$DEBIAN_RELEASE"
# Timeout configuration
export BUILD_TIMEOUT="${BUILD_TIMEOUT:-3600}" # 1 hour
export EXTRACTION_TIMEOUT="${EXTRACTION_TIMEOUT:-1800}" # 30 minutes
export CONVERSION_TIMEOUT="${CONVERSION_TIMEOUT:-900}" # 15 minutes
# Print configuration
print_config() {
echo "=== Bootc Image Creation Configuration ==="
echo "Container: $CONTAINER_IMAGE"
echo "Build Type: $BUILD_TYPE"
echo "Output Directory: $OUTPUT_DIR"
echo "Image Size: ${IMAGE_SIZE_GB}GB"
echo "Output Formats: $OUTPUT_FORMATS"
echo "Bootloader: $BOOTLOADER_TYPE"
echo "Kernel: $KERNEL_VERSION"
echo "User: $DEFAULT_USER:$DEFAULT_PASSWORD"
echo "Architecture: $TARGET_ARCH"
echo "Debian Release: $DEBIAN_RELEASE ($(get_debian_release_description "$DEBIAN_RELEASE"))"
echo "OSTree Branch: $OSTREE_BRANCH"
echo "Use apt-cacher: $USE_APT_CACHER"
echo "Enable SSH: $ENABLE_SSH"
echo "Verify Image: $VERIFY_IMAGE"
echo "Log Level: $LOG_LEVEL"
echo "=========================================="
}
# Validate Debian release
validate_debian_release() {
local release="$1"
for valid_release in $DEBIAN_RELEASES; do
if [ "$release" = "$valid_release" ]; then
return 0
fi
done
return 1
}
# Get Debian release description
get_debian_release_description() {
local release="$1"
echo "$DEBIAN_RELEASE_DESCRIPTIONS" | tr ' ' '\n' | grep "^$release=" | cut -d'=' -f2
}
# Validate configuration
validate_config() {
local errors=()
# Check required values
if [ -z "$CONTAINER_IMAGE" ]; then
errors+=("CONTAINER_IMAGE is required")
fi
if [ -z "$OUTPUT_DIR" ]; then
errors+=("OUTPUT_DIR is required")
fi
if [ -z "$IMAGE_SIZE_GB" ] || ! [[ "$IMAGE_SIZE_GB" =~ ^[0-9]+$ ]]; then
errors+=("IMAGE_SIZE_GB must be a positive integer")
fi
if [ -z "$BUILD_TYPE" ] || ! [[ "$BUILD_TYPE" =~ ^(container|chroot)$ ]]; then
errors+=("BUILD_TYPE must be 'container' or 'chroot'")
fi
if [ -z "$BOOTLOADER_TYPE" ] || ! [[ "$BOOTLOADER_TYPE" =~ ^(grub|systemd-boot)$ ]]; then
errors+=("BOOTLOADER_TYPE must be 'grub' or 'systemd-boot'")
fi
if [ -z "$TARGET_ARCH" ]; then
errors+=("TARGET_ARCH is required")
fi
# Validate Debian release
if [ -z "$DEBIAN_RELEASE" ]; then
errors+=("DEBIAN_RELEASE is required")
elif ! validate_debian_release "$DEBIAN_RELEASE"; then
errors+=("DEBIAN_RELEASE must be one of: $DEBIAN_RELEASES")
fi
# Report errors
if [ ${#errors[@]} -gt 0 ]; then
echo "Configuration validation failed:" >&2
for error in "${errors[@]}"; do
echo " - $error" >&2
done
return 1
fi
return 0
}

161
create-and-boot-vm.sh Executable file
View file

@ -0,0 +1,161 @@
#!/bin/bash
# create-and-boot-vm.sh - Create and boot the debian-bootc VM
set -euo pipefail
VM_NAME="debian-bootc"
VM_XML="debian-bootc-vm.xml"
QCOW2_PATH="/opt/Projects/overseer/alternate_paths/output/debian-bootc.qcow2"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Check prerequisites
check_prerequisites() {
log_info "Checking prerequisites..."
if ! command -v virsh &> /dev/null; then
log_error "virsh not found. Please install libvirt-clients:"
log_info " sudo apt install libvirt-clients qemu-system-x86"
exit 1
fi
if ! command -v qemu-system-x86_64 &> /dev/null; then
log_error "qemu-system-x86_64 not found. Please install qemu:"
log_info " sudo apt install qemu-system-x86"
exit 1
fi
if [ ! -f "$QCOW2_PATH" ]; then
log_error "QCOW2 image not found: $QCOW2_PATH"
exit 1
fi
if [ ! -f "$VM_XML" ]; then
log_error "VM XML configuration not found: $VM_XML"
exit 1
fi
log_info "All prerequisites satisfied."
}
# Check if VM already exists
check_vm_exists() {
if virsh list --all --name | grep -q "^$VM_NAME$"; then
log_warn "VM '$VM_NAME' already exists."
read -p "Do you want to remove it and recreate? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
log_info "Removing existing VM..."
virsh destroy "$VM_NAME" 2>/dev/null || true
virsh undefine "$VM_NAME" 2>/dev/null || true
else
log_info "Using existing VM."
return 0
fi
fi
return 1
}
# Create the VM
create_vm() {
log_info "Creating VM '$VM_NAME'..."
# Check if libvirt is running
if ! systemctl is-active --quiet libvirtd; then
log_warn "libvirtd is not running. Starting it..."
sudo systemctl start libvirtd
sudo systemctl enable libvirtd
fi
# Create the VM from XML
virsh define "$VM_XML"
if [ $? -eq 0 ]; then
log_info "VM '$VM_NAME' created successfully!"
else
log_error "Failed to create VM."
exit 1
fi
}
# Start the VM
start_vm() {
log_info "Starting VM '$VM_NAME'..."
virsh start "$VM_NAME"
if [ $? -eq 0 ]; then
log_info "VM '$VM_NAME' started successfully!"
else
log_error "Failed to start VM."
exit 1
fi
}
# Show VM status
show_vm_status() {
log_info "VM Status:"
virsh list --all | grep "$VM_NAME" || true
log_info "VM Details:"
virsh dominfo "$VM_NAME" 2>/dev/null || true
}
# Show connection info
show_connection_info() {
log_info "=== Connection Information ==="
log_info "VM Name: $VM_NAME"
log_info "QCOW2 Image: $QCOW2_PATH"
# Get VNC port
VNC_PORT=$(virsh vncdisplay "$VM_NAME" 2>/dev/null | cut -d: -f2 || echo "N/A")
if [ "$VNC_PORT" != "N/A" ]; then
log_info "VNC Display: :$VNC_PORT"
log_info "VNC URL: vnc://localhost:$VNC_PORT"
fi
log_info "Serial Console: virsh console $VM_NAME"
log_info "SSH (if network works): ssh debian@<VM_IP>"
log_info "Login Credentials: debian / debian123"
log_info "================================"
}
# Main execution
main() {
log_info "Creating and booting debian-bootc VM..."
check_prerequisites
if ! check_vm_exists; then
create_vm
fi
start_vm
show_vm_status
show_connection_info
log_info "VM is now running!"
log_info "Use 'virsh console $VM_NAME' to access the serial console"
log_info "Use 'virsh destroy $VM_NAME' to stop the VM"
log_info "Use 'virsh undefine $VM_NAME' to remove the VM"
}
# Run main function
main "$@"

350
create-bootc-image.sh Executable file
View file

@ -0,0 +1,350 @@
#!/bin/bash
# Main orchestration script for creating bootc images
# This script uses modular components to create bootable images from containers or chroot
set -e
# Source configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/config/defaults.sh"
# Source all modules
source "$SCRIPT_DIR/modules/common.sh"
source "$SCRIPT_DIR/modules/disk.sh"
source "$SCRIPT_DIR/modules/filesystem.sh"
source "$SCRIPT_DIR/modules/bootloader.sh"
source "$SCRIPT_DIR/modules/formats.sh"
source "$SCRIPT_DIR/modules/chroot.sh"
# Mark common as loaded
COMMON_LOADED=true
# Main workflow functions
create_container_image() {
log_info "Creating container image..."
if [ "$USE_APT_CACHER" = "true" ]; then
log_info "Building with apt-cacher-ng support..."
if command -v ./build-with-cache.sh >/dev/null 2>&1; then
./build-with-cache.sh
else
log_warn "build-with-cache.sh not found, falling back to direct build"
podman build -t "$CONTAINER_IMAGE" -f debian_bootc_dockerfile.txt .
fi
else
log_info "Building container directly..."
podman build -t "$CONTAINER_IMAGE" -f debian_bootc_dockerfile.txt .
fi
log_info "Container image created: $CONTAINER_IMAGE"
}
create_chroot_image() {
log_info "Creating chroot-based image..."
# Create chroot environment
create_chroot_environment
# Install packages
install_chroot_packages
# Initialize OSTree
init_ostree_repository
create_ostree_commit
deploy_ostree_system
# Configure bootloader
configure_chroot_bootloader
log_info "Chroot-based image created"
}
create_disk_image() {
log_info "Creating disk image..."
# Create and partition disk
create_disk_image_work
create_essential_directories
log_info "Disk image created and partitioned"
}
extract_filesystem() {
log_info "Extracting filesystem..."
if [ "$BUILD_TYPE" = "container" ]; then
# Extract from container
extract_container_filesystem
else
# Copy from chroot
copy_chroot_filesystem
fi
# Fix permissions
fix_file_permissions
# Verify integrity
if [ "$VERIFY_FILESYSTEM" = "true" ]; then
verify_filesystem_integrity
fi
log_info "Filesystem extraction completed"
}
install_bootloader() {
log_info "Installing bootloader..."
if [ "$BOOTLOADER_TYPE" = "grub" ]; then
install_grub_bootloader
else
install_systemd_boot
fi
# Verify bootloader
if [ "$VERIFY_BOOTLOADER" = "true" ]; then
verify_bootloader
fi
log_info "Bootloader installation completed"
}
convert_formats() {
log_info "Converting to output formats..."
case "$OUTPUT_FORMATS" in
"qcow2")
convert_to_qcow2
;;
"iso")
convert_to_iso
;;
"img")
convert_to_img
;;
"vmdk")
convert_to_vmdk
;;
"vdi")
convert_to_vdi
;;
"all")
convert_to_all_formats
;;
*)
log_error "Unknown output format: $OUTPUT_FORMATS"
exit 1
;;
esac
log_info "Format conversion completed"
}
cleanup_work() {
log_info "Cleaning up work environment..."
if [ "$CLEANUP_WORK_DIR" = "true" ]; then
cleanup
fi
if [ "$BUILD_TYPE" = "chroot" ]; then
cleanup_chroot
fi
log_info "Cleanup completed"
}
# Main execution function
main() {
log_info "Starting bootc image creation..."
# Print configuration
print_config
# Validate configuration
if ! validate_config; then
exit 1
fi
# Setup cleanup
setup_cleanup
# Create output directory
create_output_dir
# Create work directory
create_work_dir
# Check prerequisites
check_prerequisites
# Create source image (container or chroot)
if [ "$BUILD_TYPE" = "container" ]; then
create_container_image
else
create_chroot_image
fi
# Create disk image
create_disk_image
# Extract filesystem
extract_filesystem
# Get the loop device from the disk module
# The disk module should have set loop_dev, but we need to ensure it's available
if [ -z "$loop_dev" ]; then
# Try to find the loop device by looking at the raw image
if [ -f "$OUTPUT_DIR/debian-bootc.raw" ]; then
loop_dev=$(sudo losetup --find --show "$OUTPUT_DIR/debian-bootc.raw")
log_info "Found loop device: $loop_dev"
else
log_error "Cannot find loop device or raw image"
exit 1
fi
fi
# Install bootloader
install_bootloader
# Convert to output formats
convert_formats
# Verify final image
if [ "$VERIFY_IMAGE" = "true" ]; then
verify_disk_integrity
fi
# Show final results
show_format_info
# Cleanup
cleanup_work
log_info "Bootc image creation completed successfully!"
log_info "Output directory: $OUTPUT_DIR"
}
# Show usage
show_usage() {
cat << EOF
Usage: $0 [OPTIONS]
Create a bootable bootc image from container or chroot.
OPTIONS:
-t, --type TYPE Build type: container or chroot (default: container)
-f, --format FORMAT Output format: qcow2, iso, img, vmdk, vdi, all (default: qcow2)
-s, --size SIZE Image size in GB (default: 10)
-o, --output DIR Output directory (default: ./output)
-c, --container IMAGE Container image name (default: localhost/debian-bootc:ostree-transformed-v2)
-b, --bootloader TYPE Bootloader type: grub or systemd-boot (default: grub)
-a, --arch ARCH Target architecture (default: amd64)
-r, --release RELEASE Debian release: trixie, forky, sid (default: trixie)
-u, --user USER Default username (default: debian)
-p, --password PASS Default password (default: debian123)
-n, --no-cache Disable apt-cacher-ng
-v, --verbose Enable verbose output
-h, --help Show this help message
EXAMPLES:
# Create QCOW2 image from container
$0 -t container -f qcow2
# Create ISO image from chroot
$0 -t chroot -f iso -s 20
# Create all formats from container
$0 -t container -f all -o ./my-images
# Custom configuration
BUILD_TYPE=chroot OUTPUT_FORMATS=iso $0
CONFIGURATION:
Environment variables can be used to override defaults:
- BUILD_TYPE: container or chroot
- OUTPUT_FORMATS: qcow2, iso, img, vmdk, vdi, all
- IMAGE_SIZE_GB: Image size in gigabytes
- OUTPUT_DIR: Output directory
- CONTAINER_IMAGE: Container image name
- BOOTLOADER_TYPE: grub or systemd-boot
- TARGET_ARCH: Target architecture
- TARGET_DEBIAN_RELEASE: Debian release
- DEFAULT_USER: Default username
- DEFAULT_PASSWORD: Default password
- USE_APT_CACHER: Enable/disable apt-cacher-ng
EOF
}
# Parse command line arguments
parse_args() {
while [[ $# -gt 0 ]]; do
case $1 in
-t|--type)
BUILD_TYPE="$2"
shift 2
;;
-f|--format)
OUTPUT_FORMATS="$2"
shift 2
;;
-s|--size)
IMAGE_SIZE_GB="$2"
shift 2
;;
-o|--output)
OUTPUT_DIR="$2"
shift 2
;;
-c|--container)
CONTAINER_IMAGE="$2"
shift 2
;;
-b|--bootloader)
BOOTLOADER_TYPE="$2"
shift 2
;;
-a|--arch)
TARGET_ARCH="$2"
shift 2
;;
-r|--release)
DEBIAN_RELEASE="$2"
shift 2
;;
-u|--user)
DEFAULT_USER="$2"
shift 2
;;
-p|--password)
DEFAULT_PASSWORD="$2"
shift 2
;;
-n|--no-cache)
USE_APT_CACHER="false"
shift
;;
-v|--verbose)
VERBOSE="true"
LOG_LEVEL="debug"
shift
;;
-h|--help)
show_usage
exit 0
;;
*)
log_error "Unknown option: $1"
show_usage
exit 1
;;
esac
done
}
# Run main function if script is executed directly
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
parse_args "$@"
main
fi

121
debian-bootc-vm.xml Normal file
View file

@ -0,0 +1,121 @@
<?xml version="1.0" encoding="UTF-8"?>
<domain type="kvm">
<name>debian-bootc</name>
<uuid>12345678-1234-1234-1234-123456789abc</uuid>
<title>Debian Bootc OSTree System</title>
<description>Debian bootc container with OSTree support</description>
<memory unit="GiB">2</memory>
<currentMemory unit="GiB">2</currentMemory>
<vcpu>2</vcpu>
<maxvcpu>4</maxvcpu>
<os>
<type arch="x86_64" machine="pc-q35-8.0">hvm</type>
<boot dev="hd"/>
<boot dev="cdrom"/>
<bootmenu enable="yes" timeout="3000"/>
</os>
<features>
<acpi/>
<apic/>
</features>
<cpu mode="host-model" check="partial"/>
<clock offset="utc">
<timer name="rtc" tickpolicy="catchup"/>
<timer name="pit" tickpolicy="delay"/>
<timer name="hpet" present="no"/>
</clock>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/bin/qemu-system-x86_64</emulator>
<!-- Disk -->
<disk type="file" device="disk">
<driver name="qemu" type="raw" cache="writeback"/>
<source file="/opt/Projects/overseer/alternate_paths/output/debian-bootc-simple.raw"/>
<target dev="sda" bus="sata"/>
<address type="drive" controller="0" bus="0" target="0" unit="0"/>
</disk>
<!-- Network (temporarily disabled due to conflict) -->
<!--
<interface type="network">
<source network="default"/>
<model type="virtio"/>
<address type="pci" domain="0x0000" bus="0x01" slot="0x00" function="0x0"/>
</interface>
-->
<!-- Graphics -->
<graphics type="vnc" port="-1" autoport="yes" listen="0.0.0.0">
<listen type="address" address="0.0.0.0"/>
</graphics>
<!-- Serial Console -->
<serial type="pty">
<target type="isa-serial" port="0">
<model name="isa-serial"/>
</target>
</serial>
<!-- Console -->
<console type="pty">
<target type="serial" port="0"/>
</console>
<!-- Input Devices -->
<input type="tablet" bus="usb">
<address type="usb" bus="0" port="1"/>
</input>
<input type="keyboard" bus="usb">
<address type="usb" bus="0" port="2"/>
</input>
<!-- USB Controller -->
<controller type="usb" index="0" model="qemu-xhci">
<address type="pci" domain="0x0000" bus="0x02" slot="0x00" function="0x0"/>
</controller>
<!-- SATA Controller -->
<controller type="sata" index="0">
<address type="pci" domain="0x0000" bus="0x00" slot="0x1f" function="0x2"/>
</controller>
<!-- PCI Bridge -->
<controller type="pci" index="0" model="pcie-root"/>
<controller type="pci" index="1" model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="1" port="0x8"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x01" function="0x0" multifunction="on"/>
</controller>
<controller type="pci" index="2" model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="2" port="0x9"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x01" function="0x1"/>
</controller>
<controller type="pci" index="3" model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="3" port="0xa"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x01" function="0x2"/>
</controller>
<controller type="pci" index="4" model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="4" port="0xb"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x01" function="0x3"/>
</controller>
<!-- RNG for entropy -->
<rng model="virtio">
<backend model="random">/dev/urandom</backend>
<address type="pci" domain="0x0000" bus="0x03" slot="0x00" function="0x0"/>
</rng>
</devices>
</domain>

142
debian_bootc_dockerfile.txt Normal file
View file

@ -0,0 +1,142 @@
FROM debian:trixie-slim
# Install essential packages for bootc compatibility
RUN apt-get update && apt-get install -y \
ostree \
ostree-boot \
systemd \
systemd-boot \
linux-image-amd64 \
grub-efi-amd64 \
openssh-server \
sudo \
curl \
wget \
ca-certificates \
polkitd \
pkexec \
libpolkit-gobject-1-0 \
&& rm -rf /var/lib/apt/lists/*
# Download and install bootc package
RUN wget https://git.raines.xyz/robojerk/-/packages/debian/bootc/1.6.0-1~trixie1/files/495 -O bootc_1.6.0-1~trixie1_amd64.deb && \
dpkg -i bootc_1.6.0-1~trixie1_amd64.deb && \
rm bootc_1.6.0-1~trixie1_amd64.deb
# Create a default user
RUN useradd -m -s /bin/bash -G sudo debian && \
echo "debian:debian123" | chpasswd
# Configure SSH
RUN mkdir -p /home/debian/.ssh && \
chmod 700 /home/debian/.ssh && \
chown debian:debian /home/debian/.ssh
# ===== OSTREE FILESYSTEM TRANSFORMATION =====
# This is the critical step that transforms traditional Debian to OSTree
# Initialize OSTree repository
RUN mkdir -p /ostree/repo && \
ostree init --repo=/ostree/repo --mode=bare-user
# Create OSTree deployment structure
RUN ostree admin init-fs / && \
ostree admin stateroot-init debian
# Create a simple OSTree commit from the current filesystem
RUN mkdir -p /tmp/ostree-commit && \
cd /tmp/ostree-commit && \
# Copy only the files we want in OSTree (exclude special filesystems)
cp -r /bin . && \
cp -r /lib . && \
cp -r /lib64 . && \
cp -r /sbin . && \
cp -r /usr . && \
cp -r /etc . && \
cp -r /var . && \
cp -r /home . && \
cp -r /root . && \
cp -r /boot . && \
# Create essential directories properly
mkdir -p proc && \
mkdir -p sys && \
mkdir -p dev && \
mkdir -p tmp && \
mkdir -p run && \
mkdir -p media && \
mkdir -p mnt && \
mkdir -p ostree && \
# Create OSTree-expected kernel locations
mkdir -p usr/lib/ostree-boot && \
# Debug: check what's in boot directory
echo "Boot directory contents:" && ls -la boot/ && \
# Move kernel and initrd to OSTree-expected location
if [ -f boot/vmlinuz-6.12.41+deb13-amd64 ]; then \
cp boot/vmlinuz-6.12.41+deb13-amd64 usr/lib/ostree-boot/ && \
echo "Kernel copied successfully"; \
else \
echo "Kernel not found!" && \
find boot/ -name "*vmlinuz*" -o -name "*kernel*" 2>/dev/null; \
fi && \
if [ -f boot/initrd.img-6.12.41+deb13-amd64 ]; then \
cp boot/initrd.img-6.12.41+deb13-amd64 usr/lib/ostree-boot/ && \
echo "Initrd copied successfully"; \
else \
echo "Initrd not found!" && \
find boot/ -name "*initrd*" 2>/dev/null; \
fi && \
# Create the commit
ostree commit \
--repo=/ostree/repo \
--branch=debian/trixie/x86_64 \
--subject="Debian trixie system" \
--tree=dir=. && \
echo "OSTree commit created successfully" && \
# Clean up
cd / && rm -rf /tmp/ostree-commit
# Deploy the OSTree commit to create proper deployment structure
# Note: Deployment will be done at runtime when the container boots
RUN echo "OSTree commit created, deployment will be done at runtime" && \
echo "Commit hash: $(ostree rev-parse --repo=/ostree/repo debian/trixie/x86_64)"
# Configure OSTree
RUN mkdir -p /etc/ostree && \
echo "[origin]" > /etc/ostree/remotes.d/origin.conf && \
echo "repo=/ostree/repo" >> /etc/ostree/remotes.d/origin.conf
# Configure bootloader
RUN mkdir -p /boot/loader/entries
# Add bootc compatibility layer script
COPY bootc-compat.sh /usr/local/bin/bootc-compat.sh
RUN chmod +x /usr/local/bin/bootc-compat.sh
# Set up bootc status directory
RUN mkdir -p /usr/lib/bootc
# Create bootc status file
RUN echo '{' > /usr/lib/bootc/status.json && \
echo ' "apiVersion": "org.containers.bootc/v1alpha1",' >> /usr/lib/bootc/status.json && \
echo ' "kind": "BootcHost",' >> /usr/lib/bootc/status.json && \
echo ' "spec": {' >> /usr/lib/bootc/status.json && \
echo ' "image": {' >> /usr/lib/bootc/status.json && \
echo ' "image": "localhost/debian-bootc:latest"' >> /usr/lib/bootc/status.json && \
echo ' }' >> /usr/lib/bootc/status.json && \
echo ' },' >> /usr/lib/bootc/status.json && \
echo ' "status": {' >> /usr/lib/bootc/status.json && \
echo ' "booted": {' >> /usr/lib/bootc/status.json && \
echo ' "image": {' >> /usr/lib/bootc/status.json && \
echo ' "image": "localhost/debian-bootc:latest",' >> /usr/lib/bootc/status.json && \
echo ' "imageDigest": "sha256:$(echo -n '\''debian-bootc'\'' | sha256sum | cut -d'\'' '\'' -f1)"' >> /usr/lib/bootc/status.json && \
echo ' }' >> /usr/lib/bootc/status.json && \
echo ' }' >> /usr/lib/bootc/status.json && \
echo ' }' >> /usr/lib/bootc/status.json && \
echo '}' >> /usr/lib/bootc/status.json
# Set proper labels
LABEL bootc.filesystem="ext4"
LABEL bootc.architecture="x86_64"
LABEL ostree.commit="debian/trixie/x86_64"
CMD ["/usr/local/bin/bootc-compat.sh"]

12
default-network.xml Normal file
View file

@ -0,0 +1,12 @@
<network>
<name>default</name>
<uuid>12345678-1234-1234-1234-123456789abc</uuid>
<forward mode='nat'/>
<bridge name='virbr0' stp='on' delay='0'/>
<ip address='192.168.122.1' netmask='255.255.255.0'>
<dhcp>
<range start='192.168.122.2' end='192.168.122.254'/>
</dhcp>
</ip>
</network>

226
justfile Normal file
View file

@ -0,0 +1,226 @@
# Justfile for bootc image creation
# Provides user-friendly commands for creating bootable images
# Default configuration
default:
@just --list
# Create QCOW2 image from container (default)
qcow2:
@echo "Creating QCOW2 image from container..."
./create-bootc-image.sh -t container -f qcow2
# Create QCOW2 image from chroot
qcow2-chroot:
@echo "Creating QCOW2 image from chroot..."
./create-bootc-image.sh -t chroot -f qcow2
# Create QCOW2 image from chroot with specific Debian release
qcow2-chroot-release release="trixie":
@echo "Creating QCOW2 image from chroot using Debian {{release}}..."
DEBIAN_RELEASE={{release}} ./create-bootc-image.sh -t chroot -f qcow2
# Create ISO image from container
iso:
@echo "Creating ISO image from container..."
./create-bootc-image.sh -t container -f iso
# Create ISO image from chroot
iso-chroot:
@echo "Creating ISO image from chroot..."
./create-bootc-image.sh -t chroot -f iso
# Create IMG (raw) image from container
img:
@echo "Creating IMG image from container..."
./create-bootc-image.sh -t container -f img
# Create IMG (raw) image from chroot
img-chroot:
@echo "Creating IMG image from chroot..."
./create-bootc-image.sh -t chroot -f img
# Create all formats from container
all:
@echo "Creating all formats from container..."
./create-bootc-image.sh -t container -f all
# Create all formats from chroot
all-chroot:
@echo "Creating all formats from chroot..."
./create-bootc-image.sh -t chroot -f all
# Create VMDK image from container
vmdk:
@echo "Creating VMDK image from container..."
./create-bootc-image.sh -t container -f vmdk
# Create VDI image from container
vdi:
@echo "Creating VDI image from container..."
./create-bootc-image.sh -t container -f vdi
# Create custom image with specific size
custom size="20" format="qcow2":
@echo "Creating {{format}} image with size {{size}}GB from container..."
./create-bootc-image.sh -t container -f {{format}} -s {{size}}
# Create custom image from chroot with specific size
custom-chroot size="20" format="qcow2":
@echo "Creating {{format}} image with size {{size}}GB from chroot..."
./create-bootc-image.sh -t chroot -f {{format}} -s {{size}}
# Create custom image from chroot with specific size and Debian release
custom-chroot-release size="20" format="qcow2" release="trixie":
@echo "Creating {{format}} image with size {{size}}GB from chroot using Debian {{release}}..."
DEBIAN_RELEASE={{release}} ./create-bootc-image.sh -t chroot -f {{format}} -s {{size}}
# Build container only
build:
@echo "Building container image..."
./build-with-cache.sh
# Build container without cache
build-no-cache:
@echo "Building container image without cache..."
BUILD_TYPE=container USE_APT_CACHER=false ./create-bootc-image.sh -t container -f qcow2
# Setup apt-cacher-ng
setup-cache:
@echo "Setting up apt-cacher-ng..."
./setup-apt-cacher-ng.sh
# Test container
test:
@echo "Testing container..."
./test-bootc-container.sh
# Create and boot VM
vm:
@echo "Creating and booting VM..."
./create-and-boot-vm.sh
# Clean output directory
clean:
@echo "Cleaning output directory..."
rm -rf output/*
# Clean work directories
clean-work:
@echo "Cleaning work directories..."
rm -rf work-* simple-work-* ostree-work-*
# Clean everything
clean-all: clean clean-work
@echo "All cleanup completed"
# Show cleanup examples
cleanup-examples:
@echo "Cleanup Examples:"
@echo " # After successful build, clean work files"
@echo " just clean-work"
@echo ""
@echo " # Before new build, clean everything"
@echo " just clean-all"
@echo ""
@echo " # Quick cleanup of just output files"
@echo " just clean"
# Show configuration
config:
@echo "Current configuration:"
@echo "Configuration can be viewed by running:"
@echo " ./create-bootc-image.sh --help"
@echo ""
@echo "Or check the defaults file:"
@echo " cat config/defaults.sh"
# Show available formats
formats:
@echo "Available output formats:"
@echo " qcow2 - QEMU Copy-On-Write (default)"
@echo " iso - Bootable ISO image"
@echo " img - Raw disk image"
@echo " vmdk - VMware disk format"
@echo " vdi - VirtualBox disk format"
@echo " all - All formats"
# Show build types
types:
@echo "Available build types:"
@echo " container - Extract from container image (default)"
@echo " chroot - Build from chroot environment"
# Show available Debian releases
releases:
@echo "Available Debian releases:"
@echo " trixie - Debian 13 (Testing) - DEFAULT"
@echo " forky - Debian 14 (Unstable)"
@echo " sid - Debian Sid (Always Unstable)"
# Show examples
examples:
@echo "Example commands:"
@echo " just qcow2 # Create QCOW2 from container"
@echo " just iso-chroot # Create ISO from chroot"
@echo " just custom 15 iso # Create 15GB ISO from container"
@echo " just all # Create all formats from container"
@echo " just vm # Create and boot VM"
@echo ""
@echo "Debian release examples:"
@echo " just qcow2-chroot-release forky # Create QCOW2 from chroot using Debian 14"
@echo " just custom-chroot-release 25 iso trixie # Create 25GB ISO from chroot using Debian 13"
@echo " DEBIAN_RELEASE=sid just qcow2-chroot # Use Debian Sid via environment variable"
# Show help
help:
@echo "Bootc Image Creation Commands"
@echo "============================="
@echo ""
@echo "Basic Commands:"
@echo " just qcow2 # Create QCOW2 image (default)"
@echo " just iso # Create ISO image"
@echo " just img # Create IMG image"
@echo " just all # Create all formats"
@echo ""
@echo "Chroot Commands:"
@echo " just qcow2-chroot # Create QCOW2 from chroot"
@echo " just iso-chroot # Create ISO from chroot"
@echo " just img-chroot # Create IMG from chroot"
@echo " just all-chroot # Create all formats from chroot"
@echo ""
@echo "Debian Release Commands:"
@echo " just qcow2-chroot-release forky # Create QCOW2 from chroot using Debian 14"
@echo " just qcow2-chroot-release sid # Create QCOW2 from chroot using Debian Sid"
@echo " just custom-chroot-release 25 iso trixie # Create 25GB ISO from chroot using Debian 13"
@echo ""
@echo "Custom Commands:"
@echo " just custom 20 iso # Create 20GB ISO from container"
@echo " just custom-chroot 15 qcow2 # Create 15GB QCOW2 from chroot"
@echo ""
@echo "Utility Commands:"
@echo " just build # Build container only"
@echo " just vm # Create and boot VM"
@echo " just clean # Clean output files"
@echo " just clean-work # Clean work directories"
@echo " just clean-all # Clean everything"
@echo " just cleanup-examples # Show cleanup examples"
@echo " just config # Show configuration"
@echo " just formats # Show available formats"
@echo " just types # Show build types"
@echo " just releases # Show available Debian releases"
@echo " just examples # Show examples"
@echo ""
@echo "Environment Variables:"
@echo " DEBIAN_RELEASE # Set Debian release (trixie, forky, sid)"
@echo " BUILD_TYPE # Set build type (container, chroot)"
@echo " OUTPUT_FORMATS # Set output format (qcow2, iso, img, vmdk, vdi, all)"
@echo ""
@echo "For more options, run: ./create-bootc-image.sh --help"
# List all available commands
list:
@echo "Available commands:"
@just --list

236
modules/bootloader.sh Normal file
View file

@ -0,0 +1,236 @@
#!/bin/bash
# Bootloader management module for bootc image creation
# This module handles GRUB installation and configuration
# Common functions are sourced by the main script
# Install GRUB bootloader
install_grub_bootloader() {
log_info "Installing bootloader..."
# Check if kernel exists
if [ -f "$WORK_DIR/mnt/boot/vmlinuz-6.12.41+deb13-amd64" ]; then
log_info "Kernel found in /boot location"
KERNEL_PATH="boot/vmlinuz-6.12.41+deb13-amd64"
INITRD_PATH="boot/initrd.img-6.12.41+deb13-amd64"
elif [ -f "$WORK_DIR/mnt/usr/lib/ostree-boot/vmlinuz-6.12.41+deb13-amd64" ]; then
log_info "Kernel found in OSTree location"
KERNEL_PATH="usr/lib/ostree-boot/vmlinuz-6.12.41+deb13-amd64"
INITRD_PATH="usr/lib/ostree-boot/initrd.img-6.12.41+deb13-amd64"
else
log_error "Kernel not found in expected locations"
log_info "Searching for kernel files..."
find "$WORK_DIR/mnt" -name "*vmlinuz*" -o -name "*kernel*" 2>/dev/null | head -10
exit 1
fi
# Install GRUB bootloader
log_info "Installing GRUB bootloader..."
# Create GRUB directory
sudo mkdir -p "$WORK_DIR/mnt/boot/grub"
# Temporarily unmount and remount for safer GRUB installation
log_info "Temporarily unmounting filesystem for GRUB installation..."
sudo umount "$WORK_DIR/mnt"
# Get the loop device from the disk module
if [ -z "$loop_dev" ]; then
log_error "Loop device not set. Cannot install bootloader."
return 1
fi
# Ensure the loop device path is correct
local device_path="${loop_dev}"
if [[ "$device_path" == /dev/* ]]; then
device_path="${device_path#/dev/}"
fi
log_info "Loop device: $loop_dev, device path: $device_path"
log_info "Mounting partition /dev/${device_path}p2"
sudo mount "/dev/${device_path}p2" "$WORK_DIR/mnt"
# Install GRUB to the disk
log_info "Installing GRUB to /dev/$device_path..."
if sudo grub-install --target=i386-pc --boot-directory="$WORK_DIR/mnt/boot" "/dev/$device_path"; then
log_info "GRUB installed successfully"
else
log_warn "GRUB installation failed, trying alternative method..."
# Try installing to the partition instead
if sudo grub-install --target=i386-pc --boot-directory="$WORK_DIR/mnt/boot" "/dev/${device_path}p2"; then
log_info "GRUB installed to partition successfully"
else
log_error "GRUB installation failed completely"
return 1
fi
fi
# Create GRUB configuration
log_info "Creating GRUB configuration..."
sudo tee "$WORK_DIR/mnt/boot/grub/grub.cfg" > /dev/null << EOF
set timeout=5
set default=0
menuentry "Debian Bootc" {
linux /$KERNEL_PATH root=/dev/sda2 rw console=tty0 console=ttyS0,115200n8
initrd /$INITRD_PATH
}
EOF
log_info "Bootloader installation completed"
}
# Install systemd-boot (for UEFI systems)
install_systemd_boot() {
log_info "Installing systemd-boot..."
# Create bootloader entries directory
sudo mkdir -p "$WORK_DIR/mnt/boot/loader/entries"
# Create bootloader entry
sudo tee "$WORK_DIR/mnt/boot/loader/entries/debian-bootc.conf" > /dev/null << EOF
title Debian Bootc
version 1
linux /ostree/debian-bootc/vmlinuz-6.12.41+deb13-amd64
initrd /ostree/debian-bootc/initramfs-6.12.41+deb13-amd64.img
options ostree=/ostree/boot.0/debian-bootc/0 rw console=tty0 console=ttyS0,115200n8
EOF
# Create loader configuration
sudo tee "$WORK_DIR/mnt/boot/loader/loader.conf" > /dev/null << EOF
default debian-bootc
timeout 5
editor no
EOF
log_info "systemd-boot installation completed"
}
# Verify bootloader installation
verify_bootloader() {
log_info "Verifying bootloader installation..."
# Check GRUB configuration
if [ -f "$WORK_DIR/mnt/boot/grub/grub.cfg" ]; then
log_info "GRUB configuration found"
else
log_error "GRUB configuration not found"
return 1
fi
# Check GRUB core image
if [ -f "$WORK_DIR/mnt/boot/grub/i386-pc/core.img" ]; then
log_info "GRUB core image found"
else
log_warn "GRUB core image not found - bootloader may not work"
fi
# Check kernel and initrd
if [ -f "$WORK_DIR/mnt/boot/vmlinuz-6.12.41+deb13-amd64" ]; then
log_info "Kernel found: vmlinuz-6.12.41+deb13-amd64"
else
log_error "Kernel not found"
return 1
fi
if [ -f "$WORK_DIR/mnt/boot/initrd.img-6.12.41+deb13-amd64" ]; then
log_info "Initrd found: initrd.img-6.12.41+deb13-amd64"
else
log_error "Initrd not found"
return 1
fi
log_info "Bootloader verification completed successfully"
return 0
}
# Show bootloader information
show_bootloader_info() {
log_info "Bootloader information:"
echo "GRUB configuration:"
if [ -f "$WORK_DIR/mnt/boot/grub/grub.cfg" ]; then
cat "$WORK_DIR/mnt/boot/grub/grub.cfg"
else
echo "GRUB configuration not found"
fi
echo ""
echo "Boot directory contents:"
ls -la "$WORK_DIR/mnt/boot/"
echo ""
echo "GRUB directory contents:"
if [ -d "$WORK_DIR/mnt/boot/grub" ]; then
ls -la "$WORK_DIR/mnt/boot/grub/"
else
echo "GRUB directory not found"
fi
}
# Customize GRUB configuration
customize_grub_config() {
local custom_config="$1"
if [ -n "$custom_config" ] && [ -f "$custom_config" ]; then
log_info "Applying custom GRUB configuration..."
sudo cp "$custom_config" "$WORK_DIR/mnt/boot/grub/grub.cfg"
log_info "Custom GRUB configuration applied"
else
log_warn "No custom GRUB configuration provided or file not found"
fi
}
# Set GRUB timeout
set_grub_timeout() {
local timeout="${1:-5}"
log_info "Setting GRUB timeout to ${timeout} seconds..."
# Update the existing grub.cfg with new timeout
sudo sed -i "s/set timeout=.*/set timeout=$timeout/" "$WORK_DIR/mnt/boot/grub/grub.cfg"
log_info "GRUB timeout set to ${timeout} seconds"
}
# Add custom GRUB menu entries
add_grub_menu_entry() {
local title="$1"
local kernel_path="$2"
local initrd_path="$3"
local root_device="${4:-/dev/sda2}"
local extra_params="${5:-}"
log_info "Adding GRUB menu entry: $title"
# Append to grub.cfg
sudo tee -a "$WORK_DIR/mnt/boot/grub/grub.cfg" > /dev/null << EOF
menuentry "$title" {
linux /$kernel_path root=$root_device rw console=tty0 console=ttyS0,115200n8 $extra_params
initrd /$initrd_path
}
EOF
log_info "GRUB menu entry added: $title"
}
# Print module usage
print_module_usage() {
echo "Usage: source modules/bootloader.sh"
echo "This module handles bootloader installation and configuration."
echo ""
echo "Available functions:"
echo " install_bootloader - Install GRUB bootloader"
echo " install_systemd_boot - Install systemd-boot (UEFI)"
echo " verify_bootloader - Verify bootloader installation"
echo " show_bootloader_info - Display bootloader information"
echo " customize_grub_config - Apply custom GRUB configuration"
echo " set_grub_timeout - Set GRUB timeout value"
echo " add_grub_menu_entry - Add custom GRUB menu entries"
echo ""
echo "Required variables:"
echo " WORK_DIR - Working directory for operations"
echo " loop_dev - Loop device for disk operations"
}

215
modules/chroot.sh Normal file
View file

@ -0,0 +1,215 @@
#!/bin/bash
# Chroot-based OSTree creation module for bootc image creation
# This module implements the debian-ostree-builder approach using chroot
# Common functions are sourced by the main script
# Create chroot environment
create_chroot_environment() {
log_info "Creating chroot environment..."
# Create chroot directory
local chroot_dir="$WORK_DIR/chroot"
mkdir -p "$chroot_dir"
# Install debootstrap if not available
if ! command -v debootstrap >/dev/null 2>&1; then
log_info "Installing debootstrap..."
sudo apt update
sudo apt install -y debootstrap
fi
# Create base Debian system
log_info "Creating base Debian system with debootstrap..."
sudo debootstrap --arch=amd64 --variant=minbase "$TARGET_DEBIAN_RELEASE" "$chroot_dir" http://deb.debian.org/debian/
# Mount necessary filesystems
log_info "Mounting necessary filesystems..."
sudo mount --bind /dev "$chroot_dir/dev"
sudo mount --bind /proc "$chroot_dir/proc"
sudo mount --bind /sys "$chroot_dir/sys"
sudo mount --bind /dev/pts "$chroot_dir/dev/pts"
log_info "Chroot environment created at: $chroot_dir"
}
# Install packages in chroot
install_chroot_packages() {
log_info "Installing packages in chroot..."
local chroot_dir="$WORK_DIR/chroot"
# Update package lists
sudo chroot "$chroot_dir" apt update
# Install essential packages
sudo chroot "$chroot_dir" apt install -y \
systemd \
systemd-sysv \
linux-image-amd64 \
linux-headers-amd64 \
grub-pc \
ostree \
ostree-boot \
network-manager \
openssh-server \
sudo \
curl \
wget \
vim \
less \
man-db
# Clean up package cache
sudo chroot "$chroot_dir" apt clean
log_info "Package installation completed"
}
# Initialize OSTree repository in chroot
init_ostree_repository() {
log_info "Initializing OSTree repository in chroot..."
local chroot_dir="$WORK_DIR/chroot"
# Initialize OSTree repository
sudo chroot "$chroot_dir" ostree init --repo=/ostree/repo --mode=bare-user
# Create stateroot for Debian
sudo chroot "$chroot_dir" ostree admin init-fs /
sudo chroot "$chroot_dir" ostree admin stateroot-init debian
log_info "OSTree repository initialized"
}
# Create OSTree commit from chroot
create_ostree_commit() {
log_info "Creating OSTree commit from chroot..."
local chroot_dir="$WORK_DIR/chroot"
# Commit the current system state
sudo chroot "$chroot_dir" ostree commit \
--repo=/ostree/repo \
--branch=debian/$TARGET_DEBIAN_RELEASE/x86_64 \
--subject="Debian $TARGET_DEBIAN_RELEASE system" \
--tree=dir=/
log_info "OSTree commit created"
}
# Deploy OSTree system
deploy_ostree_system() {
log_info "Deploying OSTree system..."
local chroot_dir="$WORK_DIR/chroot"
# Deploy the commit
sudo chroot "$chroot_dir" ostree admin deploy \
--os=debian \
--karg=console=tty0 \
--karg=console=ttyS0,115200n8 \
debian/$TARGET_DEBIAN_RELEASE/x86_64
log_info "OSTree system deployed"
}
# Configure bootloader in chroot
configure_chroot_bootloader() {
log_info "Configuring bootloader in chroot..."
local chroot_dir="$WORK_DIR/chroot"
# Install GRUB
sudo chroot "$chroot_dir" grub-install --target=i386-pc /dev/sda
# Generate GRUB configuration
sudo chroot "$chroot_dir" grub-mkconfig -o /boot/grub/grub.cfg
log_info "Bootloader configured"
}
# Copy chroot filesystem to mounted partition
copy_chroot_filesystem() {
log_info "Copying chroot filesystem to mounted partition..."
local chroot_dir="$WORK_DIR/chroot"
# Copy the entire chroot filesystem
sudo cp -r "$chroot_dir"/* "$WORK_DIR/mnt/"
# Create essential symlinks
sudo ln -sf usr/bin "$WORK_DIR/mnt/bin"
sudo ln -sf usr/lib "$WORK_DIR/mnt/lib"
sudo ln -sf usr/sbin "$WORK_DIR/mnt/sbin"
sudo ln -sf usr/lib64 "$WORK_DIR/mnt/lib64"
log_info "Chroot filesystem copied"
}
# Cleanup chroot environment
cleanup_chroot() {
log_info "Cleaning up chroot environment..."
local chroot_dir="$WORK_DIR/chroot"
# Unmount filesystems
sudo umount "$chroot_dir/dev/pts" 2>/dev/null || true
sudo umount "$chroot_dir/sys" 2>/dev/null || true
sudo umount "$chroot_dir/proc" 2>/dev/null || true
sudo umount "$chroot_dir/dev" 2>/dev/null || true
# Remove chroot directory
sudo rm -rf "$chroot_dir"
log_info "Chroot environment cleaned up"
}
# Show chroot information
show_chroot_info() {
log_info "Chroot information:"
local chroot_dir="$WORK_DIR/chroot"
if [ -d "$chroot_dir" ]; then
echo "Chroot directory: $chroot_dir"
echo "Chroot size: $(du -sh "$chroot_dir" 2>/dev/null || echo 'Unknown')"
if [ -d "$chroot_dir/ostree" ]; then
echo "OSTree repository: Found"
echo "OSTree size: $(du -sh "$chroot_dir/ostree" 2>/dev/null || echo 'Unknown')"
else
echo "OSTree repository: Not found"
fi
if [ -d "$chroot_dir/boot" ]; then
echo "Boot directory: Found"
echo "Kernel: $(ls "$chroot_dir/boot"/vmlinuz* 2>/dev/null || echo 'Not found')"
else
echo "Boot directory: Not found"
fi
else
echo "Chroot directory: Not found"
fi
}
# Print module usage
print_module_usage() {
echo "Usage: source modules/chroot.sh"
echo "This module implements chroot-based OSTree creation."
echo ""
echo "Available functions:"
echo " create_chroot_environment - Create chroot environment"
echo " install_chroot_packages - Install packages in chroot"
echo " init_ostree_repository - Initialize OSTree repository"
echo " create_ostree_commit - Create OSTree commit"
echo " deploy_ostree_system - Deploy OSTree system"
echo " configure_chroot_bootloader - Configure bootloader"
echo " copy_chroot_filesystem - Copy to mounted partition"
echo " cleanup_chroot - Cleanup chroot environment"
echo " show_chroot_info - Display chroot information"
echo ""
echo "Required variables:"
echo " WORK_DIR - Working directory for operations"
}

183
modules/common.sh Normal file
View file

@ -0,0 +1,183 @@
#!/bin/bash
# Common functions and utilities for bootc image creation modules
# This module provides shared functionality used across all other modules
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Logging functions
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_debug() {
echo -e "${BLUE}[DEBUG]${NC} $1"
}
# Global variables (will be set by calling script)
WORK_DIR=""
loop_dev=""
# Cleanup function
cleanup() {
if [ -n "$WORK_DIR" ] && [ -d "$WORK_DIR" ]; then
log_info "Cleaning up work directory..."
sudo umount "$WORK_DIR/mnt" 2>/dev/null || true
sudo losetup -d "$loop_dev" 2>/dev/null || true
sudo rm -rf "$WORK_DIR"
fi
}
# Set trap for cleanup
setup_cleanup() {
trap cleanup EXIT INT TERM
}
# Check prerequisites
check_prerequisites() {
log_info "Checking prerequisites..."
local required_commands=("podman" "qemu-img" "parted" "losetup" "mkfs.ext4" "grub-install" "grub-mkconfig")
for cmd in "${required_commands[@]}"; do
if ! command -v "$cmd" >/dev/null 2>&1; then
log_error "Required command '$cmd' not found"
exit 1
fi
done
# Check if container image exists
if ! podman image exists "$CONTAINER_IMAGE"; then
log_error "Container image '$CONTAINER_IMAGE' not found"
log_info "Please build the image first with: podman build -t $CONTAINER_IMAGE -f debian_bootc_dockerfile.txt ."
exit 1
fi
log_info "All prerequisites satisfied"
}
# Create output directory
create_output_dir() {
log_info "Creating output directory..."
mkdir -p "$OUTPUT_DIR"
}
# Create work directory
create_work_dir() {
WORK_DIR="./work-$$"
log_info "Creating work directory: $WORK_DIR"
mkdir -p "$WORK_DIR"
}
# Validate configuration
validate_config() {
if [ -z "$CONTAINER_IMAGE" ]; then
log_error "CONTAINER_IMAGE not set"
exit 1
fi
if [ -z "$OUTPUT_DIR" ]; then
log_error "OUTPUT_DIR not set"
exit 1
fi
if [ -z "$IMAGE_SIZE_GB" ]; then
log_error "IMAGE_SIZE_GB not set"
exit 1
fi
log_debug "Configuration validated successfully"
}
# Show progress
show_progress() {
local step="$1"
local total="$2"
local current="$3"
local percentage=$((current * 100 / total))
local bar_length=30
local filled=$((bar_length * current / total))
local empty=$((bar_length - filled))
printf "\r["
printf "%${filled}s" | tr ' ' '#'
printf "%${empty}s" | tr ' ' '-'
printf "] %d%% - %s" "$percentage" "$step"
if [ "$current" -eq "$total" ]; then
echo
fi
}
# Check disk space
check_disk_space() {
# Get the directory where the main script is located
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
local required_space=$((IMAGE_SIZE_GB * 1024 * 1024 * 1024)) # Convert GB to bytes
local available_space=$(df "$script_dir" | awk 'NR==2 {print $4}')
# Convert available space to GB for comparison
local available_gb=$((available_space / 1024 / 1024 / 1024))
log_debug "Disk space check: Required: ${IMAGE_SIZE_GB}GB, Available: ${available_gb}GB"
if [ "$available_gb" -lt "$IMAGE_SIZE_GB" ]; then
log_error "Insufficient disk space. Required: ${IMAGE_SIZE_GB}GB, Available: ${available_gb}GB"
exit 1
fi
log_debug "Disk space check passed"
}
# Wait for user confirmation
confirm_action() {
local message="$1"
local default="${2:-n}"
if [ "$default" = "y" ]; then
read -p "$message [Y/n]: " -r
if [[ $REPLY =~ ^[Nn]$ ]]; then
return 1
fi
else
read -p "$message [y/N]: " -r
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
return 1
fi
fi
return 0
}
# Print module usage
print_module_usage() {
local module_name="$1"
echo "Usage: source modules/$module_name.sh"
echo "This module provides common functionality for bootc image creation."
echo ""
echo "Available functions:"
echo " log_info, log_warn, log_error, log_debug - Logging functions"
echo " cleanup, setup_cleanup - Cleanup management"
echo " check_prerequisites - Validate system requirements"
echo " create_output_dir, create_work_dir - Directory management"
echo " validate_config - Configuration validation"
echo " show_progress - Progress display"
echo " check_disk_space - Disk space validation"
echo " confirm_action - User confirmation prompts"
}

136
modules/disk.sh Normal file
View file

@ -0,0 +1,136 @@
#!/bin/bash
# Disk management module for bootc image creation
# This module handles disk image creation, partitioning, and filesystem setup
# Common functions are sourced by the main script
# Create and partition disk image
create_disk_image_work() {
log_info "Creating disk image..."
# Check disk space first (temporarily disabled for debugging)
# check_disk_space
# Create raw image first to ensure proper sizing
log_info "Creating raw image with size: ${IMAGE_SIZE_GB}GB"
dd if=/dev/zero of="$OUTPUT_DIR/debian-bootc.raw" bs=1M count=$((IMAGE_SIZE_GB * 1024))
# Create loop device
loop_dev=$(sudo losetup --find --show "$OUTPUT_DIR/debian-bootc.raw")
log_info "Using loop device: $loop_dev"
# Export the loop device variable so other modules can use it
export loop_dev
# Partition the disk with proper GPT layout including BIOS Boot Partition
log_info "Partitioning disk..."
sudo parted "$loop_dev" mklabel gpt
# Create 1MB BIOS Boot Partition for GRUB
sudo parted "$loop_dev" mkpart primary 1MiB 2MiB
sudo parted "$loop_dev" set 1 bios_grub on
# Create main system partition
sudo parted "$loop_dev" mkpart primary ext4 2MiB 100%
sudo parted "$loop_dev" set 2 boot on
# Verify partitions were created correctly
log_info "Verifying partition layout..."
sudo parted "$loop_dev" print
# Create filesystem on the main partition (partition 2)
log_info "Creating filesystem..."
sudo mkfs.ext4 "${loop_dev}p2"
# Mount the main partition (partition 2)
log_info "Mounting partition..."
mkdir -p "$WORK_DIR/mnt"
sudo mount "${loop_dev}p2" "$WORK_DIR/mnt"
log_info "Device size: $(sudo blockdev --getsize64 $loop_dev) bytes"
}
# Create essential directories
create_essential_directories() {
log_info "Creating essential directories..."
# Create essential directories individually
sudo mkdir -p "$WORK_DIR/mnt/usr"
sudo mkdir -p "$WORK_DIR/mnt/etc"
sudo mkdir -p "$WORK_DIR/mnt/var"
sudo mkdir -p "$WORK_DIR/mnt/home"
sudo mkdir -p "$WORK_DIR/mnt/root"
sudo mkdir -p "$WORK_DIR/mnt/boot"
sudo mkdir -p "$WORK_DIR/mnt/proc"
sudo mkdir -p "$WORK_DIR/mnt/sys"
sudo mkdir -p "$WORK_DIR/mnt/dev"
sudo mkdir -p "$WORK_DIR/mnt/tmp"
sudo mkdir -p "$WORK_DIR/mnt/run"
sudo mkdir -p "$WORK_DIR/mnt/media"
sudo mkdir -p "$WORK_DIR/mnt/mnt"
log_info "Essential directories created"
}
# Unmount and cleanup disk
cleanup_disk() {
log_info "Cleaning up disk operations..."
if [ -n "$WORK_DIR" ] && [ -d "$WORK_DIR/mnt" ]; then
sudo umount "$WORK_DIR/mnt" 2>/dev/null || true
fi
if [ -n "$loop_dev" ]; then
sudo losetup -d "$loop_dev" 2>/dev/null || true
fi
}
# Get disk information
get_disk_info() {
if [ -n "$loop_dev" ]; then
log_info "Disk information:"
sudo parted "$loop_dev" print
echo ""
sudo fdisk -l "$loop_dev"
else
log_warn "No loop device available for disk info"
fi
}
# Verify disk integrity
verify_disk_integrity() {
log_info "Verifying disk integrity..."
if [ ! -f "$OUTPUT_DIR/debian-bootc.raw" ]; then
log_error "Raw disk image not found"
return 1
fi
local image_size=$(stat -c%s "$OUTPUT_DIR/debian-bootc.raw")
local expected_size=$((IMAGE_SIZE_GB * 1024 * 1024 * 1024))
if [ "$image_size" -ne "$expected_size" ]; then
log_error "Disk image size mismatch. Expected: $expected_size, Got: $image_size"
return 1
fi
log_info "Disk integrity verified successfully"
return 0
}
# Print module usage
print_module_usage() {
echo "Usage: source modules/disk.sh"
echo "This module handles disk image creation and management."
echo ""
echo "Available functions:"
echo " create_disk_image - Create and partition disk image"
echo " create_essential_directories - Create required directory structure"
echo " cleanup_disk - Unmount and cleanup disk operations"
echo " get_disk_info - Display disk partition information"
echo " verify_disk_integrity - Verify disk image integrity"
echo ""
echo "Required variables:"
echo " OUTPUT_DIR - Output directory for images"
echo " IMAGE_SIZE_GB - Image size in gigabytes"
echo " WORK_DIR - Working directory for operations"
}

188
modules/filesystem.sh Normal file
View file

@ -0,0 +1,188 @@
#!/bin/bash
# Filesystem management module for bootc image creation
# This module handles container filesystem extraction and setup
# Common functions are sourced by the main script
# Extract container filesystem
extract_container_filesystem() {
log_info "Extracting container filesystem..."
# Change ownership to allow container to write
log_info "Setting directory permissions..."
sudo chown -R 1000:1000 "$WORK_DIR/mnt"
# Extract container filesystem directly
log_info "Extracting container filesystem..."
podman run --rm -v "$WORK_DIR/mnt:/extract" "$CONTAINER_IMAGE" \
/bin/bash -c "
cd /extract
echo 'Starting filesystem extraction...'
# Copy the main system directories with verbose output
echo 'Copying /usr...'
cp -rv /usr . 2>&1 || echo 'Copy of /usr failed'
echo 'Copying /etc...'
cp -rv /etc . 2>&1 || echo 'Copy of /etc failed'
echo 'Copying /var...'
cp -rv /var . 2>&1 || echo 'Copy of /var failed'
echo 'Copying /home...'
cp -rv /home . 2>&1 || echo 'Copy of /home failed'
echo 'Copying /root...'
cp -rv /root . 2>&1 || echo 'Copy of /root failed'
echo 'Copying /boot...'
cp -rv /boot . 2>&1 || echo 'Copy of /boot failed'
# Create symlinks for traditional compatibility (usr-merge structure)
echo 'Creating symlinks for usr-merge compatibility...'
if [ -d usr/bin ]; then
ln -sf usr/bin bin
echo 'Created bin -> usr/bin symlink'
fi
if [ -d usr/lib ]; then
ln -sf usr/lib lib
echo 'Created lib -> usr/lib symlink'
fi
if [ -d usr/lib64 ]; then
ln -sf usr/lib64 lib64
echo 'Created lib64 -> usr/lib64 symlink'
fi
if [ -d usr/sbin ]; then
ln -sf usr/sbin sbin
echo 'Created sbin -> usr/sbin symlink'
fi
echo 'Filesystem extraction completed'
echo 'Final directory listing:'
ls -la
echo 'Checking usr directory:'
ls -la usr/
echo 'Checking if critical directories exist:'
[ -d usr/lib ] && echo 'usr/lib exists' || echo 'usr/lib MISSING'
[ -d usr/sbin ] && echo 'usr/sbin exists' || echo 'usr/sbin MISSING'
[ -d usr/bin ] && echo 'usr/bin exists' || echo 'usr/bin MISSING'
echo 'Checking boot directory:'
ls -la boot/
"
# Restore proper ownership for the final image
log_info "Restoring proper ownership..."
sudo chown -R root:root "$WORK_DIR/mnt"
log_info "Filesystem extraction completed"
}
# Fix file permissions
fix_file_permissions() {
log_info "Fixing critical file permissions..."
# Fix sudo permissions
sudo chmod 4755 "$WORK_DIR/mnt/usr/bin/sudo" # Set setuid bit for sudo
sudo chown root:root "$WORK_DIR/mnt/usr/bin/sudo" # Ensure sudo is owned by root
# Fix home directory permissions (use UID 1000 which is typically the first user)
sudo chown -R 1000:1000 "$WORK_DIR/mnt/home/debian"
sudo chmod 755 "$WORK_DIR/mnt/home/debian"
# Ensure critical system tools have proper permissions
sudo chmod 755 "$WORK_DIR/mnt/usr/bin/ip" 2>/dev/null || echo "ip command not found"
sudo chmod 755 "$WORK_DIR/mnt/usr/bin/ping" 2>/dev/null || echo "ping command not found"
sudo chmod 755 "$WORK_DIR/mnt/bin/shutdown" 2>/dev/null || echo "shutdown command not found"
sudo chmod 755 "$WORK_DIR/mnt/bin/halt" 2>/dev/null || echo "halt command not found"
sudo chmod 755 "$WORK_DIR/mnt/bin/poweroff" 2>/dev/null || echo "poweroff command not found"
# Set proper permissions for system directories
sudo chmod 1777 "$WORK_DIR/mnt/tmp"
sudo chmod 755 "$WORK_DIR/mnt/proc" "$WORK_DIR/mnt/sys" "$WORK_DIR/mnt/dev" \
"$WORK_DIR/mnt/run" "$WORK_DIR/mnt/media" "$WORK_DIR/mnt/mnt"
log_info "File permissions fixed"
}
# Verify filesystem integrity
verify_filesystem_integrity() {
log_info "Verifying filesystem integrity..."
local critical_dirs=("usr" "etc" "var" "boot" "home")
local missing_dirs=()
for dir in "${critical_dirs[@]}"; do
if [ ! -d "$WORK_DIR/mnt/$dir" ]; then
missing_dirs+=("$dir")
fi
done
if [ ${#missing_dirs[@]} -gt 0 ]; then
log_error "Missing critical directories: ${missing_dirs[*]}"
return 1
fi
# Check for critical symlinks
local critical_symlinks=("bin" "lib" "sbin")
local missing_symlinks=()
for symlink in "${critical_symlinks[@]}"; do
if [ ! -L "$WORK_DIR/mnt/$symlink" ]; then
missing_symlinks+=("$symlink")
fi
done
if [ ${#missing_symlinks[@]} -gt 0 ]; then
log_error "Missing critical symlinks: ${missing_symlinks[*]}"
return 1
fi
# Check for kernel and initrd
if [ ! -f "$WORK_DIR/mnt/boot/vmlinuz-6.12.41+deb13-amd64" ]; then
log_error "Kernel not found in expected location"
return 1
fi
if [ ! -f "$WORK_DIR/mnt/boot/initrd.img-6.12.41+deb13-amd64" ]; then
log_error "Initrd not found in expected location"
return 1
fi
log_info "Filesystem integrity verified successfully"
return 0
}
# Show filesystem statistics
show_filesystem_stats() {
log_info "Filesystem statistics:"
echo "Directory sizes:"
du -sh "$WORK_DIR/mnt"/* 2>/dev/null | sort -hr
echo ""
echo "File counts:"
find "$WORK_DIR/mnt" -type f | wc -l | xargs echo "Total files:"
find "$WORK_DIR/mnt" -type d | wc -l | xargs echo "Total directories:"
find "$WORK_DIR/mnt" -type l | wc -l | xargs echo "Total symlinks:"
echo ""
echo "Largest files:"
find "$WORK_DIR/mnt" -type f -exec ls -lh {} + 2>/dev/null | sort -k5 -hr | head -10
}
# Print module usage
print_module_usage() {
echo "Usage: source modules/filesystem.sh"
echo "This module handles filesystem extraction and management."
echo ""
echo "Available functions:"
echo " extract_container_filesystem - Extract container filesystem"
echo " fix_file_permissions - Fix critical file permissions"
echo " verify_filesystem_integrity - Verify filesystem integrity"
echo " show_filesystem_stats - Display filesystem statistics"
echo ""
echo "Required variables:"
echo " CONTAINER_IMAGE - Container image to extract from"
echo " WORK_DIR - Working directory for operations"
}

171
modules/formats.sh Normal file
View file

@ -0,0 +1,171 @@
#!/bin/bash
# Output format conversion module for bootc image creation
# This module handles conversion to different output formats (QCOW2, ISO, IMG)
# Common functions are sourced by the main script
# Convert to QCOW2
convert_to_qcow2() {
log_info "Converting to QCOW2..."
# Unmount before conversion
sudo umount "$WORK_DIR/mnt"
# Convert raw image to QCOW2
qemu-img convert -f raw -O qcow2 "$OUTPUT_DIR/debian-bootc.raw" "$OUTPUT_DIR/debian-bootc.qcow2"
# Keep the raw image for VM use
log_info "Raw image kept: $OUTPUT_DIR/debian-bootc.raw"
log_info "QCOW2 image created: $OUTPUT_DIR/debian-bootc-simple.qcow2"
# Show final image info
ls -lh "$OUTPUT_DIR/debian-bootc.qcow2"
}
# Convert to ISO
convert_to_iso() {
log_info "Converting to ISO..."
# Unmount before conversion
sudo umount "$WORK_DIR/mnt"
# Create temporary directory for ISO contents
local iso_temp="$WORK_DIR/iso-temp"
mkdir -p "$iso_temp"
# Copy filesystem to temporary directory
log_info "Preparing ISO contents..."
sudo cp -r "$WORK_DIR/mnt"/* "$iso_temp/"
# Create bootable ISO
log_info "Creating bootable ISO..."
genisoimage -o "$OUTPUT_DIR/debian-bootc.iso" \
-b isolinux/isolinux.bin \
-c isolinux/boot.cat \
-no-emul-boot \
-boot-load-size 4 \
-boot-info-table \
-r \
-J \
-v \
"$iso_temp"
# Cleanup temporary directory
sudo rm -rf "$iso_temp"
log_info "ISO image created: $OUTPUT_DIR/debian-bootc.iso"
ls -lh "$OUTPUT_DIR/debian-bootc.iso"
}
# Convert to IMG (raw format)
convert_to_img() {
log_info "Converting to IMG format..."
# Unmount before conversion
sudo umount "$WORK_DIR/mnt"
# Copy raw image to IMG
cp "$OUTPUT_DIR/debian-bootc.raw" "$OUTPUT_DIR/debian-bootc.img"
log_info "IMG image created: $OUTPUT_DIR/debian-bootc.img"
ls -lh "$OUTPUT_DIR/debian-bootc.img"
}
# Convert to VMDK (VMware format)
convert_to_vmdk() {
log_info "Converting to VMDK..."
# Unmount before conversion
sudo umount "$WORK_DIR/mnt"
# Convert raw image to VMDK
qemu-img convert -f raw -O vmdk "$OUTPUT_DIR/debian-bootc.raw" "$OUTPUT_DIR/debian-bootc.vmdk"
log_info "VMDK image created: $OUTPUT_DIR/debian-bootc.vmdk"
ls -lh "$OUTPUT_DIR/debian-bootc.vmdk"
}
# Convert to VDI (VirtualBox format)
convert_to_vdi() {
log_info "Converting to VDI..."
# Unmount before conversion
sudo umount "$WORK_DIR/mnt"
# Convert raw image to VDI
qemu-img convert -f raw -O vdi "$OUTPUT_DIR/debian-bootc.raw" "$OUTPUT_DIR/debian-bootc.vdi"
log_info "VDI image created: $OUTPUT_DIR/debian-bootc.vdi"
ls -lh "$OUTPUT_DIR/debian-bootc.vdi"
}
# Convert to multiple formats
convert_to_all_formats() {
log_info "Converting to all supported formats..."
# Unmount before conversion
sudo umount "$WORK_DIR/mnt"
# Convert to all formats
convert_to_qcow2
convert_to_iso
convert_to_img
convert_to_vmdk
convert_to_vdi
log_info "All format conversions completed!"
# Show all created images
echo ""
log_info "Created images:"
ls -lh "$OUTPUT_DIR"/debian-bootc.*
}
# Show format information
show_format_info() {
log_info "Format information:"
if [ -f "$OUTPUT_DIR/debian-bootc.raw" ]; then
echo "Raw image: $(ls -lh "$OUTPUT_DIR/debian-bootc.raw")"
fi
if [ -f "$OUTPUT_DIR/debian-bootc.qcow2" ]; then
echo "QCOW2 image: $(ls -lh "$OUTPUT_DIR/debian-bootc.qcow2")"
fi
if [ -f "$OUTPUT_DIR/debian-bootc.iso" ]; then
echo "ISO image: $(ls -lh "$OUTPUT_DIR/debian-bootc.iso")"
fi
if [ -f "$OUTPUT_DIR/debian-bootc.img" ]; then
echo "IMG image: $(ls -lh "$OUTPUT_DIR/debian-bootc.img")"
fi
if [ -f "$OUTPUT_DIR/debian-bootc.vmdk" ]; then
echo "VMDK image: $(ls -lh "$OUTPUT_DIR/debian-bootc.vmdk")"
fi
if [ -f "$OUTPUT_DIR/debian-bootc.vdi" ]; then
echo "VDI image: $(ls -lh "$OUTPUT_DIR/debian-bootc.vdi")"
fi
}
# Print module usage
print_module_usage() {
echo "Usage: source modules/formats.sh"
echo "This module handles output format conversion."
echo ""
echo "Available functions:"
echo " convert_to_qcow2 - Convert to QCOW2 format"
echo " convert_to_iso - Convert to ISO format"
echo " convert_to_img - Convert to IMG format"
echo " convert_to_vmdk - Convert to VMDK format"
echo " convert_to_vdi - Convert to VDI format"
echo " convert_to_all_formats - Convert to all formats"
echo " show_format_info - Display format information"
echo ""
echo "Required variables:"
echo " OUTPUT_DIR - Output directory for images"
echo " WORK_DIR - Working directory for operations"
}

74
setup-apt-cacher-ng.sh Executable file
View file

@ -0,0 +1,74 @@
#!/bin/bash
# setup-apt-cacher-ng.sh - Quick setup for apt-cacher-ng
set -euo pipefail
log_info() {
echo -e "\033[0;32m[INFO]\033[0m $1"
}
log_warn() {
echo -e "\033[1;33m[WARN]\033[0m $1"
}
log_error() {
echo -e "\033[0;31m[ERROR]\033[0m $1"
}
# Check if apt-cacher-ng is already running
check_existing() {
if curl -s --connect-timeout 5 "http://localhost:3142/acng-report.html" > /dev/null 2>&1; then
log_info "apt-cacher-ng is already running at http://localhost:3142"
return 0
fi
return 1
}
# Install apt-cacher-ng
install_apt_cacher_ng() {
log_info "Installing apt-cacher-ng..."
sudo apt update
sudo apt install -y apt-cacher-ng
# Configure to allow all clients
sudo sed -i 's/^#BindAddress: 127.0.0.1/BindAddress: 0.0.0.0/' /etc/apt-cacher-ng/acng.conf
# Start and enable service
sudo systemctl enable apt-cacher-ng
sudo systemctl start apt-cacher-ng
log_info "apt-cacher-ng installed and started"
}
# Test the setup
test_setup() {
log_info "Testing apt-cacher-ng..."
if curl -s --connect-timeout 5 "http://localhost:3142/acng-report.html" > /dev/null 2>&1; then
log_info "✅ apt-cacher-ng is working!"
log_info "Cache URL: http://localhost:3142"
log_info "Status page: http://localhost:3142/acng-report.html"
return 0
else
log_error "❌ apt-cacher-ng is not responding"
return 1
fi
}
# Main execution
main() {
log_info "Setting up apt-cacher-ng for faster bootc builds..."
if check_existing; then
log_info "apt-cacher-ng is already available"
exit 0
fi
install_apt_cacher_ng
test_setup
log_info "Setup complete! You can now use:"
log_info " export APT_CACHER_NG_URL=http://localhost:3142"
log_info " ./build-with-cache.sh"
}
main "$@"

60
show-debian-releases.sh Executable file
View file

@ -0,0 +1,60 @@
#!/bin/bash
# Script to demonstrate Debian release functionality
# Shows available releases and current configuration
set -e
# Source configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/config/defaults.sh"
echo "=== Debian Release Information ==="
echo ""
echo "Available Debian Releases:"
echo " trixie - Debian 13 (Testing) - DEFAULT"
echo " forky - Debian 14 (Unstable)"
echo " sid - Debian Sid (Always Unstable)"
echo ""
echo "Current Configuration:"
echo " DEBIAN_RELEASE: $DEBIAN_RELEASE"
echo " TARGET_DEBIAN_RELEASE: $TARGET_DEBIAN_RELEASE"
echo " Description: $(get_debian_release_description "$DEBIAN_RELEASE")"
echo ""
echo "OSTree Configuration:"
echo " Branch: $OSTREE_BRANCH"
echo " Subject: $OSTREE_SUBJECT"
echo ""
echo "Usage Examples:"
echo " # Use specific release"
echo " DEBIAN_RELEASE=forky ./create-bootc-image.sh -t chroot -f qcow2"
echo " DEBIAN_RELEASE=sid ./create-bootc-image.sh -t chroot -f qcow2"
echo ""
echo " # Use justfile with specific release"
echo " just qcow2-chroot-release forky"
echo " just qcow2-chroot-release sid"
echo " just custom-chroot-release 20 iso trixie"
echo ""
echo " # Check available releases"
echo " just releases"
echo ""
echo "Environment Variable Override:"
echo " export DEBIAN_RELEASE=forky"
echo " export DEBIAN_RELEASE=sid"
echo " ./create-bootc-image.sh -t chroot -f qcow2"
echo ""
echo "Validation:"
if validate_debian_release "$DEBIAN_RELEASE"; then
echo " ✓ Current release '$DEBIAN_RELEASE' is valid"
else
echo " ✗ Current release '$DEBIAN_RELEASE' is invalid"
fi
echo ""
echo "=== End of Information ==="

48
test-bootc-container.sh Executable file
View file

@ -0,0 +1,48 @@
#!/bin/bash
echo "=== Testing Debian Bootc Container Components ==="
# Test basic commands
echo "1. Testing basic commands:"
podman run --rm localhost/debian-bootc:latest /bin/bash -c "
echo 'bootc version:' && bootc --version
echo 'ostree version:' && ostree --version
echo 'grub version:' && grub-install --version
echo 'kernel version:' && uname -r
"
echo -e "\n2. Testing OSTree functionality:"
podman run --rm -v /tmp:/tmp localhost/debian-bootc:latest /bin/bash -c "
cd /tmp
mkdir -p test-ostree
ostree admin init-fs /tmp/test-ostree
echo 'OSTree init successful'
ls -la /tmp/test-ostree/
"
echo -e "\n3. Testing bootc functionality:"
podman run --rm localhost/debian-bootc:latest /bin/bash -c "
echo 'Testing bootc commands:'
bootc --help | head -5
"
echo -e "\n4. Testing systemd-boot components:"
podman run --rm localhost/debian-bootc:latest /bin/bash -c "
echo 'systemd-boot files:'
ls -la /usr/lib/systemd/boot/
echo 'systemd-boot packages:'
dpkg -l | grep systemd-boot
"
echo -e "\n5. Testing GRUB components:"
podman run --rm localhost/debian-bootc:latest /bin/bash -c "
echo 'GRUB files:'
ls -la /usr/lib/grub/
echo 'GRUB packages:'
dpkg -l | grep grub
"
echo -e "\n=== Container Test Complete ==="
echo "If all tests passed, the container should be capable of creating bootable images."