#!/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