#!/bin/bash # Turmli Bar Calendar Tool - Podman Deployment Script # Compatible with Podman and Podman-compose set -e # Exit on error # 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 IMAGE_NAME="turmli-calendar" CONTAINER_NAME="turmli-calendar" DEFAULT_PORT=8000 CACHE_FILE="calendar_cache.json" # Print functions print_error() { echo -e "${RED}❌ $1${NC}" } print_success() { echo -e "${GREEN}✅ $1${NC}" } print_info() { echo -e "${BLUE}ℹ️ $1${NC}" } print_warning() { echo -e "${YELLOW}⚠️ $1${NC}" } # Check for podman or docker check_container_runtime() { if command -v podman &> /dev/null; then RUNTIME="podman" print_success "Podman is installed" elif command -v docker &> /dev/null; then RUNTIME="docker" print_warning "Podman not found, using Docker instead" else print_error "Neither Podman nor Docker is installed. Please install Podman or Docker first." exit 1 fi } # Check for podman-compose or docker-compose check_compose() { if command -v podman-compose &> /dev/null; then COMPOSE="podman-compose" COMPOSE_FILE="podman-compose.yml" print_success "podman-compose is installed" elif command -v docker-compose &> /dev/null; then COMPOSE="docker-compose" COMPOSE_FILE="docker-compose.yml" print_warning "podman-compose not found, using docker-compose instead" else print_warning "Compose tool not found. Will use standalone container commands." COMPOSE="" fi } build() { print_info "Building container image..." # Detect architecture ARCH=$(uname -m) print_info "Detected architecture: ${ARCH}" # Choose appropriate Dockerfile based on architecture and availability if [ -f "Dockerfile.minimal" ]; then BUILD_FILE="Dockerfile.minimal" print_info "Using minimal Dockerfile (no compilation required)" elif [ "$ARCH" = "armv6l" ] || [ "$ARCH" = "armv7l" ] || [ "$ARCH" = "aarch64" ]; then # ARM architecture (Raspberry Pi, etc.) if [ -f "Dockerfile.arm" ]; then BUILD_FILE="Dockerfile.arm" print_info "Using ARM-optimized Dockerfile" elif [ -f "Containerfile" ]; then BUILD_FILE="Containerfile" else BUILD_FILE="Dockerfile" fi else # x86_64 or other architectures if [ -f "Containerfile" ]; then BUILD_FILE="Containerfile" else BUILD_FILE="Dockerfile" fi fi print_info "Using build file: ${BUILD_FILE}" ${RUNTIME} build -f ${BUILD_FILE} -t ${IMAGE_NAME} . || { print_error "Failed to build container image" print_info "Try using Dockerfile.minimal with simplified dependencies" exit 1 } print_success "Container image built successfully" } start() { print_info "Starting calendar application..." # Create cache file if it doesn't exist if [ ! -f "${CACHE_FILE}" ]; then echo "{}" > ${CACHE_FILE} print_info "Created cache file: ${CACHE_FILE}" fi if [ -n "$COMPOSE" ] && [ -f "$COMPOSE_FILE" ]; then # Use compose if available print_info "Starting with ${COMPOSE}..." ${COMPOSE} -f ${COMPOSE_FILE} up -d || { print_error "Failed to start application with compose" exit 1 } else # Use standalone container command print_info "Starting with ${RUNTIME}..." # Check if container already exists if ${RUNTIME} ps -a --format '{{.Names}}' 2>/dev/null | grep -q "^${CONTAINER_NAME}$"; then print_info "Container already exists, removing it..." ${RUNTIME} rm -f ${CONTAINER_NAME} fi # Run container with Podman-specific options ${RUNTIME} run -d \ --name ${CONTAINER_NAME} \ -p ${PORT:-$DEFAULT_PORT}:8000 \ -e TZ=${TZ:-Europe/Berlin} \ -e PYTHONUNBUFFERED=1 \ -v $(pwd)/${CACHE_FILE}:/app/${CACHE_FILE}:Z \ --restart unless-stopped \ ${IMAGE_NAME} || { print_error "Failed to start container" exit 1 } fi print_success "Application started successfully" print_info "Access the calendar at: http://localhost:${PORT:-$DEFAULT_PORT}" } stop() { print_info "Stopping calendar application..." if [ -n "$COMPOSE" ] && [ -f "$COMPOSE_FILE" ]; then ${COMPOSE} -f ${COMPOSE_FILE} down || true else ${RUNTIME} stop ${CONTAINER_NAME} 2>/dev/null || true ${RUNTIME} rm ${CONTAINER_NAME} 2>/dev/null || true fi print_success "Application stopped" } restart() { stop start } logs() { if [ -n "$COMPOSE" ] && [ -f "$COMPOSE_FILE" ]; then ${COMPOSE} -f ${COMPOSE_FILE} logs -f else ${RUNTIME} logs -f ${CONTAINER_NAME} fi } status() { echo -e "${BLUE}Container Status:${NC}" if [ -n "$COMPOSE" ] && [ -f "$COMPOSE_FILE" ]; then ${COMPOSE} -f ${COMPOSE_FILE} ps else if ${RUNTIME} ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep -q ${CONTAINER_NAME}; then ${RUNTIME} ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep -E "NAMES|${CONTAINER_NAME}" else print_info "Container is not running" return fi fi echo "" print_info "Testing application..." if curl -s -f http://localhost:${PORT:-$DEFAULT_PORT}/api/events > /dev/null 2>&1; then print_success "Application is healthy and responding" else print_error "Application is not responding" fi } clean() { print_info "Cleaning up..." stop # Remove image ${RUNTIME} rmi ${IMAGE_NAME} 2>/dev/null || true # Clean up build cache (Podman specific) if [ "$RUNTIME" = "podman" ]; then ${RUNTIME} system prune -f 2>/dev/null || true fi print_success "Cleanup complete" } # Generate systemd service for rootless Podman generate_systemd() { if [ "$RUNTIME" != "podman" ]; then print_error "Systemd generation is only available for Podman" exit 1 fi print_info "Generating systemd service for rootless Podman..." # Check if container is running if ! ${RUNTIME} ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then print_error "Container must be running to generate systemd service" print_info "Run './deploy-podman.sh start' first" exit 1 fi # Create user systemd directory if it doesn't exist mkdir -p ~/.config/systemd/user/ # Generate systemd files ${RUNTIME} generate systemd --name --files --new ${CONTAINER_NAME} # Move to user systemd directory mv container-${CONTAINER_NAME}.service ~/.config/systemd/user/ print_success "Systemd service generated" print_info "To enable the service:" echo " systemctl --user daemon-reload" echo " systemctl --user enable container-${CONTAINER_NAME}.service" echo " systemctl --user start container-${CONTAINER_NAME}.service" } # Show help show_help() { echo "Turmli Bar Calendar - Podman Deployment Script" echo "" echo "Usage: $0 {build|start|stop|restart|logs|status|clean|systemd|info|help}" echo "" echo "Commands:" echo " build - Build the container image" echo " start - Build and start the application" echo " stop - Stop the application" echo " restart - Restart the application" echo " logs - Show application logs" echo " status - Check application status" echo " clean - Remove containers and images" echo " systemd - Generate systemd service (Podman only)" echo " info - Show system and architecture information" echo " help - Show this help message" echo "" echo "Environment Variables:" echo " PORT - Port to expose (default: 8000)" echo " TZ - Timezone (default: Europe/Berlin)" echo "" echo "Architecture Notes:" echo " Dockerfile.minimal - Works on all architectures (no compilation)" echo " Dockerfile.arm - ARM-optimized with simplified dependencies" echo " Dockerfile - Standard multi-stage build (requires compilation)" } # Show system information show_info() { echo -e "${BLUE}System Information:${NC}" echo " Architecture: $(uname -m)" echo " OS: $(uname -s)" echo " Kernel: $(uname -r)" if command -v podman &> /dev/null; then echo "" echo -e "${BLUE}Podman Information:${NC}" podman version --format " Version: {{.Client.Version}}" podman info --format " Storage Driver: {{.Store.GraphDriverName}}" podman info --format " Root: {{.Store.GraphRoot}}" fi if command -v docker &> /dev/null; then echo "" echo -e "${BLUE}Docker Information:${NC}" docker version --format " Version: {{.Client.Version}}" 2>/dev/null || echo " Docker daemon not accessible" fi echo "" echo -e "${BLUE}Build Configuration:${NC}" ARCH=$(uname -m) if [ -f "Dockerfile.minimal" ]; then echo " Will use: Dockerfile.minimal (no compilation required)" echo " Perfect for: All architectures including ARM/Raspberry Pi" elif [ "$ARCH" = "armv6l" ] || [ "$ARCH" = "armv7l" ] || [ "$ARCH" = "aarch64" ]; then echo " ARM architecture detected" if [ -f "Dockerfile.arm" ]; then echo " Will use: Dockerfile.arm (simplified dependencies)" else echo " Will use: Standard Dockerfile (may require longer build time)" fi else echo " x86_64/standard architecture detected" echo " Will use: Dockerfile or Containerfile" fi } # Main script case "$1" in build) check_container_runtime build ;; start) check_container_runtime check_compose build start ;; stop) check_container_runtime check_compose stop ;; restart) check_container_runtime check_compose restart ;; logs) check_container_runtime check_compose logs ;; status) check_container_runtime check_compose status ;; clean) check_container_runtime clean ;; systemd) check_container_runtime generate_systemd ;; info) show_info ;; help) show_help ;; *) show_help exit 1 ;; esac