#!/bin/bash #================================================================ # HEADER #================================================================ #% SYNOPSIS #+ update-containers.sh #% #% DESCRIPTION #+ Updates all Docker container images in the media stack by pulling #+ the latest versions and restarting the compose stack. #% #% OPTIONS #+ None #% #% EXAMPLES #+ ./update-containers.sh #% #% NOTES #+ - Requires Docker and Docker Compose to be installed #+ - Must be run from a directory containing docker-compose.yml #+ - Stops all containers before updating, then restarts them #+ - Handles missing images gracefully with warnings #% #% AUTHOR #+ AceDanger #% #% VERSION #+ 1.1.0 #% #% SECURITY #+ - All variables are properly quoted to prevent command injection #+ - Input validation on Docker commands and image names #+ - Temporary files use secure locations with proper cleanup #+ - Error handling prevents script continuation on critical failures #% #================================================================ # Enable strict error handling set -euo pipefail # Constants readonly SCRIPT_NAME="$(basename "$0")" readonly DOCKER_MEDIA_DIR="$HOME/docker/media" readonly ERROR_FILE="/tmp/docker-images-update-$$.error" # Cleanup function cleanup() { if [[ -f "$ERROR_FILE" ]]; then rm -f "$ERROR_FILE" fi } # Set up cleanup trap trap cleanup EXIT ERR # Function to log messages with timestamp log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" } # Function to validate Docker image name format validate_image_name() { local image="$1" # Basic validation for Docker image name format # Allow alphanumeric, hyphens, underscores, dots, slashes, and colons if [[ ! "$image" =~ ^[a-zA-Z0-9._/-]+:[a-zA-Z0-9._-]+$ ]]; then log "ERROR: Invalid Docker image name format: $image" return 1 fi return 0 } # Change to docker media directory if [[ ! -d "$DOCKER_MEDIA_DIR" ]]; then log "ERROR: Docker media directory does not exist: $DOCKER_MEDIA_DIR" exit 1 fi cd "$DOCKER_MEDIA_DIR" || { log "ERROR: Failed to change to directory: $DOCKER_MEDIA_DIR" exit 1 } # Stop docker compose log "Stopping Docker Compose stack" if ! docker compose down; then log "ERROR: Failed to stop Docker Compose stack" exit 1 fi # Verify Docker is running log "Checking Docker daemon status" if ! docker info >/dev/null 2>&1; then log "ERROR: Docker daemon is not running or accessible" exit 1 fi log "Docker is running, continuing with image updates" # Get list of currently installed Docker images log "Retrieving list of installed Docker images" IMAGES_WITH_TAGS=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -v ":" || true) if [[ -z "$IMAGES_WITH_TAGS" ]]; then log "WARNING: No Docker images found to update" else log "Found $(echo "$IMAGES_WITH_TAGS" | wc -l) images to update" # Process each image while IFS= read -r IMAGE; do [[ -z "$IMAGE" ]] && continue log "Processing image: $IMAGE" # Validate image name format if ! validate_image_name "$IMAGE"; then log "WARNING: Skipping invalid image name: $IMAGE" continue fi log "Updating $IMAGE" # Pull the image with error handling if docker pull "$IMAGE" 2>"$ERROR_FILE"; then log "Successfully updated: $IMAGE" else # Check if the error is due to image not found if grep -q "not found\|pull access denied\|repository does not exist" "$ERROR_FILE" 2>/dev/null; then log "WARNING: Docker image $IMAGE not found in repository, skipping" else log "ERROR: Failed to pull image $IMAGE" if [[ -f "$ERROR_FILE" ]]; then log "Error details: $(cat "$ERROR_FILE")" fi exit 2 fi fi log "Completed processing: $IMAGE" echo done <<< "$IMAGES_WITH_TAGS" fi # Restart Docker Compose stack log "Restarting Docker Compose stack" if ! docker compose up -d; then log "ERROR: Failed to restart Docker Compose stack" exit 3 fi # Verify stack is running properly log "Verifying Docker Compose stack status" if docker compose ps --format "table {{.Name}}\t{{.Status}}" | grep -v "Up"; then log "WARNING: Some containers may not be running properly" docker compose ps else log "All containers are running successfully" fi log "Docker images update completed successfully" exit 0