Merge claude/2

This commit is contained in:
librelad 2026-05-23 15:34:17 +01:00
commit a11a7a7a71
12 changed files with 67 additions and 8 deletions

View File

@ -17,6 +17,7 @@
CFG_AUTHELIA_APP_NAME=authelia CFG_AUTHELIA_APP_NAME=authelia
CFG_AUTHELIA_REQUIRES="domain,traefik" CFG_AUTHELIA_REQUIRES="domain,traefik"
CFG_AUTHELIA_BACKUP=true CFG_AUTHELIA_BACKUP=true
CFG_AUTHELIA_BACKUP_STRATEGY=auto
CFG_AUTHELIA_COMPOSE_FILE=default CFG_AUTHELIA_COMPOSE_FILE=default
CFG_AUTHELIA_HEALTHCHECK=true CFG_AUTHELIA_HEALTHCHECK=true
CFG_AUTHELIA_AUTHELIA=false CFG_AUTHELIA_AUTHELIA=false

View File

@ -13,6 +13,7 @@
# #
CFG_BOOKSTACK_APP_NAME=bookstack CFG_BOOKSTACK_APP_NAME=bookstack
CFG_BOOKSTACK_BACKUP=true CFG_BOOKSTACK_BACKUP=true
CFG_BOOKSTACK_BACKUP_STRATEGY=auto
CFG_BOOKSTACK_COMPOSE_FILE=default CFG_BOOKSTACK_COMPOSE_FILE=default
CFG_BOOKSTACK_HEALTHCHECK=true CFG_BOOKSTACK_HEALTHCHECK=true
CFG_BOOKSTACK_AUTHELIA=false CFG_BOOKSTACK_AUTHELIA=false

View File

@ -11,6 +11,7 @@
# #
CFG_HEADSCALE_APP_NAME=headscale CFG_HEADSCALE_APP_NAME=headscale
CFG_HEADSCALE_BACKUP=true CFG_HEADSCALE_BACKUP=true
CFG_HEADSCALE_BACKUP_STRATEGY=auto
CFG_HEADSCALE_COMPOSE_FILE=default CFG_HEADSCALE_COMPOSE_FILE=default
CFG_HEADSCALE_HEALTHCHECK=true CFG_HEADSCALE_HEALTHCHECK=true
CFG_HEADSCALE_BASIC_AUTH_PASS=RANDOMIZEDPASSWORD1 CFG_HEADSCALE_BASIC_AUTH_PASS=RANDOMIZEDPASSWORD1

View File

@ -11,6 +11,7 @@
# #
CFG_INVIDIOUS_APP_NAME=invidious CFG_INVIDIOUS_APP_NAME=invidious
CFG_INVIDIOUS_BACKUP=false CFG_INVIDIOUS_BACKUP=false
CFG_INVIDIOUS_BACKUP_STRATEGY=auto
CFG_INVIDIOUS_COMPOSE_FILE=default CFG_INVIDIOUS_COMPOSE_FILE=default
CFG_INVIDIOUS_HEALTHCHECK=false CFG_INVIDIOUS_HEALTHCHECK=false
CFG_INVIDIOUS_AUTHELIA=false CFG_INVIDIOUS_AUTHELIA=false

View File

@ -11,6 +11,7 @@
# #
CFG_LINKDING_APP_NAME=linkding CFG_LINKDING_APP_NAME=linkding
CFG_LINKDING_BACKUP=true CFG_LINKDING_BACKUP=true
CFG_LINKDING_BACKUP_STRATEGY=auto
CFG_LINKDING_COMPOSE_FILE=default CFG_LINKDING_COMPOSE_FILE=default
CFG_LINKDING_HEALTHCHECK=true CFG_LINKDING_HEALTHCHECK=true
CFG_LINKDING_AUTHELIA=false CFG_LINKDING_AUTHELIA=false

View File

