diff --git a/scripts/docker/app/compose/up_app.sh b/scripts/docker/app/compose/up_app.sh index 6436abd..7e8384c 100755 --- a/scripts/docker/app/compose/up_app.sh +++ b/scripts/docker/app/compose/up_app.sh @@ -1,5 +1,24 @@ #!/bin/bash +# Print the compose output when `up -d` failed, so the log records WHY. +# Without this the only trace of a failed app install was "Started container for +# (exit 1, up_app.sh:130)" — the compose output was captured into a +# variable and dropped. That is the difference between "navidrome's install +# failed because the image pull died" and a mystery nobody can answer ten days +# later. Tail-capped: a Dockerfile build can emit hundreds of lines, and the +# failure is always at the end. Called BEFORE checkSuccess, which may exit. +_upReportComposeFailure() +{ + local app_name="$1" rc="$2" output="$3" + (( rc == 0 )) && return 0 + [[ -z "$output" ]] && { isNotice "docker compose gave no output for $app_name (exit $rc)."; return 0; } + isNotice "docker compose output for $app_name (exit $rc):" + local _l + while IFS= read -r _l; do + [[ -n "$_l" ]] && isNotice " $_l" + done <<< "$(printf '%s\n' "$output" | tail -20)" +} + dockerComposeUp() { local app_name="$1" @@ -122,16 +141,18 @@ dockerComposeUp() fi if [[ $CFG_DOCKER_INSTALL_TYPE == "rootless" ]]; then isNotice "Starting container for $app_name, this may take a while..." - local result; result=$(dockerCommandRunInstallUser "cd $containers_dir$app_name && COMPOSE_PROGRESS=plain docker compose $setup_compose up $_compose_quiet $_compose_build_flag -d") + local result; result=$(dockerCommandRunInstallUser "cd $containers_dir$app_name && COMPOSE_PROGRESS=plain docker compose $setup_compose up $_compose_quiet $_compose_build_flag -d" 2>&1) _rc=$? + _upReportComposeFailure "$app_name" "$_rc" "$result" # Restore $? to the compose exit code — a bare `checkSuccess` # after `_rc=$?` would read the assignment's 0 and always print # success, hiding a failed `up -d` (e.g. an image pull EOF). ( exit "$_rc" ); checkSuccess "Started container for $app_name" elif [[ $CFG_DOCKER_INSTALL_TYPE == "rooted" ]]; then isNotice "Starting container for $app_name, this may take a while..." - local result; result=$(cd "$containers_dir$app_name" && COMPOSE_PROGRESS=plain docker compose $setup_compose up $_compose_quiet $_compose_build_flag -d) + local result; result=$(cd "$containers_dir$app_name" && COMPOSE_PROGRESS=plain docker compose $setup_compose up $_compose_quiet $_compose_build_flag -d 2>&1) _rc=$? + _upReportComposeFailure "$app_name" "$_rc" "$result" ( exit "$_rc" ); checkSuccess "Started container for $app_name" fi # Used for the CLI dockertype switcher. diff --git a/scripts/source/files/arrays/function_manifest.sh b/scripts/source/files/arrays/function_manifest.sh index 4f5ce7c..ed45d52 100644 --- a/scripts/source/files/arrays/function_manifest.sh +++ b/scripts/source/files/arrays/function_manifest.sh @@ -937,6 +937,7 @@ declare -gA LP_FN_MAP=( [updaterSetAnchorRef]="cli/commands/updater/cli_updater_commands.sh" [updaterTagOf]="webui/data/generators/updater/webui_updater_scan.sh" [updateTaskFields]="task/crontab_task_processor.sh" + [_upReportComposeFailure]="docker/app/compose/up_app.sh" [userExists]="function/checks/user_exists.sh" [validateContainerHealth]="task/crontab_check_processor.sh" [validateDirectoryStructure]="task/crontab_check_processor.sh" @@ -1949,6 +1950,7 @@ declare -gA LP_FN_ROOT=( [updaterSetAnchorRef]="scripts" [updaterTagOf]="scripts" [updateTaskFields]="scripts" + [_upReportComposeFailure]="scripts" [userExists]="scripts" [validateContainerHealth]="scripts" [validateDirectoryStructure]="scripts" @@ -2994,6 +2996,7 @@ updaterRollbackApp() { unset -f updaterRollbackApp; __lpAutoload "${install_scri updaterSetAnchorRef() { unset -f updaterSetAnchorRef; __lpAutoload "${install_scripts_dir}cli/commands/updater/cli_updater_commands.sh"; updaterSetAnchorRef "$@"; } updaterTagOf() { unset -f updaterTagOf; __lpAutoload "${install_scripts_dir}webui/data/generators/updater/webui_updater_scan.sh"; updaterTagOf "$@"; } updateTaskFields() { unset -f updateTaskFields; __lpAutoload "${install_scripts_dir}task/crontab_task_processor.sh"; updateTaskFields "$@"; } +_upReportComposeFailure() { unset -f _upReportComposeFailure; __lpAutoload "${install_scripts_dir}docker/app/compose/up_app.sh"; _upReportComposeFailure "$@"; } userExists() { unset -f userExists; __lpAutoload "${install_scripts_dir}function/checks/user_exists.sh"; userExists "$@"; } validateContainerHealth() { unset -f validateContainerHealth; __lpAutoload "${install_scripts_dir}task/crontab_check_processor.sh"; validateContainerHealth "$@"; } validateDirectoryStructure() { unset -f validateDirectoryStructure; __lpAutoload "${install_scripts_dir}task/crontab_check_processor.sh"; validateDirectoryStructure "$@"; }