402 lines
12 KiB
Bash
Executable File
402 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
|
# deploy-podman.sh - Production Podman deployment script for HMAC File Server 3.2
|
|
# Usage: ./deploy-podman.sh [start|stop|restart|status|logs|config]
|
|
|
|
set -euo pipefail
|
|
|
|
# Color codes for pretty output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Logging functions
|
|
info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
|
success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
|
|
warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
|
|
error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
|
|
|
# Configuration variables
|
|
readonly APP_NAME='hmac-file-server'
|
|
readonly POD_NAME='xmpp-pod'
|
|
readonly CTR_NAME="${POD_NAME}-${APP_NAME}"
|
|
readonly CTR_IMAGE='localhost/hmac-file-server:latest'
|
|
readonly RESTART_POLICY='unless-stopped'
|
|
readonly CTR_UID='1011'
|
|
readonly APP_DATA="${APP_DATA:-/opt/podman/hmac-file-server}"
|
|
readonly LISTEN_PORT="${LISTEN_PORT:-8888}"
|
|
readonly METRICS_PORT="${METRICS_PORT:-9090}"
|
|
readonly CONFIG_FILE="${APP_DATA}/config/config.toml"
|
|
|
|
# Check if running as root (not recommended for Podman)
|
|
check_user() {
|
|
if [[ $EUID -eq 0 ]]; then
|
|
warning "Running as root. Consider using Podman rootless for better security."
|
|
read -p "Continue anyway? (y/N): " -n 1 -r
|
|
echo
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
exit 1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Create application directories
|
|
setup_directories() {
|
|
info "Setting up application directories..."
|
|
|
|
mkdir -p "${APP_DATA}"/{config,data,deduplication,logs}
|
|
|
|
# Set proper ownership
|
|
if command -v podman >/dev/null 2>&1; then
|
|
podman unshare chown -R "${CTR_UID}:${CTR_UID}" "${APP_DATA}"
|
|
else
|
|
error "Podman not found. Please install Podman first."
|
|
exit 1
|
|
fi
|
|
|
|
success "Directories created at ${APP_DATA}"
|
|
}
|
|
|
|
# Generate configuration file
|
|
generate_config() {
|
|
if [[ -f "${CONFIG_FILE}" ]]; then
|
|
warning "Configuration file already exists at ${CONFIG_FILE}"
|
|
read -p "Overwrite? (y/N): " -n 1 -r
|
|
echo
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
info "Generating configuration file..."
|
|
|
|
# Generate random secrets
|
|
local hmac_secret=$(openssl rand -base64 32 2>/dev/null || head -c 32 /dev/urandom | base64)
|
|
local jwt_secret=$(openssl rand -base64 32 2>/dev/null || head -c 32 /dev/urandom | base64)
|
|
|
|
cat > "${CONFIG_FILE}" << EOF
|
|
# HMAC File Server 3.2 - Podman Production Configuration
|
|
# Generated on $(date)
|
|
|
|
[server]
|
|
listen_address = "${LISTEN_PORT}"
|
|
storage_path = "/data"
|
|
metrics_enabled = true
|
|
metrics_port = "${METRICS_PORT}"
|
|
max_upload_size = "10GB"
|
|
max_header_bytes = 1048576
|
|
cleanup_interval = "24h"
|
|
max_file_age = "720h"
|
|
enable_dynamic_workers = true
|
|
worker_scale_up_thresh = 40
|
|
worker_scale_down_thresh = 10
|
|
deduplication_enabled = true
|
|
min_free_bytes = "1GB"
|
|
file_naming = "original"
|
|
networkevents = true # Enable network monitoring for resilience
|
|
|
|
[uploads]
|
|
# XMPP-compatible file extensions for maximum client support
|
|
allowed_extensions = [".zip", ".rar", ".7z", ".tar.gz", ".tgz", ".gpg", ".enc", ".pgp", ".txt", ".pdf", ".png", ".jpg", ".jpeg", ".gif", ".bmp", ".tiff", ".svg", ".webp", ".wav", ".mp4", ".avi", ".mkv", ".mov", ".wmv", ".flv", ".webm", ".mpeg", ".mpg", ".m4v", ".3gp", ".3g2", ".mp3", ".ogg", ".doc", ".docx"]
|
|
chunked_uploads_enabled = true
|
|
chunk_size = "32MB"
|
|
resumable_uploads_enabled = true
|
|
max_resumable_age = "48h"
|
|
sessiontimeout = "60m"
|
|
maxretries = 3
|
|
|
|
# Upload resilience settings
|
|
session_persistence = true
|
|
session_recovery_timeout = "300s"
|
|
client_reconnect_window = "120s"
|
|
upload_slot_ttl = "3600s"
|
|
retry_failed_uploads = true
|
|
max_upload_retries = 3
|
|
|
|
# Enhanced Network Resilience (NEW)
|
|
[network_resilience]
|
|
fast_detection = true # 1-second network change detection
|
|
quality_monitoring = true # Monitor RTT and packet loss
|
|
predictive_switching = true # Proactive network switching
|
|
mobile_optimizations = true # Mobile-friendly thresholds
|
|
detection_interval = "1s"
|
|
quality_check_interval = "5s"
|
|
max_detection_interval = "10s"
|
|
|
|
[downloads]
|
|
resumable_downloads_enabled = true
|
|
chunked_downloads_enabled = true
|
|
chunk_size = "32MB"
|
|
# Same extensions as uploads for consistency
|
|
allowed_extensions = [".zip", ".rar", ".7z", ".tar.gz", ".tgz", ".gpg", ".enc", ".pgp", ".txt", ".pdf", ".png", ".jpg", ".jpeg", ".gif", ".bmp", ".tiff", ".svg", ".webp", ".wav", ".mp4", ".avi", ".mkv", ".mov", ".wmv", ".flv", ".webm", ".mpeg", ".mpg", ".m4v", ".3gp", ".3g2", ".mp3", ".ogg", ".doc", ".docx"]
|
|
|
|
[security]
|
|
secret = "${hmac_secret}"
|
|
enablejwt = true
|
|
jwtsecret = "${jwt_secret}"
|
|
jwtalgorithm = "HS256"
|
|
jwtexpiration = "24h"
|
|
|
|
[logging]
|
|
level = "info"
|
|
file = "/logs/hmac-file-server.log"
|
|
max_size = 100
|
|
max_backups = 7
|
|
max_age = 30
|
|
compress = true
|
|
|
|
[deduplication]
|
|
enabled = true
|
|
directory = "/deduplication"
|
|
|
|
[workers]
|
|
numworkers = 4
|
|
uploadqueuesize = 100
|
|
|
|
[timeouts]
|
|
readtimeout = "3600s"
|
|
writetimeout = "3600s"
|
|
idletimeout = "3600s"
|
|
shutdown = "30s"
|
|
EOF
|
|
|
|
success "Configuration generated at ${CONFIG_FILE}"
|
|
warning "Secrets have been auto-generated. Keep this file secure!"
|
|
}
|
|
|
|
# Build container image
|
|
build_image() {
|
|
info "Checking if image ${CTR_IMAGE} exists..."
|
|
|
|
if podman image exists "${CTR_IMAGE}"; then
|
|
warning "Image ${CTR_IMAGE} already exists"
|
|
read -p "Rebuild? (y/N): " -n 1 -r
|
|
echo
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
info "Building container image ${CTR_IMAGE}..."
|
|
|
|
# Find the Dockerfile
|
|
local dockerfile_path
|
|
if [[ -f "dockerenv/podman/Dockerfile.podman" ]]; then
|
|
dockerfile_path="dockerenv/podman/Dockerfile.podman"
|
|
elif [[ -f "Dockerfile.podman" ]]; then
|
|
dockerfile_path="Dockerfile.podman"
|
|
else
|
|
error "Dockerfile.podman not found. Please run from project root or ensure file exists."
|
|
exit 1
|
|
fi
|
|
|
|
podman build --no-cache -t "${CTR_IMAGE}" -f "${dockerfile_path}" .
|
|
|
|
success "Image ${CTR_IMAGE} built successfully"
|
|
}
|
|
|
|
# Create pod for networking
|
|
create_pod() {
|
|
info "Creating pod ${POD_NAME}..."
|
|
|
|
# Remove existing pod if it exists
|
|
if podman pod exists "${POD_NAME}"; then
|
|
warning "Pod ${POD_NAME} already exists, removing..."
|
|
podman pod stop "${POD_NAME}" 2>/dev/null || true
|
|
podman pod rm "${POD_NAME}" 2>/dev/null || true
|
|
fi
|
|
|
|
podman pod create --name "${POD_NAME}" \
|
|
--publish "${LISTEN_PORT}:8888" \
|
|
--publish "${METRICS_PORT}:9090"
|
|
|
|
success "Pod ${POD_NAME} created"
|
|
}
|
|
|
|
# Start the container
|
|
start_container() {
|
|
info "Starting HMAC File Server container..."
|
|
|
|
# Stop and remove existing container
|
|
podman container stop "${CTR_NAME}" 2>/dev/null || true
|
|
podman container rm "${CTR_NAME}" 2>/dev/null || true
|
|
|
|
# Run container with security-hardened settings
|
|
podman run -d \
|
|
--pod="${POD_NAME}" \
|
|
--restart="${RESTART_POLICY}" \
|
|
--name "${CTR_NAME}" \
|
|
--user "${CTR_UID}:${CTR_UID}" \
|
|
--cap-drop=ALL \
|
|
--security-opt no-new-privileges \
|
|
--read-only \
|
|
--tmpfs /tmp:rw,noexec,nosuid,size=100m \
|
|
-v "${CONFIG_FILE}:/app/config.toml:ro,Z" \
|
|
-v "${APP_DATA}/data:/data:rw,Z" \
|
|
-v "${APP_DATA}/deduplication:/deduplication:rw,Z" \
|
|
-v "${APP_DATA}/logs:/logs:rw,Z" \
|
|
--health-cmd="curl -f http://localhost:8888/health || exit 1" \
|
|
--health-interval=30s \
|
|
--health-timeout=10s \
|
|
--health-retries=3 \
|
|
--health-start-period=40s \
|
|
"${CTR_IMAGE}" -config /app/config.toml
|
|
|
|
success "Container ${CTR_NAME} started successfully!"
|
|
}
|
|
|
|
# Stop the container
|
|
stop_container() {
|
|
info "Stopping HMAC File Server..."
|
|
|
|
podman container stop "${CTR_NAME}" 2>/dev/null || true
|
|
podman container rm "${CTR_NAME}" 2>/dev/null || true
|
|
podman pod stop "${POD_NAME}" 2>/dev/null || true
|
|
podman pod rm "${POD_NAME}" 2>/dev/null || true
|
|
|
|
success "HMAC File Server stopped"
|
|
}
|
|
|
|
# Show status
|
|
show_status() {
|
|
echo
|
|
info "=== HMAC File Server Status ==="
|
|
|
|
if podman pod exists "${POD_NAME}"; then
|
|
echo "Pod Status:"
|
|
podman pod ps --filter "name=${POD_NAME}"
|
|
echo
|
|
fi
|
|
|
|
if podman container exists "${CTR_NAME}"; then
|
|
echo "Container Status:"
|
|
podman ps --filter "name=${CTR_NAME}"
|
|
echo
|
|
|
|
echo "Health Status:"
|
|
podman healthcheck run "${CTR_NAME}" 2>/dev/null && echo "✅ Healthy" || echo "❌ Unhealthy"
|
|
echo
|
|
else
|
|
warning "Container ${CTR_NAME} not found"
|
|
fi
|
|
|
|
echo "Service URLs:"
|
|
echo " 🌐 File Server: http://localhost:${LISTEN_PORT}"
|
|
echo " 📊 Metrics: http://localhost:${METRICS_PORT}/metrics"
|
|
echo " 🔍 Health Check: http://localhost:${LISTEN_PORT}/health"
|
|
echo
|
|
}
|
|
|
|
# Show logs
|
|
show_logs() {
|
|
if podman container exists "${CTR_NAME}"; then
|
|
info "Showing logs for ${CTR_NAME} (Ctrl+C to exit)..."
|
|
podman logs -f "${CTR_NAME}"
|
|
else
|
|
error "Container ${CTR_NAME} not found"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Full deployment
|
|
deploy() {
|
|
info "Starting full HMAC File Server deployment..."
|
|
|
|
check_user
|
|
setup_directories
|
|
generate_config
|
|
build_image
|
|
create_pod
|
|
start_container
|
|
|
|
sleep 5 # Wait for container to start
|
|
show_status
|
|
|
|
success "🎉 HMAC File Server deployed successfully!"
|
|
echo
|
|
info "Next steps:"
|
|
echo "1. Test the service: curl -f http://localhost:${LISTEN_PORT}/health"
|
|
echo "2. View logs: ./deploy-podman.sh logs"
|
|
echo "3. Check status: ./deploy-podman.sh status"
|
|
echo "4. Edit config: ${CONFIG_FILE}"
|
|
echo
|
|
}
|
|
|
|
# Main command dispatcher
|
|
case "${1:-deploy}" in
|
|
start|deploy)
|
|
deploy
|
|
;;
|
|
stop)
|
|
stop_container
|
|
;;
|
|
restart)
|
|
stop_container
|
|
sleep 2
|
|
create_pod
|
|
start_container
|
|
show_status
|
|
;;
|
|
status)
|
|
show_status
|
|
;;
|
|
logs)
|
|
show_logs
|
|
;;
|
|
config)
|
|
info "Configuration file location: ${CONFIG_FILE}"
|
|
if [[ -f "${CONFIG_FILE}" ]]; then
|
|
echo "Current configuration:"
|
|
cat "${CONFIG_FILE}"
|
|
else
|
|
warning "Configuration file not found. Run './deploy-podman.sh' to generate it."
|
|
fi
|
|
;;
|
|
build)
|
|
build_image
|
|
;;
|
|
pod)
|
|
create_pod
|
|
;;
|
|
clean)
|
|
warning "This will remove all containers, pods, and the image. Data will be preserved."
|
|
read -p "Continue? (y/N): " -n 1 -r
|
|
echo
|
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
stop_container
|
|
podman image rm "${CTR_IMAGE}" 2>/dev/null || true
|
|
success "Cleanup completed"
|
|
fi
|
|
;;
|
|
help|--help|-h)
|
|
echo "HMAC File Server Podman Deployment Script"
|
|
echo
|
|
echo "Usage: $0 [COMMAND]"
|
|
echo
|
|
echo "Commands:"
|
|
echo " deploy Full deployment (default)"
|
|
echo " start Start services"
|
|
echo " stop Stop all services"
|
|
echo " restart Restart services"
|
|
echo " status Show service status"
|
|
echo " logs Show container logs"
|
|
echo " config Show configuration"
|
|
echo " build Build container image only"
|
|
echo " pod Create pod only"
|
|
echo " clean Remove containers and image"
|
|
echo " help Show this help"
|
|
echo
|
|
echo "Environment Variables:"
|
|
echo " APP_DATA Data directory (default: /opt/podman/hmac-file-server)"
|
|
echo " LISTEN_PORT Server port (default: 8888)"
|
|
echo " METRICS_PORT Metrics port (default: 9090)"
|
|
echo
|
|
;;
|
|
*)
|
|
error "Unknown command: $1"
|
|
echo "Run '$0 help' for usage information"
|
|
exit 1
|
|
;;
|
|
esac
|