@ -11,6 +11,7 @@
# #
CFG_MASTODON_APP_NAME=mastodon CFG_MASTODON_APP_NAME=mastodon
CFG_MASTODON_BACKUP=true CFG_MASTODON_BACKUP=true
CFG_MASTODON_BACKUP_STRATEGY=auto
CFG_MASTODON_COMPOSE_FILE=default CFG_MASTODON_COMPOSE_FILE=default
CFG_MASTODON_HEALTHCHECK=true CFG_MASTODON_HEALTHCHECK=true
CFG_MASTODON_AUTHELIA=false CFG_MASTODON_AUTHELIA=false

View File

@ -15,6 +15,7 @@
# #
CFG_NEXTCLOUD_APP_NAME=nextcloud CFG_NEXTCLOUD_APP_NAME=nextcloud
CFG_NEXTCLOUD_BACKUP=true CFG_NEXTCLOUD_BACKUP=true
CFG_NEXTCLOUD_BACKUP_STRATEGY=auto
CFG_NEXTCLOUD_COMPOSE_FILE=default CFG_NEXTCLOUD_COMPOSE_FILE=default
CFG_NEXTCLOUD_HEALTHCHECK=true CFG_NEXTCLOUD_HEALTHCHECK=true
CFG_NEXTCLOUD_AUTHELIA=false CFG_NEXTCLOUD_AUTHELIA=false

View File

@ -11,6 +11,7 @@
# #
CFG_OWNCLOUD_APP_NAME=owncloud CFG_OWNCLOUD_APP_NAME=owncloud
CFG_OWNCLOUD_BACKUP=true CFG_OWNCLOUD_BACKUP=true
CFG_OWNCLOUD_BACKUP_STRATEGY=auto
CFG_OWNCLOUD_COMPOSE_FILE=default CFG_OWNCLOUD_COMPOSE_FILE=default
CFG_OWNCLOUD_HEALTHCHECK=true CFG_OWNCLOUD_HEALTHCHECK=true
CFG_OWNCLOUD_AUTHELIA=false CFG_OWNCLOUD_AUTHELIA=false

View File

@ -11,6 +11,7 @@
# #
CFG_TRILIUM_APP_NAME=trilium CFG_TRILIUM_APP_NAME=trilium
CFG_TRILIUM_BACKUP=true CFG_TRILIUM_BACKUP=true
CFG_TRILIUM_BACKUP_STRATEGY=auto
CFG_TRILIUM_COMPOSE_FILE=default CFG_TRILIUM_COMPOSE_FILE=default
CFG_TRILIUM_HEALTHCHECK=true CFG_TRILIUM_HEALTHCHECK=true
CFG_TRILIUM_AUTHELIA=false CFG_TRILIUM_AUTHELIA=false

View File

@ -12,6 +12,7 @@
# #
CFG_VAULTWARDEN_APP_NAME=vaultwarden CFG_VAULTWARDEN_APP_NAME=vaultwarden
CFG_VAULTWARDEN_BACKUP=true CFG_VAULTWARDEN_BACKUP=true
CFG_VAULTWARDEN_BACKUP_STRATEGY=auto
CFG_VAULTWARDEN_COMPOSE_FILE=default CFG_VAULTWARDEN_COMPOSE_FILE=default
CFG_VAULTWARDEN_HEALTHCHECK=false CFG_VAULTWARDEN_HEALTHCHECK=false
CFG_VAULTWARDEN_AUTHELIA=false CFG_VAULTWARDEN_AUTHELIA=false

View File

