Add container exclusion

This commit is contained in:
sky
2025-09-01 00:28:20 +02:00
parent 9a64b7e9af
commit ab9b10acd9
5 changed files with 94 additions and 268 deletions

View File

@@ -1,47 +0,0 @@
#!/bin/bash
# This script is designed to perform an annual backup of a source directory directly to a compressed `.tar.xz` archive for maximum compression.
# It allows excluding specified files or directories from the archive during the backup process.
# Additionally, it generates a SHA-256 checksum for each archive, saving it in a corresponding `.sha256` file for integrity verification.
# Finally, it removes older archives and their checksum files exceeding a specified retention period (e.g., 5 years), ensuring backup rotation.
# Usage:
# To use this script, save it as "annual_backup_with_max_compression.sh" and make it executable with the command `chmod +x annual_backup_with_max_compression.sh`.
# You can define exclusions either in the EXCLUDE_LIST array or in a file specified by EXCLUDE_FILE.
# Automate the execution annually by adding this cron job: `0 0 1 1 * /path/to/script/annual_backup_with_max_compression.sh`
# Variables
SOURCE_DIR="/path/to/source_directory" # Source directory to back up
ARCHIVE_DIR="/path/to/archive_directory" # Directory where tar.xz archives are stored
ARCHIVE_NAME="backup-$(date +%Y).tar.xz" # Archive name with the year
CHECKSUM_FILE="$ARCHIVE_NAME.sha256" # SHA-256 checksum file name (relative path)
RETENTION_YEARS=5 # Number of years to retain archives
RETENTION_DAYS=$((RETENTION_YEARS * 365)) # Retention period in days (5 years)
# Exclusion settings
EXCLUDE_LIST=() # Inline exclusion list, add patterns here (e.g., "*.tmp", "node_modules")
EXCLUDE_FILE="" # File with additional exclude patterns, one per line (e.g., "/path/to/exclude_file.txt")
# Build tar exclusion options
TAR_EXCLUDE_OPTIONS=()
for pattern in "${EXCLUDE_LIST[@]}"; do
TAR_EXCLUDE_OPTIONS+=("--exclude=$pattern")
done
if [ -n "$EXCLUDE_FILE" ]; then
TAR_EXCLUDE_OPTIONS+=("--exclude-from=$EXCLUDE_FILE")
fi
# 1. Create a tar.xz archive directly from the source directory with maximum compression, preserving file permissions
tar -cJf "$ARCHIVE_DIR/$ARCHIVE_NAME" "${TAR_EXCLUDE_OPTIONS[@]}" -C "$SOURCE_DIR" . --preserve-permissions
# 2. Change to the archive directory and generate a SHA-256 checksum with relative paths
(
cd "$ARCHIVE_DIR" || exit
sha256sum "$ARCHIVE_NAME" > "$CHECKSUM_FILE"
)
# 3. Remove older archives and checksum files (older than 5 years)
find "$ARCHIVE_DIR" -type f -name "backup-*.tar.xz" -mtime +$RETENTION_DAYS -exec rm {} \;
find "$ARCHIVE_DIR" -type f -name "backup-*.tar.xz.sha256" -mtime +$RETENTION_DAYS -exec rm {} \;
echo "Annual backup with maximum compression and checksum completed: $ARCHIVE_NAME"

View File

@@ -1,54 +0,0 @@
#!/bin/bash
# This script creates a .tar.xz archive of a specified source directory, preserving file permissions,
# and names the archive using the source directory's name followed by the current date in DDMMYYYY format.
# Additionally, it generates a SHA-256 checksum file for the archive in the specified output directory.
# Usage:
# 1. Make the script executable: `chmod +x archive_with_checksum`
# 2. Run the script by providing the path to the source directory as the first argument
# and the path to the output directory as the second argument.
# Example: `./archive_with_checksum /path/to/source_directory /path/to/output_directory`
#
# The script will produce an archive named `source_directory_DDMMYYYY.tar.xz` and a checksum file
# named `source_directory_DDMMYYYY.tar.xz.sha256` in the specified output directory.
# Check if the correct number of arguments is provided
if [ "$#" -ne 2 ]; then
echo "Usage: $0 source_directory output_directory"
exit 1
fi
# Assign parameters
source_directory=$1
output_directory=$2
# Get the base name of the source directory (without the full path)
source_name=$(basename "$source_directory")
# Get the current date in DDMMYYYY format
current_date=$(date +%d%m%Y)
# Create the archive name with the date, based on the source directory's name
archive_name="${source_name}_${current_date}.tar.xz"
archive_path="${output_directory}/${archive_name}"
# Create the archive with file permissions preserved
tar -cJpf "$archive_path" "$source_directory"
# Confirm archive creation and create a checksum if successful
if [ $? -eq 0 ]; then
echo "Archive created: $archive_path"
# Generate SHA-256 checksum file for the archive in the output directory
checksum_file="${archive_path}.sha256"
sha256sum "$archive_path" > "$checksum_file"
if [ $? -eq 0 ]; then
echo "Checksum file created: $checksum_file"
else
echo "Error creating the checksum file."
fi
else
echo "Error creating the archive."
fi

