#!/bin/bash # Integration script between apt-ostree and deb-bootc-image-builder # Creates complete Debian Atomic pipeline: treefile → apt-ostree → bootable image set -euo pipefail # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Configuration WORKSPACE_PATH="/home/rob/Documents/Projects/overseer" APT_OSTREE_PATH="$WORKSPACE_PATH/apt-ostree" DEB_BOOTC_PATH="$WORKSPACE_PATH/deb-bootc-image-builder" ATOMIC_CONFIGS_PATH="$WORKSPACE_PATH/debian-atomic-configs" TEMP_DIR=$(mktemp -d /tmp/debian-atomic-XXXXXX) # Functions log_info() { echo -e "${BLUE}ℹ️ $1${NC}" } log_success() { echo -e "${GREEN}✅ $1${NC}" } log_warning() { echo -e "${YELLOW}⚠️ $1${NC}" } log_error() { echo -e "${RED}❌ $1${NC}" } cleanup() { log_info "Cleaning up temporary files..." if [[ -d "$TEMP_DIR" ]]; then rm -rf "$TEMP_DIR" fi } # Set up cleanup on exit trap cleanup EXIT # Validate paths validate_paths() { log_info "Validating required components..." local missing_paths=() [[ ! -d "$APT_OSTREE_PATH" ]] && missing_paths+=("apt-ostree") [[ ! -d "$DEB_BOOTC_PATH" ]] && missing_paths+=("deb-bootc-image-builder") [[ ! -d "$ATOMIC_CONFIGS_PATH" ]] && missing_paths+=("debian-atomic-configs") if [[ ${#missing_paths[@]} -gt 0 ]]; then log_error "Missing required components: ${missing_paths[*]}" exit 1 fi log_success "All required components found" } # Build apt-ostree if needed build_apt_ostree() { local apt_ostree_bin="$APT_OSTREE_PATH/target/debug/apt-ostree" if [[ ! -f "$apt_ostree_bin" ]]; then log_info "Building apt-ostree..." cd "$APT_OSTREE_PATH" if ! cargo build --bin apt-ostree; then log_error "Failed to build apt-ostree" exit 1 fi log_success "apt-ostree built successfully" else log_info "apt-ostree binary found, skipping build" fi } # Build deb-bootc-image-builder if needed build_deb_bootc() { local bib_bin="$DEB_BOOTC_PATH/bib/create-ostree-bootable-image" if [[ ! -f "$bib_bin" ]]; then log_info "Building deb-bootc-image-builder..." cd "$DEB_BOOTC_PATH" if ! go build -o bib/create-ostree-bootable-image ./bib/create-ostree-bootable-image.go; then log_error "Failed to build deb-bootc-image-builder" exit 1 fi log_success "deb-bootc-image-builder built successfully" else log_info "deb-bootc-image-builder binary found, skipping build" fi } # Step 1: Create OSTree commit using apt-ostree create_ostree_commit() { echo "DEBUG: create_ostree_commit function called with: $1" local treefile="$1" local treefile_path="$ATOMIC_CONFIGS_PATH/treefiles/$treefile" log_info "Step 1: Creating OSTree commit from $treefile" log_info "Treefile path: $treefile_path" if [[ ! -f "$treefile_path" ]]; then log_error "Treefile not found: $treefile_path" return 1 fi # Run apt-ostree inside the Debian container where libraries are available local apt_ostree_bin="$APT_OSTREE_PATH/target/release/apt-ostree" log_info "Running apt-ostree inside Debian container..." log_info "apt-ostree binary: $apt_ostree_bin" # Create a temporary working directory that's shared between host and container local container_workdir="$TEMP_DIR/apt-ostree-build" # Run the command in the container and capture output log_info "Executing: podman run --rm --privileged -v $APT_OSTREE_PATH:/workspace:z -v $ATOMIC_CONFIGS_PATH:/configs:z -v $TEMP_DIR:/shared:z apt-ostree-builder:latest bash -c 'cd /workspace && ./target/release/apt-ostree compose tree /configs/treefiles/$(basename $treefile_path) --workdir /shared/apt-ostree-build'" local output local exit_code output=$(podman run --rm --privileged -v "$APT_OSTREE_PATH:/workspace:z" -v "$ATOMIC_CONFIGS_PATH:/configs:z" -v "$TEMP_DIR:/shared:z" apt-ostree-builder:latest bash -c "cd /workspace && ./target/release/apt-ostree compose tree /configs/treefiles/$(basename $treefile_path) --workdir /shared/apt-ostree-build" 2>&1) exit_code=$? log_info "Command completed with exit code: $exit_code" log_info "Command output:" echo "$output" if [[ $exit_code -ne 0 ]]; then log_error "apt-ostree failed with exit code $exit_code" return 1 fi log_success "OSTree commit created successfully" # apt-ostree creates the repository in the shared workdir local repo_path="$TEMP_DIR/apt-ostree-build/repo" log_info "Checking for repository at: $repo_path" if [[ ! -d "$repo_path" ]]; then log_error "OSTree repository not found at $repo_path" return 1 fi log_info "Repository found, checking commits..." # Get commit information local commits_dir="$repo_path/commits" if [[ ! -d "$commits_dir" ]]; then log_error "No commits directory found" return 1 fi local commits=($(ls "$commits_dir" | grep -E "^commit_")) log_info "Found commits: ${commits[*]}" if [[ ${#commits[@]} -eq 0 ]]; then log_error "No commits found in repository" return 1 fi local commit_id="${commits[0]}" log_info "Selected commit: $commit_id" # Read metadata if available local metadata_file="$commits_dir/$commit_id/metadata.json" if [[ -f "$metadata_file" ]]; then log_info "Commit metadata:" cat "$metadata_file" | jq '.' 2>/dev/null || cat "$metadata_file" fi log_success "Successfully created commit: $commit_id" echo "$commit_id" } # Step 2: Extract rootfs from OSTree commit and create bootable image create_bootable_image() { local commit_id="$1" local repo_path="/tmp/apt-ostree-build/repo" log_info "Step 2: Creating bootable image from OSTree commit" cd "$TEMP_DIR" # Extract the rootfs from the OSTree commit local rootfs_path="$TEMP_DIR/rootfs" log_info "Extracting rootfs from OSTree commit..." # Use ostree to checkout the commit to a directory if ! ostree checkout --repo="$repo_path" --subpath=/ "$commit_id" "$rootfs_path"; then log_error "Failed to extract rootfs from OSTree commit" exit 1 fi log_success "Rootfs extracted to: $rootfs_path" # Verify rootfs structure if [[ ! -d "$rootfs_path/usr" ]] || [[ ! -d "$rootfs_path/etc" ]]; then log_error "Invalid rootfs structure" exit 1 fi # Create bootable image using deb-bootc-image-builder local bib_bin="$DEB_BOOTC_PATH/bib/create-ostree-bootable-image" local output_image="$TEMP_DIR/debian-atomic.img" log_info "Creating bootable image from rootfs..." if ! "$bib_bin" "$rootfs_path" "$output_image"; then log_error "Failed to create bootable image" exit 1 fi log_success "Bootable image created successfully" # Check if image was created if [[ ! -f "$output_image" ]]; then log_error "Output image not found: $output_image" exit 1 fi # Show image information local image_size=$(du -h "$output_image" | cut -f1) log_info "Image created: $output_image ($image_size)" echo "$output_image" } # Main pipeline function run_pipeline() { local treefile="$1" local variant="${2:-minimal}" log_info "🚀 Starting Debian Atomic pipeline" log_info "Treefile: $treefile" log_info "Variant: $variant" log_info "Working directory: $TEMP_DIR" # Step 1: Create OSTree commit log_info "Executing Step 1: Create OSTree commit..." local commit_id if ! commit_id=$(create_ostree_commit "$treefile"); then log_error "Step 1 failed: Could not create OSTree commit" return 1 fi log_success "Step 1 completed: OSTree commit $commit_id created" # Step 2: Create bootable image log_info "Executing Step 2: Create bootable image..." local output_image if ! output_image=$(create_bootable_image "$commit_id"); then log_error "Step 2 failed: Could not create bootable image" return 1 fi log_success "Step 2 completed: Bootable image created" log_success "🎉 Pipeline completed successfully!" log_info "Output image: $output_image" # Copy image to workspace for easy access local final_image="$WORKSPACE_PATH/debian-atomic-$variant.img" cp "$output_image" "$final_image" log_info "Image copied to: $final_image" # Show testing instructions echo log_info "🧪 To test the image:" echo "qemu-system-x86_64 -m 2G -drive file=$final_image,format=raw -nographic" echo log_info "📋 Summary:" log_success "✅ OSTree commit created from $treefile" log_success "✅ Bootable image created: $final_image" log_success "✅ Debian Atomic pipeline completed successfully!" return 0 } # Main function main() { if [[ $# -lt 1 ]]; then echo "Usage: $0 [variant]" echo "Example: $0 debian-minimal.yaml minimal" echo echo "Available treefiles:" if [[ -d "$ATOMIC_CONFIGS_PATH/treefiles" ]]; then ls "$ATOMIC_CONFIGS_PATH/treefiles/"*.yaml 2>/dev/null | sed 's/.*\///' || echo "No treefiles found" fi exit 1 fi local treefile="$1" local variant="${2:-minimal}" # Validate and build components validate_paths build_apt_ostree build_deb_bootc # Run the pipeline if ! run_pipeline "$treefile" "$variant"; then log_error "Pipeline failed" exit 1 fi log_success "Pipeline completed successfully" } # Run main function main "$@"