diff --git a/configs/webui/webui_updater b/configs/webui/webui_updater index b3770eb..89dbbb5 100644 --- a/configs/webui/webui_updater +++ b/configs/webui/webui_updater @@ -6,4 +6,5 @@ CFG_UPDATER_SCAN_INTERVAL=30 # App Scan Interval - CFG_UPDATER_REGISTRY_INTERVAL=360 # Registry Check Interval - Minutes between registry lookups for new image builds (the expensive step; the local scan still refreshes every scan). 0 = only when you press Check now. CFG_HOTFIX_AUTO=security-breakage # Hotfix Auto-Apply - Which signed hotfix severities apply automatically on the update check [security-breakage|all|off] CFG_UPDATER_AUTO=true # Automatic App Updates - Master switch for per-app automatic updates. Each app's own Update Type decides individually; turning this off makes every app manual. Every update snapshots the app first and rolls back on failure. [true:On|false:Off] +CFG_UPDATER_UPGRADE_PRUNE=true # Clean Up After Version Upgrades - After a successful stepped upgrade (e.g. Nextcloud 31→34), delete the images it stepped through. Each one can be well over a gigabyte and nothing else removes them, since every step is a real tag rather than a dangling image. The version immediately before the current one is always kept so a roll-back needs no download. [true:On|false:Off] CFG_UPDATER_WINDOW=06:00-08:00 # Automatic Update Window - When automatic updates are allowed to install, in the host's local time (HH:MM-HH:MM; crosses midnight when start > end; 'always' = any time). Checks still run all day so the Updates page stays current — found updates simply wait for the window. Pressing Update yourself always works. diff --git a/scripts/cli/commands/updater/cli_updater_upgrade.sh b/scripts/cli/commands/updater/cli_updater_upgrade.sh index a89e871..d8005cf 100644 --- a/scripts/cli/commands/updater/cli_updater_upgrade.sh +++ b/scripts/cli/commands/updater/cli_updater_upgrade.sh @@ -158,10 +158,48 @@ updaterUpgradeApp() { done isSuccessful "$app upgraded through ${done_n} version(s) — now on $from, verified." + _updaterUpgradePruneImages "$app" "$cur" "${rungs[@]}" webuiUpdaterScan >/dev/null 2>&1 || true return 0 } +# Drop the images the climb left behind. A 3-rung Nextcloud upgrade downloads +# ~1.5 GB per rung and keeps every one — 4.4 GB of superseded images after a +# single upgrade, which on a small VPS is the difference between working and +# full. `system reclaim` cannot help: it collects DANGLING images, and each rung +# is a distinct tag, so they are all still tagged and all still there. (Rolling +# apps do not have this problem — moving a floating tag orphans the old image, +# which reclaim then collects.) +# +# Only ever after a SUCCESSFUL climb, and the immediately-previous version is +# KEPT as the roll-back target so recovery does not depend on the network. +# CFG_UPDATER_UPGRADE_PRUNE=false to keep everything. +_updaterUpgradePruneImages() { + local app="$1" start="$2"; shift 2 + local -a climbed=("$@") + [[ "${CFG_UPDATER_UPGRADE_PRUNE:-true}" == "true" ]] || { isNotice "Keeping superseded images (CFG_UPDATER_UPGRADE_PRUNE=false)."; return 0; } + (( ${#climbed[@]} >= 2 )) || return 0 # one step: previous IS the rollback target + + local anchor repo + anchor="$(updaterPrimaryImage "$app" "${containers_dir%/}/$app/docker-compose.yml")" + repo="$(updaterRepoTag "$anchor")"; repo="${repo%:*}" + + # Everything we moved off, minus the last one (kept for rollback). + local -a superseded=("$start" "${climbed[@]:0:$(( ${#climbed[@]} - 1 ))}") + unset 'superseded[-1]' + (( ${#superseded[@]} > 0 )) || return 0 + + local tag removed=0 + for tag in "${superseded[@]}"; do + [[ -n "$tag" ]] || continue + if runFileOp docker image rm "${repo}:${tag}" >/dev/null 2>&1; then + removed=$((removed + 1)) + fi + done + (( removed > 0 )) && isSuccessful "Removed $removed superseded image(s); kept ${climbed[-2]} for roll-back." + return 0 +} + # Undo one failed rung: put the version back, restore the snapshot taken moments # ago, start it, and record what happened. Best effort by nature — if the # restore itself fails the user is told plainly rather than reassured.