View File

@@ -1,29 +0,0 @@
# This script creates a tar.gz backup of the /opt/AdGuardHome directory, cron jobs, and system logs.
# The backup is stored in the './backups/' directory.
#
# To automate backups, you can add this script to your crontab.
# For example, to run this backup on the 1st of every month, you would add the following line to your crontab:
# 0 0 1 * * /path/to/this/script.sh
# (Remember to replace '/path/to/this/script.sh' with the actual path to this script)
# You can edit your crontab with the command: crontab -e
# Get the current date in a suitable format for the filename
current_date=$(date +"%Y-%m-%d")
# Create the backup filename
backup_filename="adguardhome_backup_${current_date}.tar.gz"
# Default backup location
backup_location="./backups/"
# Create the 'adguardhome' directory if it doesn't exist
mkdir -p "$backup_location/adguardhome"
# Create the tar.gz archive
tar -czvf "$backup_location/adguardhome/$backup_filename" /opt/AdGuardHome /var/spool/cron/crontabs/* /var/log
# Print a success message
echo "Backup created successfully in $backup_location/adguardhome/$backup_filename"
# Delete backups older than 90 days
find "$backup_location/adguardhome" -mtime +90 -type f -delete

View File

@@ -1,68 +0,0 @@
#!/bin/bash
# This script backs up all running Docker containers.
# For each container, it creates a compressed archive file (.tar.gz) containing
# the container's state at the time of execution.
# Backups are stored in a directory called "backup_docker_container".
# Each backup file is named with the container name and the current date and time,
# making it easy to identify when the backup was taken.
#
# Usage:
# 1. Save this script to a file, for example: backup_containers.sh
# 2. Make the script executable: chmod +x backup_containers.sh
# 3. Run the script: ./backup_containers.sh
#
# Automation with Cron:
# You can automate the execution of this script and manage old backups with a Cron job:
#
# 1. To back up all Docker containers every Sunday at midnight:
# 0 0 * * 0 /root/backup_docker_container.sh
#
# 2. To delete backup files older than 14 days every day at 1 AM:
# 0 1 * * * find /root/backup_docker_container/* -mtime +14 -exec rm {} \;
#
# Restoring a backup:
# To restore a Docker container from a backup, follow these steps:
#
# 1. Uncompress the .tar.gz file:
# gunzip /path/to/backup_docker_container/container_name_date.tar.gz
#
# 2. Create a Docker image from the .tar file:
# cat /path/to/backup_docker_container/container_name_date.tar | docker import - new_image_name
#
# This will create a new Docker image from the container's backup.
#
# 3. Start a new container from the restored image:
# docker run -d --name new_container_name new_image_name
#
# This will launch a new container based on the restored image.
#
# Note: This process does not restore Docker volumes. If your container used volumes,
# you will need to restore or recreate them separately.
#
# This script only backs up running containers at the time of execution.
# It exports only the container's file system (container content) and does not back up
# Docker volumes that may be mounted from the host.
# Backup directory
backup_dir="backup_docker_container"
# Create backup directory if it doesn't exist
mkdir -p "$backup_dir"
# Get current date and time
current_datetime=$(date +"%Y-%m-%d_%H-%M-%S")
# Get list of running Docker containers
containers=$(docker ps --format '{{.Names}}')
# Iterate through each container and create a compressed backup with container name and current date and time
for container in $containers
do
echo "Backing up container $container..."
docker export "$container" | gzip > "$backup_dir/${container}_${current_datetime}.tar.gz"
echo "Backup of container $container completed."
done
# Indicate that the backup process is completed
echo "Backup process completed."

View File

@@ -1,10 +1,11 @@
#!/bin/bash #!/bin/bash
# Description # Description
# Ce script effectue une sauvegarde de tous les dossiers dans /srv # This script performs a backup of all folders in /srv
# Pour les dossiers correspondant à des conteneurs Docker actifs, # For folders corresponding to active Docker containers,
# les conteneurs sont arrêtés pendant la sauvegarde puis redémarrés # containers are stopped during backup then restarted
# Les sauvegardes sont conservées pendant 7 jours # Containers listed in EXCLUDED_CONTAINERS are ignored
# Backups are kept for 7 days
# Configuration # Configuration
SRV_DIR="/home/docker/srv" SRV_DIR="/home/docker/srv"
@@ -12,72 +13,89 @@ BACKUP_DEST="/home/docker/backup"
RETENTION_DAYS=7 RETENTION_DAYS=7
LOG_FILE="/home/docker/docker-backup.log" LOG_FILE="/home/docker/docker-backup.log"
# Fonction de logging # List of containers to exclude from backup (space separated)
# Example: EXCLUDED_CONTAINERS="traefik mysql-prod redis-cache"
EXCLUDED_CONTAINERS=""
# Logging function
log_message() { log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE" echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
} }
# Vérification de l'existence du répertoire de destination # Check if destination directory exists
if [ ! -d "$BACKUP_DEST" ]; then if [ ! -d "$BACKUP_DEST" ]; then
log_message "Création du répertoire de destination $BACKUP_DEST" log_message "Creating destination directory $BACKUP_DEST"
mkdir -p "$BACKUP_DEST" mkdir -p "$BACKUP_DEST"
fi fi
# Vérification de l'espace disque disponible (au moins 1GB) # Check available disk space (at least 1GB)
available_space=$(df "$BACKUP_DEST" | awk 'NR==2 {print $4}') available_space=$(df "$BACKUP_DEST" | awk 'NR==2 {print $4}')
if [ "$available_space" -lt 1048576 ]; then if [ "$available_space" -lt 1048576 ]; then
log_message "AVERTISSEMENT: Espace disque faible (moins de 1GB disponible)" log_message "WARNING: Low disk space (less than 1GB available)"
fi fi
log_message "Début de la sauvegarde Docker" log_message "Starting Docker backup"
# Compteurs pour les statistiques # Counters for statistics
success_count=0 success_count=0
error_count=0 error_count=0
docker_stopped=() docker_stopped=()
docker_errors=() docker_errors=()
# Fonction pour sauvegarder un répertoire # Function to backup a directory
backup_directory() { backup_directory() {
local source_dir="$1" local source_dir="$1"
local folder_name="$2" local folder_name="$2"
if [ ! -e "$source_dir" ]; then if [ ! -e "$source_dir" ]; then
log_message "AVERTISSEMENT: $source_dir n'existe pas, ignoré" log_message "WARNING: $source_dir does not exist, skipped"
((error_count++)) ((error_count++))
return 1 return 1
fi fi
# Créer le dossier de destination pour ce service # Create destination folder for this service
local dest_folder="$BACKUP_DEST/$folder_name" local dest_folder="$BACKUP_DEST/$folder_name"
mkdir -p "$dest_folder" mkdir -p "$dest_folder"
local filename="${folder_name}_$(date +%Y-%m-%d_%H-%M-%S).tar.gz" local filename="${folder_name}_$(date +%Y-%m-%d_%H-%M-%S).tar.gz"
local filepath="$dest_folder/$filename" local filepath="$dest_folder/$filename"
log_message "Sauvegarde de $source_dir vers $folder_name/$filename" log_message "Backing up $source_dir to $folder_name/$filename"
# Création de l'archive # Create the archive
if tar -czf "$filepath" -C "$(dirname "$source_dir")" "$(basename "$source_dir")" 2>/dev/null; then if tar -czf "$filepath" -C "$(dirname "$source_dir")" "$(basename "$source_dir")" 2>/dev/null; then
# Création du fichier de checksum SHA-256 # Create SHA-256 checksum file
sha256sum "$filepath" > "$filepath.sha256" sha256sum "$filepath" > "$filepath.sha256"
file_size=$(du -h "$filepath" | cut -f1) file_size=$(du -h "$filepath" | cut -f1)
log_message "SUCCESS: $filename créé ($file_size) - Checksum généré" log_message "SUCCESS: $filename created ($file_size) - Checksum generated"
((success_count++)) ((success_count++))
return 0 return 0
else else
log_message "ERREUR: Impossible de créer l'archive pour $source_dir" log_message "ERROR: Unable to create archive for $source_dir"
((error_count++)) ((error_count++))
return 1 return 1
fi fi
} }
# Fonction pour vérifier si Docker est installé # Function to check if Docker is installed
is_docker_available() { is_docker_available() {
command -v docker >/dev/null 2>&1 command -v docker >/dev/null 2>&1
} }
# Fonction pour vérifier si un conteneur Docker existe et est en cours d'exécution # Function to check if a container is excluded
is_container_excluded() {
local container_name="$1"
if [ -n "$EXCLUDED_CONTAINERS" ]; then
for excluded in $EXCLUDED_CONTAINERS; do
if [ "$container_name" = "$excluded" ]; then
return 0
fi
done
fi
return 1
}
# Function to check if a Docker container exists and is running
is_container_running() { is_container_running() {
local container_name="$1" local container_name="$1"
if is_docker_available; then if is_docker_available; then
@@ -87,86 +105,92 @@ is_container_running() {
fi fi
} }
# Fonction pour arrêter un conteneur Docker # Function to stop a Docker container
stop_container() { stop_container() {
local container_name="$1" local container_name="$1"
log_message "Arrêt du conteneur Docker: $container_name" log_message "Stopping Docker container: $container_name"
if docker stop "$container_name" >/dev/null 2>&1; then if docker stop "$container_name" >/dev/null 2>&1; then
log_message "Conteneur $container_name arrêté avec succès" log_message "Container $container_name stopped successfully"
docker_stopped+=("$container_name") docker_stopped+=("$container_name")
return 0 return 0
else else
log_message "ERREUR: Impossible d'arrêter le conteneur $container_name" log_message "ERROR: Unable to stop container $container_name"
docker_errors+=("$container_name") docker_errors+=("$container_name")
return 1 return 1
fi fi
} }
# Fonction pour redémarrer un conteneur Docker # Function to start a Docker container
start_container() { start_container() {
local container_name="$1" local container_name="$1"
log_message "Redémarrage du conteneur Docker: $container_name" log_message "Starting Docker container: $container_name"
if docker start "$container_name" >/dev/null 2>&1; then if docker start "$container_name" >/dev/null 2>&1; then
log_message "Conteneur $container_name redémarré avec succès" log_message "Container $container_name started successfully"
return 0 return 0
else else
log_message "ERREUR: Impossible de redémarrer le conteneur $container_name" log_message "ERROR: Unable to start container $container_name"
return 1 return 1
fi fi
} }
# Vérifier si Docker est disponible # Check if Docker is available
if ! is_docker_available; then if ! is_docker_available; then
log_message "AVERTISSEMENT: Docker n'est pas installé ou accessible" log_message "WARNING: Docker is not installed or accessible"
fi fi
# Sauvegarde des répertoires dans /srv # Backup directories in /srv
log_message "=== SAUVEGARDE DES SERVICES DOCKER ===" log_message "=== DOCKER SERVICES BACKUP ==="
if [ -d "$SRV_DIR" ]; then if [ -d "$SRV_DIR" ]; then
# Parcourir tous les dossiers dans /srv # Loop through all folders in /srv
for srv_folder in "$SRV_DIR"/*; do for srv_folder in "$SRV_DIR"/*; do
if [ -d "$srv_folder" ]; then if [ -d "$srv_folder" ]; then
folder_name=$(basename "$srv_folder") folder_name=$(basename "$srv_folder")
# Vérifier si un conteneur Docker avec ce nom existe et est en cours d'exécution # Check if the container is in the exclusion list
if is_container_running "$folder_name"; then if is_container_excluded "$folder_name"; then
log_message "Conteneur Docker actif détecté: $folder_name" log_message "EXCLUSION: Container $folder_name skipped (in exclusion list)"
continue
fi
# Arrêter le conteneur # Check if a Docker container with this name exists and is running
if is_container_running "$folder_name"; then
log_message "Active Docker container detected: $folder_name"
# Stop the container
if stop_container "$folder_name"; then if stop_container "$folder_name"; then
# Attendre un peu pour s'assurer que le conteneur est complètement arrêté # Wait a bit to ensure the container is completely stopped
sleep 5 sleep 5
# Effectuer la sauvegarde # Perform the backup
backup_directory "$srv_folder" "$folder_name" backup_directory "$srv_folder" "$folder_name"
# Redémarrer le conteneur # Restart the container
start_container "$folder_name" start_container "$folder_name"
else else
log_message "AVERTISSEMENT: Sauvegarde de $folder_name sans arrêter le conteneur (risque d'incohérence)" log_message "WARNING: Backing up $folder_name without stopping container (risk of inconsistency)"
backup_directory "$srv_folder" "$folder_name" backup_directory "$srv_folder" "$folder_name"
fi fi
else else
# Pas de conteneur Docker correspondant, sauvegarde normale # No corresponding Docker container, normal backup
log_message "Service sans conteneur actif: $folder_name" log_message "Service without active container: $folder_name"
backup_directory "$srv_folder" "$folder_name" backup_directory "$srv_folder" "$folder_name"
fi fi
fi fi
done done
else else
log_message "ERREUR: Le répertoire $SRV_DIR n'existe pas" log_message "ERROR: Directory $SRV_DIR does not exist"
exit 1 exit 1
fi fi
# Vérification et génération des checksums pour toutes les archives # Verification and generation of checksums for all archives
log_message "=== VÉRIFICATION ET GÉNÉRATION DES CHECKSUMS ===" log_message "=== CHECKSUM VERIFICATION AND GENERATION ==="
archives_without_checksum=0 archives_without_checksum=0
archives_with_checksum=0 archives_with_checksum=0
find "$BACKUP_DEST" -name "*.tar.gz" -type f | while read -r archive_file; do find "$BACKUP_DEST" -name "*.tar.gz" -type f | while read -r archive_file; do
checksum_file="${archive_file}.sha256" checksum_file="${archive_file}.sha256"
if [ ! -f "$checksum_file" ]; then if [ ! -f "$checksum_file" ]; then
log_message "Génération du checksum manquant pour $(basename "$archive_file")" log_message "Generating missing checksum for $(basename "$archive_file")"
sha256sum "$archive_file" > "$checksum_file" sha256sum "$archive_file" > "$checksum_file"
((archives_without_checksum++)) ((archives_without_checksum++))
else else
@@ -174,70 +198,70 @@ find "$BACKUP_DEST" -name "*.tar.gz" -type f | while read -r archive_file; do
fi fi
done done
# Compte final des archives # Final archive count
total_archives=$(find "$BACKUP_DEST" -name "*.tar.gz" -type f | wc -l) total_archives=$(find "$BACKUP_DEST" -name "*.tar.gz" -type f | wc -l)
missing_checksums=$(find "$BACKUP_DEST" -name "*.tar.gz" -type f | while read -r archive; do [ ! -f "${archive}.sha256" ] && echo "$archive"; done | wc -l) missing_checksums=$(find "$BACKUP_DEST" -name "*.tar.gz" -type f | while read -r archive; do [ ! -f "${archive}.sha256" ] && echo "$archive"; done | wc -l)
log_message "Archives trouvées: $total_archives" log_message "Archives found: $total_archives"
if [ "$missing_checksums" -eq 0 ]; then if [ "$missing_checksums" -eq 0 ]; then
log_message "SUCCESS: Toutes les archives ont un fichier checksum" log_message "SUCCESS: All archives have a checksum file"
else else
log_message "AVERTISSEMENT: $missing_checksums archives sans checksum" log_message "WARNING: $missing_checksums archives without checksum"
fi fi
# Suppression des sauvegardes obsolètes # Cleanup of old backups
log_message "=== NETTOYAGE DES ANCIENNES SAUVEGARDES ===" log_message "=== OLD BACKUPS CLEANUP ==="
for service_dir in "$BACKUP_DEST"/*/; do for service_dir in "$BACKUP_DEST"/*/; do
if [ -d "$service_dir" ]; then if [ -d "$service_dir" ]; then
service_name=$(basename "$service_dir") service_name=$(basename "$service_dir")
log_message "Suppression des sauvegardes de plus de $RETENTION_DAYS jours pour $service_name" log_message "Removing backups older than $RETENTION_DAYS days for $service_name"
# Chercher les fichiers obsolètes (archives et checksums séparément) # Find obsolete files (archives and checksums separately)
deleted_files_tar=$(find "$service_dir" -type f -name "*.tar.gz" -mtime +$RETENTION_DAYS -print 2>/dev/null) deleted_files_tar=$(find "$service_dir" -type f -name "*.tar.gz" -mtime +$RETENTION_DAYS -print 2>/dev/null)
deleted_files_sha=$(find "$service_dir" -type f -name "*.sha256" -mtime +$RETENTION_DAYS -print 2>/dev/null) deleted_files_sha=$(find "$service_dir" -type f -name "*.sha256" -mtime +$RETENTION_DAYS -print 2>/dev/null)
if [ -n "$deleted_files_tar" ] || [ -n "$deleted_files_sha" ]; then if [ -n "$deleted_files_tar" ] || [ -n "$deleted_files_sha" ]; then
# Supprimer et logger les archives # Remove and log archives
if [ -n "$deleted_files_tar" ]; then if [ -n "$deleted_files_tar" ]; then
echo "$deleted_files_tar" | while read -r file; do echo "$deleted_files_tar" | while read -r file; do
log_message "Suppression: $service_name/$(basename "$file")" log_message "Removing: $service_name/$(basename "$file")"
done done
find "$service_dir" -type f -name "*.tar.gz" -mtime +$RETENTION_DAYS -delete 2>/dev/null find "$service_dir" -type f -name "*.tar.gz" -mtime +$RETENTION_DAYS -delete 2>/dev/null
fi fi
# Supprimer et logger les checksums # Remove and log checksums
if [ -n "$deleted_files_sha" ]; then if [ -n "$deleted_files_sha" ]; then
echo "$deleted_files_sha" | while read -r file; do echo "$deleted_files_sha" | while read -r file; do
log_message "Suppression: $service_name/$(basename "$file")" log_message "Removing: $service_name/$(basename "$file")"
done done
find "$service_dir" -type f -name "*.sha256" -mtime +$RETENTION_DAYS -delete 2>/dev/null find "$service_dir" -type f -name "*.sha256" -mtime +$RETENTION_DAYS -delete 2>/dev/null
fi fi
else else
log_message "Aucun fichier obsolète à supprimer pour $service_name" log_message "No obsolete files to remove for $service_name"
fi fi
fi fi
done done
# Redémarrage des conteneurs qui n'ont pas pu être redémarrés # Restart containers that failed to restart
if [ ${#docker_errors[@]} -gt 0 ]; then if [ ${#docker_errors[@]} -gt 0 ]; then
log_message "=== TENTATIVE DE REDÉMARRAGE DES CONTENEURS EN ERREUR ===" log_message "=== RETRY STARTING CONTAINERS IN ERROR ==="
for container in "${docker_errors[@]}"; do for container in "${docker_errors[@]}"; do
start_container "$container" start_container "$container"
done done
fi fi
# Statistiques finales # Final statistics
log_message "=== RÉSUMÉ DE LA SAUVEGARDE ===" log_message "=== BACKUP SUMMARY ==="
log_message "Sauvegardes réussies: $success_count" log_message "Successful backups: $success_count"
log_message "Erreurs: $error_count" log_message "Errors: $error_count"
if [ ${#docker_stopped[@]} -gt 0 ]; then if [ ${#docker_stopped[@]} -gt 0 ]; then
log_message "Conteneurs Docker gérés: ${docker_stopped[*]}" log_message "Docker containers managed: ${docker_stopped[*]}"
fi fi
if [ ${#docker_errors[@]} -gt 0 ]; then if [ ${#docker_errors[@]} -gt 0 ]; then
log_message "Conteneurs Docker en erreur: ${docker_errors[*]}" log_message "Docker containers in error: ${docker_errors[*]}"
fi fi
log_message "Sauvegarde terminée" log_message "Backup completed"
# Code de sortie basé sur les erreurs # Exit code based on errors
if [ $error_count -gt 0 ] || [ ${#docker_errors[@]} -gt 0 ]; then if [ $error_count -gt 0 ] || [ ${#docker_errors[@]} -gt 0 ]; then
exit 1 exit 1
else else