feat(backup): kopia + borg system-config adapters (engine parity)
Mirror the restic system-config adapters for the other two engines, each in that engine's own convention, so system backup/restore/status/retention work on any location regardless of engine: - kopia: BackupSystemToLocation (--tags system:config), SystemSnapshotsJson (filter tag system:config), RestoreSystemLatest, ForgetSystem (per-source policy on $configs_dir + maintenance). - borg: BackupSystemToLocation (archive system-<host>-<ts>, comment system=config; no app is named "system" so the namespace can't collide), SystemSnapshotsJson (--glob-archives system-<host>-*), RestoreSystemLatest, ForgetSystem (prune the system-<host>-* glob). No dispatcher change needed — engineBackupSystem/SystemSnapshotsJson/ RestoreSystemLatest/ForgetSystem already resolve <engine><fn> per location. All three engines now define the full set; syntax clean. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Signed-off-by: librelad <librelad@digitalangels.vip>
This commit is contained in:
parent
49aa5f01f3
commit
34bd6d7936
@ -50,3 +50,44 @@ borgBackupAppToLocation()
|
|||||||
borgEnvUnset
|
borgEnvUnset
|
||||||
return $rc
|
return $rc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
borgBackupSystemToLocation()
|
||||||
|
{
|
||||||
|
local idx="$1"
|
||||||
|
local source_path="${configs_dir%/}"
|
||||||
|
|
||||||
|
if [[ ! -d "$source_path" ]]; then
|
||||||
|
isError "System config path missing: $source_path"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
borgEnvExport "$idx" || return 1
|
||||||
|
|
||||||
|
local host_tag="${CFG_INSTALL_NAME:-libreportal}"
|
||||||
|
# No app is named "system", so the "system-<host>-*" archive namespace can't
|
||||||
|
# collide with an app's archives.
|
||||||
|
local archive
|
||||||
|
archive=$(borgArchiveName "system" "$host_tag")
|
||||||
|
local comment="system=config host=$host_tag engine=libreportal"
|
||||||
|
|
||||||
|
local loc_name
|
||||||
|
loc_name=$(resticLocationName "$idx")
|
||||||
|
isNotice "Snapshotting system config → $loc_name (archive: $archive)" >&2
|
||||||
|
|
||||||
|
runBackupOp borg create \
|
||||||
|
--comment "$comment" \
|
||||||
|
--compression auto,zstd \
|
||||||
|
"::$archive" \
|
||||||
|
"$source_path"
|
||||||
|
local rc=$?
|
||||||
|
|
||||||
|
if [[ $rc -eq 0 ]]; then
|
||||||
|
isSuccessful "System config backed up to $loc_name: $archive" >&2
|
||||||
|
echo "$archive"
|
||||||
|
else
|
||||||
|
isError "System config backup to $loc_name failed" >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
borgEnvUnset
|
||||||
|
return $rc
|
||||||
|
}
|
||||||
|
|||||||
@ -38,3 +38,41 @@ borgForgetApp()
|
|||||||
borgEnvUnset
|
borgEnvUnset
|
||||||
return $rc
|
return $rc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
borgForgetSystem()
|
||||||
|
{
|
||||||
|
local idx="$1"
|
||||||
|
|
||||||
|
if resticLocationAppendOnly "$idx"; then
|
||||||
|
isNotice "$(resticLocationName "$idx") is append-only — skipping forget for system config"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local keep_last keep_daily keep_weekly keep_monthly keep_yearly
|
||||||
|
keep_last=$(resticRetentionFor "$idx" KEEP_LAST)
|
||||||
|
keep_daily=$(resticRetentionFor "$idx" KEEP_DAILY)
|
||||||
|
keep_weekly=$(resticRetentionFor "$idx" KEEP_WEEKLY)
|
||||||
|
keep_monthly=$(resticRetentionFor "$idx" KEEP_MONTHLY)
|
||||||
|
keep_yearly=$(resticRetentionFor "$idx" KEEP_YEARLY)
|
||||||
|
|
||||||
|
borgEnvExport "$idx" || return 1
|
||||||
|
|
||||||
|
local host_tag="${CFG_INSTALL_NAME:-libreportal}"
|
||||||
|
local args=(prune --glob-archives "system-${host_tag}-*")
|
||||||
|
[[ -n "$keep_last" ]] && args+=(--keep-last "$keep_last")
|
||||||
|
[[ -n "$keep_daily" ]] && args+=(--keep-daily "$keep_daily")
|
||||||
|
[[ -n "$keep_weekly" ]] && args+=(--keep-weekly "$keep_weekly")
|
||||||
|
[[ -n "$keep_monthly" ]] && args+=(--keep-monthly "$keep_monthly")
|
||||||
|
[[ -n "$keep_yearly" ]] && args+=(--keep-yearly "$keep_yearly")
|
||||||
|
|
||||||
|
isNotice "Applying retention for system config on $(resticLocationName "$idx")"
|
||||||
|
runBackupOp borg "${args[@]}"
|
||||||
|
local rc=$?
|
||||||
|
|
||||||
|
if [[ "$CFG_BACKUP_PRUNE_AFTER_FORGET" == "true" && $rc -eq 0 ]]; then
|
||||||
|
runBackupOp borg compact
|
||||||
|
fi
|
||||||
|
|
||||||
|
borgEnvUnset
|
||||||
|
return $rc
|
||||||
|
}
|
||||||
|
|||||||
@ -29,6 +29,26 @@ borgRestoreSnapshot()
|
|||||||
return $rc
|
return $rc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
borgRestoreSystemLatest()
|
||||||
|
{
|
||||||
|
local idx="$1"
|
||||||
|
local target_dir="$2"
|
||||||
|
local host="${3:-$CFG_INSTALL_NAME}"
|
||||||
|
|
||||||
|
borgEnvExport "$idx" || return 1
|
||||||
|
local snapshot_id
|
||||||
|
snapshot_id=$(runBackupOp borg list --json --glob-archives "system-${host}-*" --last 1 2>/dev/null \
|
||||||
|
| grep -o '"name":"[^"]*"' | head -1 | cut -d'"' -f4)
|
||||||
|
borgEnvUnset
|
||||||
|
|
||||||
|
if [[ -z "$snapshot_id" ]]; then
|
||||||
|
isError "No system-config archive found in $(resticLocationName "$idx") for host=$host"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
# Whole-archive extract into staging (no include subpath).
|
||||||
|
borgRestoreSnapshot "$idx" "$snapshot_id" "$target_dir"
|
||||||
|
}
|
||||||
|
|
||||||
borgDumpFile()
|
borgDumpFile()
|
||||||
{
|
{
|
||||||
local idx="$1"
|
local idx="$1"
|
||||||
|
|||||||
@ -55,6 +55,50 @@ print(json.dumps(out))
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
borgSystemSnapshotsJson()
|
||||||
|
{
|
||||||
|
local idx="$1"
|
||||||
|
local host_filter="$2"
|
||||||
|
|
||||||
|
borgEnvExport "$idx" || return 1
|
||||||
|
|
||||||
|
local glob="system-${host_filter:-*}-*"
|
||||||
|
local raw
|
||||||
|
raw=$(runBackupOp borg list --json --glob-archives "$glob" 2>/dev/null)
|
||||||
|
local rc=$?
|
||||||
|
borgEnvUnset
|
||||||
|
[[ $rc -ne 0 || -z "$raw" ]] && { echo "[]"; return $rc; }
|
||||||
|
|
||||||
|
if command -v jq >/dev/null 2>&1; then
|
||||||
|
echo "$raw" | jq -c '[.archives[] | {
|
||||||
|
id: .id,
|
||||||
|
short_id: .name,
|
||||||
|
time: .time,
|
||||||
|
hostname: .hostname,
|
||||||
|
tags: (.comment | split(" ") | map(select(test("^[a-z_]+=")))),
|
||||||
|
paths: []
|
||||||
|
}]'
|
||||||
|
else
|
||||||
|
echo "$raw" | python3 -c '
|
||||||
|
import json, sys
|
||||||
|
raw = json.load(sys.stdin)
|
||||||
|
out = []
|
||||||
|
for a in raw.get("archives", []):
|
||||||
|
comment = a.get("comment", "")
|
||||||
|
tags = [t for t in comment.split() if "=" in t]
|
||||||
|
out.append({
|
||||||
|
"id": a.get("id"),
|
||||||
|
"short_id": a.get("name"),
|
||||||
|
"time": a.get("time"),
|
||||||
|
"hostname": a.get("hostname"),
|
||||||
|
"tags": tags,
|
||||||
|
"paths": []
|
||||||
|
})
|
||||||
|
print(json.dumps(out))
|
||||||
|
' 2>/dev/null || echo "[]"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
borgSnapshotLatestId()
|
borgSnapshotLatestId()
|
||||||
{
|
{
|
||||||
local idx="$1"
|
local idx="$1"
|
||||||
|
|||||||
@ -60,3 +60,41 @@ kopiaBackupAppToLocation()
|
|||||||
kopiaEnvUnset
|
kopiaEnvUnset
|
||||||
return $rc
|
return $rc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kopiaBackupSystemToLocation()
|
||||||
|
{
|
||||||
|
local idx="$1"
|
||||||
|
local source_path="${configs_dir%/}"
|
||||||
|
|
||||||
|
if [[ ! -d "$source_path" ]]; then
|
||||||
|
isError "System config path missing: $source_path"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
kopiaEnvExport "$idx" || return 1
|
||||||
|
|
||||||
|
local host_tag="${CFG_INSTALL_NAME:-libreportal}"
|
||||||
|
local tags=("--tags" "system:config" "--tags" "host:$host_tag" "--tags" "engine:libreportal")
|
||||||
|
|
||||||
|
local loc_name
|
||||||
|
loc_name=$(resticLocationName "$idx")
|
||||||
|
isNotice "Snapshotting system config → $loc_name (kopia)" >&2
|
||||||
|
|
||||||
|
local output
|
||||||
|
output=$(runBackupOp kopia snapshot create "$source_path" "${tags[@]}" --json 2>&1)
|
||||||
|
local rc=$?
|
||||||
|
|
||||||
|
local snapshot_id
|
||||||
|
snapshot_id=$(echo "$output" | grep -oE '"id":\s*"[^"]+"' | head -1 | cut -d'"' -f4)
|
||||||
|
|
||||||
|
if [[ $rc -eq 0 ]]; then
|
||||||
|
isSuccessful "System config backed up to $loc_name: ${snapshot_id:0:12}" >&2
|
||||||
|
echo "$snapshot_id"
|
||||||
|
else
|
||||||
|
isError "Kopia system config backup to $loc_name failed" >&2
|
||||||
|
echo "$output" | tail -10 >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
kopiaEnvUnset
|
||||||
|
return $rc
|
||||||
|
}
|
||||||
|
|||||||
@ -41,3 +41,39 @@ kopiaForgetApp()
|
|||||||
kopiaEnvUnset
|
kopiaEnvUnset
|
||||||
return $rc
|
return $rc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kopiaForgetSystem()
|
||||||
|
{
|
||||||
|
local idx="$1"
|
||||||
|
|
||||||
|
if resticLocationAppendOnly "$idx"; then
|
||||||
|
isNotice "$(resticLocationName "$idx") is append-only — skipping forget for system config"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local keep_last keep_daily keep_weekly keep_monthly keep_yearly
|
||||||
|
keep_last=$(resticRetentionFor "$idx" KEEP_LAST)
|
||||||
|
keep_daily=$(resticRetentionFor "$idx" KEEP_DAILY)
|
||||||
|
keep_weekly=$(resticRetentionFor "$idx" KEEP_WEEKLY)
|
||||||
|
keep_monthly=$(resticRetentionFor "$idx" KEEP_MONTHLY)
|
||||||
|
keep_yearly=$(resticRetentionFor "$idx" KEEP_YEARLY)
|
||||||
|
|
||||||
|
kopiaEnvExport "$idx" || return 1
|
||||||
|
|
||||||
|
local src="${configs_dir%/}"
|
||||||
|
|
||||||
|
local policy_args=(policy set --global=false "$src")
|
||||||
|
[[ -n "$keep_last" ]] && policy_args+=(--keep-latest "$keep_last")
|
||||||
|
[[ -n "$keep_daily" ]] && policy_args+=(--keep-daily "$keep_daily")
|
||||||
|
[[ -n "$keep_weekly" ]] && policy_args+=(--keep-weekly "$keep_weekly")
|
||||||
|
[[ -n "$keep_monthly" ]] && policy_args+=(--keep-monthly "$keep_monthly")
|
||||||
|
[[ -n "$keep_yearly" ]] && policy_args+=(--keep-annual "$keep_yearly")
|
||||||
|
|
||||||
|
runBackupOp kopia "${policy_args[@]}" >/dev/null 2>&1
|
||||||
|
|
||||||
|
isNotice "Running Kopia maintenance for system config on $(resticLocationName "$idx")"
|
||||||
|
runBackupOp kopia maintenance run --full
|
||||||
|
local rc=$?
|
||||||
|
kopiaEnvUnset
|
||||||
|
return $rc
|
||||||
|
}
|
||||||
|
|||||||
@ -42,6 +42,61 @@ kopiaSnapshotsJson()
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kopiaSystemSnapshotsJson()
|
||||||
|
{
|
||||||
|
local idx="$1"
|
||||||
|
local host_filter="$2"
|
||||||
|
|
||||||
|
kopiaEnvExport "$idx" || return 1
|
||||||
|
|
||||||
|
local raw
|
||||||
|
raw=$(runBackupOp kopia snapshot list --all --json 2>/dev/null)
|
||||||
|
local rc=$?
|
||||||
|
kopiaEnvUnset
|
||||||
|
[[ $rc -ne 0 || -z "$raw" ]] && { echo "[]"; return $rc; }
|
||||||
|
|
||||||
|
local jq_filter='[.[] | {
|
||||||
|
id: .id,
|
||||||
|
short_id: (.id[0:8]),
|
||||||
|
time: .startTime,
|
||||||
|
hostname: .source.host,
|
||||||
|
tags: ((.tags // []) | map(sub(":"; "="))),
|
||||||
|
paths: [.source.path]
|
||||||
|
}]'
|
||||||
|
jq_filter='[.[] | select(any(.tags[]?; . == "system:config"))] | '"$jq_filter"
|
||||||
|
if [[ -n "$host_filter" ]]; then
|
||||||
|
jq_filter='[.[] | select(.source.host == "'"$host_filter"'")] | '"$jq_filter"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v jq >/dev/null 2>&1; then
|
||||||
|
echo "$raw" | jq -c "$jq_filter"
|
||||||
|
else
|
||||||
|
echo "$raw"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
kopiaRestoreSystemLatest()
|
||||||
|
{
|
||||||
|
local idx="$1"
|
||||||
|
local target_dir="$2"
|
||||||
|
local host="${3:-$CFG_INSTALL_NAME}"
|
||||||
|
|
||||||
|
local json snapshot_id
|
||||||
|
json=$(kopiaSystemSnapshotsJson "$idx" "$host")
|
||||||
|
if command -v jq >/dev/null 2>&1; then
|
||||||
|
snapshot_id=$(echo "$json" | jq -r 'sort_by(.time) | last | .id // empty')
|
||||||
|
else
|
||||||
|
snapshot_id=$(echo "$json" | grep -oE '"id":\s*"[^"]+"' | tail -1 | cut -d'"' -f4)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$snapshot_id" ]]; then
|
||||||
|
isError "No system-config snapshot found in $(resticLocationName "$idx") for host=$host"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
# Whole-snapshot restore into staging (no include subpath).
|
||||||
|
kopiaRestoreSnapshot "$idx" "$snapshot_id" "$target_dir"
|
||||||
|
}
|
||||||
|
|
||||||
kopiaSnapshotLatestId()
|
kopiaSnapshotLatestId()
|
||||||
{
|
{
|
||||||
local idx="$1"
|
local idx="$1"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user