particle-os-tools/oci-integration.sh
robojerk 74c7bede5f Initial commit: Particle-OS tools repository
- Complete Particle-OS rebranding from uBlue-OS
- Professional installation system with standardized paths
- Self-initialization system with --init and --reset commands
- Enhanced error messages and dependency checking
- Comprehensive testing infrastructure
- All source scriptlets updated with runtime improvements
- Clean codebase with redundant files moved to archive
- Complete documentation suite
2025-07-11 21:14:33 -07:00

407 lines
No EOL
12 KiB
Bash

#!/bin/bash
# Particle-OS OCI Integration
# Provides OCI export/import functionality for ComposeFS images
set -euo pipefail
# Source unified configuration
if [[ -f "${PARTICLE_CONFIG_FILE:-/usr/local/etc/particle-config.sh}" ]]; then
source "${PARTICLE_CONFIG_FILE:-/usr/local/etc/particle-config.sh}"
else
# Fallback configuration
PARTICLE_WORKSPACE="${PARTICLE_WORKSPACE:-/var/lib/particle-os}"
PARTICLE_CONFIG_DIR="${PARTICLE_CONFIG_DIR:-/usr/local/etc/particle-os}"
PARTICLE_LOG_DIR="${PARTICLE_LOG_DIR:-/var/log/particle-os}"
PARTICLE_CACHE_DIR="${PARTICLE_CACHE_DIR:-/var/cache/particle-os}"
COMPOSEFS_SCRIPT="${PARTICLE_COMPOSEFS_SCRIPT:-/usr/local/bin/composefs-alternative.sh}"
PARTICLE_CONTAINER_RUNTIME="${PARTICLE_CONTAINER_RUNTIME:-podman}"
PARTICLE_TEMP_DIR="${PARTICLE_TEMP_DIR:-/tmp/particle-oci-$$}"
fi
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Logging functions
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
# Cleanup function
cleanup() {
if [[ -d "$PARTICLE_TEMP_DIR" ]]; then
log_info "Cleaning up temporary directory: $PARTICLE_TEMP_DIR"
rm -rf "$PARTICLE_TEMP_DIR" 2>/dev/null || true
fi
}
# Set up trap for cleanup
trap cleanup EXIT
# OCI export functions
export_composefs_to_oci() {
local composefs_image="$1"
local oci_image_name="$2"
local oci_tag="${3:-latest}"
local full_oci_name="$oci_image_name:$oci_tag"
log_info "Exporting ComposeFS image to OCI: $composefs_image -> $full_oci_name"
# Create temporary directory
mkdir -p "$PARTICLE_TEMP_DIR"
# Mount ComposeFS image
local mount_point="$PARTICLE_TEMP_DIR/mount"
mkdir -p "$mount_point"
log_info "Mounting ComposeFS image..."
if ! "$COMPOSEFS_SCRIPT" mount "$composefs_image" "$mount_point"; then
log_error "Failed to mount ComposeFS image: $composefs_image"
return 1
fi
# Create Containerfile
local containerfile="$PARTICLE_TEMP_DIR/Containerfile"
cat > "$containerfile" << EOF
FROM scratch
COPY . /
LABEL org.ubuntu.ublue.image="$composefs_image"
LABEL org.ubuntu.ublue.type="composefs-export"
LABEL org.ubuntu.ublue.created="$(date -Iseconds)"
CMD ["/bin/bash"]
EOF
# Build OCI image
log_info "Building OCI image..."
if ! "$PARTICLE_CONTAINER_RUNTIME" build -f "$containerfile" -t "$full_oci_name" "$mount_point"; then
log_error "Failed to build OCI image: $full_oci_name"
"$COMPOSEFS_SCRIPT" unmount "$mount_point"
return 1
fi
# Unmount ComposeFS image
"$COMPOSEFS_SCRIPT" unmount "$mount_point"
log_success "ComposeFS image exported to OCI: $full_oci_name"
return 0
}
# OCI import functions
import_oci_to_composefs() {
local oci_image_name="$1"
local composefs_image="$2"
local oci_tag="${3:-latest}"
local full_oci_name="$oci_image_name:$oci_tag"
log_info "Importing OCI image to ComposeFS: $full_oci_name -> $composefs_image"
# Create temporary directory
mkdir -p "$PARTICLE_TEMP_DIR"
# Create temporary container and export filesystem
local container_name="particle-import-$$"
log_info "Creating temporary container..."
if ! "$PARTICLE_CONTAINER_RUNTIME" create --name "$container_name" "$full_oci_name"; then
log_error "Failed to create temporary container from: $full_oci_name"
return 1
fi
# Export container filesystem
local export_dir="$PARTICLE_TEMP_DIR/export"
mkdir -p "$export_dir"
log_info "Exporting container filesystem..."
if ! "$PARTICLE_CONTAINER_RUNTIME" export "$container_name" | tar -xf - -C "$export_dir"; then
log_error "Failed to export container filesystem"
"$PARTICLE_CONTAINER_RUNTIME" rm "$container_name" >/dev/null 2>&1 || true
return 1
fi
# Remove temporary container
"$PARTICLE_CONTAINER_RUNTIME" rm "$container_name" >/dev/null 2>&1 || true
# Clean up device files and ephemeral directories that can't be in ComposeFS
log_info "Cleaning up device files and ephemeral directories..."
rm -rf "$export_dir"/{dev,proc,sys}/* 2>/dev/null || true
# Remove temporary and ephemeral directories
rm -rf "$export_dir"/tmp/* 2>/dev/null || true
rm -rf "$export_dir"/var/tmp/* 2>/dev/null || true
rm -rf "$export_dir"/run/* 2>/dev/null || true
rm -rf "$export_dir"/mnt/* 2>/dev/null || true
rm -rf "$export_dir"/media/* 2>/dev/null || true
# Create ComposeFS image
log_info "Creating ComposeFS image..."
if ! "$COMPOSEFS_SCRIPT" create "$composefs_image" "$export_dir"; then
log_error "Failed to create ComposeFS image: $composefs_image"
return 1
fi
log_success "OCI image imported to ComposeFS: $composefs_image"
return 0
}
# OCI push/pull functions
push_oci_image() {
local oci_image_name="$1"
local registry_url="${2:-}"
local oci_tag="${3:-latest}"
log_info "Pushing OCI image: $oci_image_name:$oci_tag"
# Add registry prefix if provided
local full_image_name="$oci_image_name"
if [[ -n "$registry_url" ]]; then
full_image_name="$registry_url/$oci_image_name"
fi
# Tag image with full name
if ! "$PARTICLE_CONTAINER_RUNTIME" tag "$oci_image_name:$oci_tag" "$full_image_name:$oci_tag"; then
log_error "Failed to tag image: $full_image_name:$oci_tag"
return 1
fi
# Push to registry
if ! "$PARTICLE_CONTAINER_RUNTIME" push "$full_image_name:$oci_tag"; then
log_error "Failed to push image: $full_image_name:$oci_tag"
return 1
fi
log_success "OCI image pushed: $full_image_name:$oci_tag"
return 0
}
pull_oci_image() {
local oci_image_name="$1"
local registry_url="${2:-}"
local oci_tag="${3:-latest}"
log_info "Pulling OCI image: $oci_image_name:$oci_tag"
# Add registry prefix if provided
local full_image_name="$oci_image_name"
if [[ -n "$registry_url" ]]; then
full_image_name="$registry_url/$oci_image_name"
fi
# Pull from registry
if ! "$PARTICLE_CONTAINER_RUNTIME" pull "$full_image_name:$oci_tag"; then
log_error "Failed to pull image: $full_image_name:$oci_tag"
return 1
fi
# Tag with local name
if ! "$PARTICLE_CONTAINER_RUNTIME" tag "$full_image_name:$oci_tag" "$oci_image_name:$oci_tag"; then
log_error "Failed to tag image: $oci_image_name:$oci_tag"
return 1
fi
log_success "OCI image pulled: $oci_image_name:$oci_tag"
return 0
}
# OCI image inspection
inspect_oci_image() {
local oci_image_name="$1"
local oci_tag="${2:-latest}"
local full_image_name="$oci_image_name:$oci_tag"
log_info "Inspecting OCI image: $full_image_name"
if ! "$PARTICLE_CONTAINER_RUNTIME" inspect "$full_image_name"; then
log_error "Failed to inspect image: $full_image_name"
return 1
fi
return 0
}
# List OCI images
list_oci_images() {
log_info "Listing OCI images:"
echo
"$PARTICLE_CONTAINER_RUNTIME" images
}
# Remove OCI image
remove_oci_image() {
local oci_image_name="$1"
local oci_tag="${2:-latest}"
local full_image_name="$oci_image_name:$oci_tag"
log_info "Removing OCI image: $full_image_name"
if ! "$PARTICLE_CONTAINER_RUNTIME" rmi "$full_image_name"; then
log_error "Failed to remove image: $full_image_name"
return 1
fi
log_success "OCI image removed: $full_image_name"
return 0
}
# Integration with apt-layer.sh
integrate_with_apt_layer() {
local operation="$1"
local composefs_image="$2"
local oci_image_name="$3"
local oci_tag="${4:-latest}"
case "$operation" in
"export")
log_info "Integrating OCI export with apt-layer: $composefs_image"
export_composefs_to_oci "$composefs_image" "$oci_image_name" "$oci_tag"
;;
"import")
log_info "Integrating OCI import with apt-layer: $oci_image_name"
import_oci_to_composefs "$oci_image_name" "$composefs_image" "$oci_tag"
;;
*)
log_error "Unknown operation: $operation"
return 1
;;
esac
return 0
}
# Main function
main() {
# Check dependencies
if [[ ! -f "$COMPOSEFS_SCRIPT" ]]; then
log_error "composefs-alternative.sh not found at: $COMPOSEFS_SCRIPT"
exit 1
fi
if ! command -v "$PARTICLE_CONTAINER_RUNTIME" >/dev/null 2>&1; then
log_error "Container runtime not found: $PARTICLE_CONTAINER_RUNTIME"
exit 1
fi
# Parse command line arguments
case "${1:-}" in
"export")
if [[ -z "${2:-}" ]] || [[ -z "${3:-}" ]]; then
log_error "ComposeFS image and OCI image name required for export"
exit 1
fi
export_composefs_to_oci "$2" "$3" "${4:-}"
;;
"import")
if [[ -z "${2:-}" ]] || [[ -z "${3:-}" ]]; then
log_error "OCI image name and ComposeFS image required for import"
exit 1
fi
import_oci_to_composefs "$2" "$3" "${4:-}"
;;
"push")
if [[ -z "${2:-}" ]]; then
log_error "OCI image name required for push"
exit 1
fi
push_oci_image "$2" "${3:-}" "${4:-}"
;;
"pull")
if [[ -z "${2:-}" ]]; then
log_error "OCI image name required for pull"
exit 1
fi
pull_oci_image "$2" "${3:-}" "${4:-}"
;;
"inspect")
if [[ -z "${2:-}" ]]; then
log_error "OCI image name required for inspect"
exit 1
fi
inspect_oci_image "$2" "${3:-}"
;;
"list")
list_oci_images
;;
"remove")
if [[ -z "${2:-}" ]]; then
log_error "OCI image name required for remove"
exit 1
fi
remove_oci_image "$2" "${3:-}"
;;
"integrate")
if [[ -z "${2:-}" ]] || [[ -z "${3:-}" ]] || [[ -z "${4:-}" ]]; then
log_error "Operation, ComposeFS image, and OCI image name required for integrate"
exit 1
fi
integrate_with_apt_layer "$2" "$3" "$4" "${5:-}"
;;
"help"|"-h"|"--help")
cat << EOF
Particle-OS OCI Integration
Usage: $0 <command> [options]
Commands:
export <composefs> <oci> [tag] Export ComposeFS image to OCI
import <oci> <composefs> [tag] Import OCI image to ComposeFS
push <oci> [registry] [tag] Push OCI image to registry
pull <oci> [registry] [tag] Pull OCI image from registry
inspect <oci> [tag] Inspect OCI image
list List OCI images
remove <oci> [tag] Remove OCI image
integrate <op> <composefs> <oci> [tag] Integrate with apt-layer.sh
Operations for integrate:
export Export ComposeFS to OCI
import Import OCI to ComposeFS
Examples:
$0 export particle-os/gaming/24.04 particle-os/gaming:latest
$0 import ubuntu:24.04 particle-os/base/24.04
$0 push particle-os/gaming registry.example.com latest
$0 integrate export particle-os/gaming/24.04 particle-os/gaming
Environment Variables:
PARTICLE_CONTAINER_RUNTIME=podman Container runtime to use
PARTICLE_REGISTRY_URL=registry.example.com Default registry URL
PARTICLE_CONFIG_FILE=/path/to/config.sh Configuration file path
PARTICLE_WORKSPACE=/var/lib/particle-os Workspace directory
PARTICLE_COMPOSEFS_SCRIPT=/path/to/composefs ComposeFS script path
EOF
;;
*)
log_error "Unknown command: ${1:-}"
echo "Use '$0 help' for usage information"
exit 1
;;
esac
}
# Run main function
main "$@"