From a61c0e9e0bde2553c0af9bb4f3bc324f3f16afa1 Mon Sep 17 00:00:00 2001 From: robojerk Date: Thu, 21 Aug 2025 07:31:52 -0700 Subject: [PATCH] first commit --- .gitignore | 55 ++++++ bootc-compat.sh | 57 ++++++ build-with-cache.sh | 283 +++++++++++++++++++++++++++++ config.toml | 16 ++ config/defaults.sh | 171 ++++++++++++++++++ create-and-boot-vm.sh | 161 +++++++++++++++++ create-bootc-image.sh | 350 ++++++++++++++++++++++++++++++++++++ debian-bootc-vm.xml | 121 +++++++++++++ debian_bootc_dockerfile.txt | 142 +++++++++++++++ default-network.xml | 12 ++ justfile | 226 +++++++++++++++++++++++ modules/bootloader.sh | 236 ++++++++++++++++++++++++ modules/chroot.sh | 215 ++++++++++++++++++++++ modules/common.sh | 183 +++++++++++++++++++ modules/disk.sh | 136 ++++++++++++++ modules/filesystem.sh | 188 +++++++++++++++++++ modules/formats.sh | 171 ++++++++++++++++++ setup-apt-cacher-ng.sh | 74 ++++++++ show-debian-releases.sh | 60 +++++++ test-bootc-container.sh | 48 +++++ 20 files changed, 2905 insertions(+) create mode 100644 .gitignore create mode 100755 bootc-compat.sh create mode 100755 build-with-cache.sh create mode 100644 config.toml create mode 100644 config/defaults.sh create mode 100755 create-and-boot-vm.sh create mode 100755 create-bootc-image.sh create mode 100644 debian-bootc-vm.xml create mode 100644 debian_bootc_dockerfile.txt create mode 100644 default-network.xml create mode 100644 justfile create mode 100644 modules/bootloader.sh create mode 100644 modules/chroot.sh create mode 100644 modules/common.sh create mode 100644 modules/disk.sh create mode 100644 modules/filesystem.sh create mode 100644 modules/formats.sh create mode 100755 setup-apt-cacher-ng.sh create mode 100755 show-debian-releases.sh create mode 100755 test-bootc-container.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..663390a --- /dev/null +++ b/.gitignore @@ -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 diff --git a/bootc-compat.sh b/bootc-compat.sh new file mode 100755 index 0000000..00bbf87 --- /dev/null +++ b/bootc-compat.sh @@ -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 "$@" diff --git a/build-with-cache.sh b/build-with-cache.sh new file mode 100755 index 0000000..13e1ad2 --- /dev/null +++ b/build-with-cache.sh @@ -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 "$@" diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..5104380 --- /dev/null +++ b/config.toml @@ -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"] diff --git a/config/defaults.sh b/config/defaults.sh new file mode 100644 index 0000000..3b0974d --- /dev/null +++ b/config/defaults.sh @@ -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 +} diff --git a/create-and-boot-vm.sh b/create-and-boot-vm.sh new file mode 100755 index 0000000..f2c6130 --- /dev/null +++ b/create-and-boot-vm.sh @@ -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@" + 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 "$@" diff --git a/create-bootc-image.sh b/create-bootc-image.sh new file mode 100755 index 0000000..196ce39 --- /dev/null +++ b/create-bootc-image.sh @@ -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 diff --git a/debian-bootc-vm.xml b/debian-bootc-vm.xml new file mode 100644 index 0000000..6b8a738 --- /dev/null +++ b/debian-bootc-vm.xml @@ -0,0 +1,121 @@ + + + debian-bootc + 12345678-1234-1234-1234-123456789abc + Debian Bootc OSTree System + Debian bootc container with OSTree support + + 2 + 2 + 2 + 4 + + + hvm + + + + + + + + + + + + + + + + + + + destroy + restart + destroy + + + /usr/bin/qemu-system-x86_64 + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + +
+ + + + +
+ + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + /dev/urandom +
+ + + diff --git a/debian_bootc_dockerfile.txt b/debian_bootc_dockerfile.txt new file mode 100644 index 0000000..632b0c3 --- /dev/null +++ b/debian_bootc_dockerfile.txt @@ -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"] \ No newline at end of file diff --git a/default-network.xml b/default-network.xml new file mode 100644 index 0000000..7ebd9fa --- /dev/null +++ b/default-network.xml @@ -0,0 +1,12 @@ + + default + 12345678-1234-1234-1234-123456789abc + + + + + + + + + diff --git a/justfile b/justfile new file mode 100644 index 0000000..59101bc --- /dev/null +++ b/justfile @@ -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 + + diff --git a/modules/bootloader.sh b/modules/bootloader.sh new file mode 100644 index 0000000..4224445 --- /dev/null +++ b/modules/bootloader.sh @@ -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" +} diff --git a/modules/chroot.sh b/modules/chroot.sh new file mode 100644 index 0000000..0b6bcfa --- /dev/null +++ b/modules/chroot.sh @@ -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" +} diff --git a/modules/common.sh b/modules/common.sh new file mode 100644 index 0000000..7908a9a --- /dev/null +++ b/modules/common.sh @@ -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" +} diff --git a/modules/disk.sh b/modules/disk.sh new file mode 100644 index 0000000..c562149 --- /dev/null +++ b/modules/disk.sh @@ -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" +} diff --git a/modules/filesystem.sh b/modules/filesystem.sh new file mode 100644 index 0000000..de1e33b --- /dev/null +++ b/modules/filesystem.sh @@ -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" +} diff --git a/modules/formats.sh b/modules/formats.sh new file mode 100644 index 0000000..fb680cd --- /dev/null +++ b/modules/formats.sh @@ -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" +} diff --git a/setup-apt-cacher-ng.sh b/setup-apt-cacher-ng.sh new file mode 100755 index 0000000..6709836 --- /dev/null +++ b/setup-apt-cacher-ng.sh @@ -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 "$@" diff --git a/show-debian-releases.sh b/show-debian-releases.sh new file mode 100755 index 0000000..f481b83 --- /dev/null +++ b/show-debian-releases.sh @@ -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 ===" diff --git a/test-bootc-container.sh b/test-bootc-container.sh new file mode 100755 index 0000000..d983c63 --- /dev/null +++ b/test-bootc-container.sh @@ -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." + +