@ -55,7 +55,8 @@ backupDbDescriptors()
backupDbHasDescriptors() backupDbHasDescriptors()
{ {
local app="$1" local app="$1"
[[ -n "$(backupDbDescriptors "$app")" ]] if [[ -n "$(backupDbDescriptors "$app")" ]]; then return 0; fi
return 1
} }
# True when the app carries `libreportal.backup.live: "true"` — i.e. its data is # True when the app carries `libreportal.backup.live: "true"` — i.e. its data is
@ -65,26 +66,60 @@ backupAppIsLiveSafe()
local app="$1" local app="$1"
local compose="$containers_dir$app/docker-compose.yml" local compose="$containers_dir$app/docker-compose.yml"
[[ -f "$compose" ]] || return 1 [[ -f "$compose" ]] || return 1
grep -qE '^[[:space:]]*libreportal\.backup\.live[[:space:]]*:[[:space:]]*["'\'']?true' "$compose" 2>/dev/null if grep -qE '^[[:space:]]*libreportal\.backup\.live[[:space:]]*:[[:space:]]*["'\'']?true' "$compose" 2>/dev/null; then
return 0
fi
return 1
} }
# Resolve the effective strategy for one app. Explicit settings are honoured as # An app can be backed up live without downtime when we can make it consistent:
# power-user overrides; the default "auto" goes live only where we can guarantee # it has a dumpable database, or it is explicitly blessed live-safe.
# consistency (a dumpable database, or an app blessed live-safe) and otherwise backupAppLiveCapable()
# falls back to the always-safe stop-snapshot-start. {
local app="$1"
if backupDbHasDescriptors "$app"; then return 0; fi
if backupAppIsLiveSafe "$app"; then return 0; fi
return 1
}
# Strategy options valid for one app, in .config "[a:b|c:d]" syntax. live is
# offered only where the app can actually do it, so the UI never shows a choice
# that would just fall back to stop.
backupAppStrategyOptions()
{
local app="$1"
local opts="auto:Automatic — recommended|stop-snapshot-start:Stop → snapshot → start|pause-snapshot-unpause:Pause → snapshot → unpause"
if backupAppLiveCapable "$app"; then
opts="$opts|live:Live — no downtime"
fi
echo "$opts"
return 0
}
# Resolve the effective strategy for one app. Order of precedence:
# 1. per-app override CFG_<APP>_BACKUP_STRATEGY (advanced, defaults to auto)
# 2. global default CFG_BACKUP_STRATEGY (auto)
# An explicit stop/pause/live is honoured as-is; "auto" goes live only where the
# app is live-capable and otherwise uses the always-safe stop-snapshot-start.
backupResolveStrategy() backupResolveStrategy()
{ {
local app="$1" local app="$1"
local s="${CFG_BACKUP_STRATEGY:-auto}" local override_key="CFG_${app^^}_BACKUP_STRATEGY"
local s="${!override_key}"
if [[ -z "$s" || "$s" == "auto" ]]; then
s="${CFG_BACKUP_STRATEGY:-auto}"
fi
case "$s" in case "$s" in
live|pause-snapshot-unpause|stop-snapshot-start) live|pause-snapshot-unpause|stop-snapshot-start)
echo "$s"; return 0 ;; echo "$s"; return 0 ;;
esac esac
if backupDbHasDescriptors "$app" || backupAppIsLiveSafe "$app"; then if backupAppLiveCapable "$app"; then
echo "live" echo "live"
else else
echo "stop-snapshot-start" echo "stop-snapshot-start"
fi fi
return 0
} }
# Deterministic dump filename for a descriptor — backup writes it, restore reads # Deterministic dump filename for a descriptor — backup writes it, restore reads

View File

@ -159,6 +159,20 @@ PORTEOF
"tooltip": "Enable automatic backups for this application", "tooltip": "Enable automatic backups for this application",
"default": false "default": false
}, },
"BACKUP_STRATEGY": {
"category": "advanced",
"label": "Backup Strategy",
"type": "select",
"tooltip": "How this app is quiesced before its backup snapshot. Automatic picks the safest zero-downtime method available (a live, consistent database dump for this app), and falls back to stopping the app if a live dump ever fails. Only shown for apps that can be backed up live.",
"advanced": true,
"options": [
{"value": "auto", "label": "Automatic (recommended)"},
{"value": "stop-snapshot-start", "label": "Stop → snapshot → start"},
{"value": "pause-snapshot-unpause", "label": "Pause → snapshot → unpause"},
{"value": "live", "label": "Live — no downtime"}
],
"default": "auto"
},
"MONITORING": { "MONITORING": {
"category": "features", "category": "features",
"label": "Export metrics to Grafana", "label": "Export metrics to Grafana",