365 lines
11 KiB
Bash
Executable File
365 lines
11 KiB
Bash
Executable File
#!/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 |