#!/bin/bash restoreAppStart() { local app_name="$1" local snapshot_arg="$2" local location_idx="$3" local host_filter="$4" local stored_app_name="$app_name" if [[ -z "$app_name" ]]; then isError "restoreAppStart called with empty app_name" return 1 fi if [[ -z "$(resticEnabledLocations)" ]]; then isError "No backup locations enabled — cannot restore" return 1 fi isHeader "Restoring $stored_app_name" local restore_started_at restore_started_at=$(date -Iseconds) isNotice "Task started: restore $stored_app_name at $restore_started_at" ((menu_number++)) echo "" echo "---- $menu_number. Picking backup" echo "" local pick pick=$(restorePickSnapshot "$stored_app_name" "$location_idx" "$snapshot_arg" "$host_filter") if [[ -z "$pick" ]]; then isError "No backup to restore from" return 1 fi local chosen_idx="${pick%%:*}" local chosen_id="${pick##*:}" isSuccessful "Using backup ${chosen_id:0:8} from $(resticLocationName "$chosen_idx")" ((menu_number++)) echo "" echo "---- $menu_number. Setting up install folder and config for $stored_app_name" echo "" dockerConfigSetupToContainer "loud" "$stored_app_name" "install" initializeAppVariables "$stored_app_name" ((menu_number++)) echo "" echo "---- $menu_number. Shutting down container(s) for restoration" echo "" dockerComposeDown "$stored_app_name" ((menu_number++)) echo "" echo "---- $menu_number. Wiping existing app folder" echo "" if [[ -d "$containers_dir$stored_app_name" ]]; then # Root-owned helper, not runFileOp — restoring over an app that left # sub-UID data behind (postgres, www-data, …) needs to actually wipe # those dirs before laying the snapshot down. runOwnership app-data-remove "$stored_app_name" fi ((menu_number++)) echo "" echo "---- $menu_number. Running pre-restore hook (if present)" echo "" restoreAppRunHook "$stored_app_name" pre ((menu_number++)) echo "" echo "---- $menu_number. Restoring snapshot ${chosen_id:0:8}" echo "" local include_path="$containers_dir$stored_app_name" engineRestoreSnapshot "$chosen_idx" "$chosen_id" "/" "$include_path" if [[ $? -ne 0 ]]; then isError "Restore failed — leaving app in stopped state" return 1 fi runFileOp chown -R "$docker_install_user":"$docker_install_user" "$containers_dir$stored_app_name" ((menu_number++)) echo "" echo "---- $menu_number. Rehydrating databases + files (pre-start)" echo "" restoreDbRehydratePreStart "$stored_app_name" restoreFilesRehydratePreStart "$stored_app_name" ((menu_number++)) echo "" echo "---- $menu_number. Updating docker compose file(s)" echo "" dockerComposeUpdateAndStartApp "$stored_app_name" install ((menu_number++)) echo "" echo "---- $menu_number. Fixing permissions before starting" echo "" fixPermissionsBeforeStart "$stored_app_name" ((menu_number++)) echo "" echo "---- $menu_number. Starting up the $stored_app_name docker service(s)" echo "" dockerComposeUp "$stored_app_name" ((menu_number++)) echo "" echo "---- $menu_number. Running post-restore hook (if present)" echo "" restoreAppRunHook "$stored_app_name" post ((menu_number++)) echo "" echo "---- $menu_number. Loading database dumps (post-start)" echo "" restoreDbReplayPostStart "$stored_app_name" ((menu_number++)) echo "" echo "---- $menu_number. Logging restore into database" echo "" databaseRestoreInsert "$stored_app_name" databaseInstallApp "$stored_app_name" ((menu_number++)) echo "" echo "---- $menu_number. Running Headscale setup (if required)" echo "" setupHeadscale "$stored_app_name" ((menu_number++)) echo "" echo "---- $menu_number. Running app-specific updates (if required)" echo "" appUpdateSpecifics "$stored_app_name" local restore_finished_at restore_finished_at=$(date -Iseconds) isSuccessful "Task finished: restore $stored_app_name at $restore_finished_at (started $restore_started_at)" menu_number=0 }