#!/bin/bash backupAppStart() { local app_name="$1" local stored_app_name="$app_name" if [[ -z "$app_name" ]]; then isError "backupAppStart called with empty app_name" return 1 fi if [[ ! -d "$containers_dir$app_name" ]]; then isError "Cannot back up '$app_name' — not installed at $containers_dir$app_name" return 1 fi if [[ -z "$(resticEnabledLocations)" ]]; then isError "No backup locations enabled — configure at least one on the Locations page before running backups." return 1 fi engineEnsureAllLocationsReady isHeader "Backing up $stored_app_name" ((menu_number++)) echo "" echo "---- $menu_number. Running pre-backup hook (if present)" echo "" backupAppRunHook "$stored_app_name" pre local strategy strategy=$(backupResolveStrategy "$stored_app_name") ((menu_number++)) echo "" echo "---- $menu_number. Quiescing container(s) for $stored_app_name (strategy: $strategy)" echo "" if [[ "$strategy" == "pause-snapshot-unpause" ]]; then dockerComposePause "$stored_app_name" 2>/dev/null || dockerComposeDown "$stored_app_name" elif [[ "$strategy" == "live" ]]; then isNotice "Live strategy — containers stay running; databases dumped consistently" backupDbDump "$stored_app_name" else dockerComposeDown "$stored_app_name" fi ((menu_number++)) echo "" echo "---- $menu_number. Writing backup manifest" echo "" local manifest_sha manifest_sha=$(manifestWrite "$stored_app_name") checkSuccess "Manifest written (sha: ${manifest_sha:0:8})" ((menu_number++)) echo "" echo "---- $menu_number. Snapshotting to all enabled locations" echo "" # On the live path the raw DB data dirs are torn and superseded by the # dumps written above — exclude them so the snapshot carries only the # consistent copy. Other strategies quiesced the DB, so keep everything. backup_exclude_paths="" if [[ "$strategy" == "live" ]]; then backup_exclude_paths=$(backupDbExcludePaths "$stored_app_name") fi local primary_snapshot_id="" local primary_idx="" local first_loc=true local idx while IFS= read -r idx; do [[ -z "$idx" ]] && continue local snap_id snap_id=$(engineBackupApp "$idx" "$stored_app_name" "$manifest_sha") if [[ "$first_loc" == true && -n "$snap_id" ]]; then primary_snapshot_id="$snap_id" primary_idx="$idx" first_loc=false fi done < <(resticEnabledLocations) ((menu_number++)) echo "" echo "---- $menu_number. Restarting container(s) for $stored_app_name" echo "" if [[ "$strategy" == "pause-snapshot-unpause" ]]; then dockerComposeUnpause "$stored_app_name" 2>/dev/null || dockerComposeUp "$stored_app_name" elif [[ "$strategy" != "live" ]]; then dockerComposeUp "$stored_app_name" fi ((menu_number++)) echo "" echo "---- $menu_number. Running post-backup hook (if present)" echo "" backupAppRunHook "$stored_app_name" post if [[ "$CFG_BACKUP_VERIFY_AFTER" == "true" && -n "$primary_snapshot_id" ]]; then ((menu_number++)) echo "" echo "---- $menu_number. Verifying snapshot integrity" echo "" backupVerifySnapshot "$primary_idx" "$primary_snapshot_id" "$stored_app_name" fi ((menu_number++)) echo "" echo "---- $menu_number. Applying retention policy" echo "" engineForgetAppAllLocations "$stored_app_name" ((menu_number++)) echo "" echo "---- $menu_number. Logging backup into database" echo "" databaseBackupInsert "$stored_app_name" if [[ "$CFG_REQUIREMENT_WEBUI" == "true" ]]; then ((menu_number++)) echo "" echo "---- $menu_number. Updating WebUI backup data" echo "" webuiGenerateBackupLocations webuiGenerateBackupDashboard webuiGenerateBackupSnapshots all webuiGenerateBackupAppStatus "$stored_app_name" fi echo "" echo "A backup of $stored_app_name has been taken on $current_date at $current_time" >> "$logs_dir$backup_log_file" echo "" menu_number=0 } backupSchedule() { local app_name="$1" backupAppStart "$app_name" }