Add reproducible build system, native Unraid plugin, and WebUI
- versions.env pins podman, conmon, crun, netavark, aardvark-dns, passt, and fuse-overlayfs to verified upstream source checksums; SlackBuild recipes, scripts/build-packages.sh, checksums.sh, release.sh, and update-versions.sh implement the reproducible pipeline; GitHub Actions workflows build in a Slackware container and publish releases without committing any binaries. - plugin/podman.plg installs/updates/removes all eight packages (the seven components plus the plugin's own unraid-podman scaffolding package) via upgradepkg, using the official Unraid array-event hook mechanism (event/disks_mounted, event/stopping) instead of editing /boot/config/go. rc.podman and the sbin/ helper scripts implement storage creation, config seeding/sync, preflight checks, autostart with per-container Safe-Mode, and package verify/update/rollback. - webui/plugins/podman implements the Dashboard, Containers, Pods, Images, Volumes, Networks, Logs, Terminal, Compose, and Settings panels against the approved mockup (webui/mockups/prototype.html), talking to podman system service exclusively via PodmanClient.php (libpod REST API over the Unix socket), with two documented exceptions: Terminal's one-shot exec model and Compose's use of the podman compose CLI, since libpod has no REST equivalent for either. - docs/ARCHITECTURE.md and docs/ROADMAP.md record the design decisions and honest current status (syntax-checked, unit- and integration-tested against fake sockets/servers; not yet run against a real Unraid/Podman/Slackware system). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Executable
+168
@@ -0,0 +1,168 @@
|
||||
#!/bin/bash
|
||||
# =============================================================================
|
||||
# plugin/sbin/podman-backup.sh
|
||||
#
|
||||
# Rollback support — see docs/ARCHITECTURE.md section 14 (Rollback). Two
|
||||
# independent kinds of backup, matching the two kinds of thing an update can
|
||||
# break:
|
||||
#
|
||||
# PACKAGES plugin/podman.plg downloads each release's .txz files
|
||||
# straight into $PODMAN_BOOT_DIR/backup/packages/<plugin-version>/
|
||||
# — all 7 component packages of one plugin release share a
|
||||
# single directory named after the PLUGIN version (not each
|
||||
# component's own version), since a rollback means "go back to
|
||||
# plugin release X" as one unit — rather than into a scratch
|
||||
# dir that gets discarded, so the previously installed
|
||||
# version's packages are automatically still on disk after an
|
||||
# update, with no separate copy step. `restore-packages
|
||||
# <plugin-version>` reinstalls every package from one of those
|
||||
# directories.
|
||||
#
|
||||
# CONFIG Before a config schema migration (see podman.cfg's
|
||||
# CONFIG_SCHEMA_VERSION), the plg's postinstall calls
|
||||
# `snapshot-config` to copy the current *.conf + podman.cfg
|
||||
# into $PODMAN_BOOT_DIR/backup/config/<timestamp>/.
|
||||
# `restore-config <timestamp>` copies them back.
|
||||
#
|
||||
# `prune` bounds how many old snapshots of each kind are kept, since flash
|
||||
# space is limited (see ARCHITECTURE.md section 14, "Rollback-Historie
|
||||
# begrenzen").
|
||||
#
|
||||
# Usage:
|
||||
# podman-backup.sh snapshot-config
|
||||
# podman-backup.sh restore-config <timestamp>
|
||||
# podman-backup.sh restore-packages <version>
|
||||
# podman-backup.sh list
|
||||
# podman-backup.sh prune [--keep N]
|
||||
# =============================================================================
|
||||
|
||||
set -eu
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
# shellcheck source=./podman-common.sh
|
||||
. "$SCRIPT_DIR/podman-common.sh"
|
||||
|
||||
DEFAULT_KEEP=3
|
||||
|
||||
cmd_snapshot_config() {
|
||||
local ts
|
||||
ts=$(date -u +%Y%m%dT%H%M%SZ)
|
||||
local dest="$PODMAN_BACKUP_DIR/config/$ts"
|
||||
mkdir -p "$dest"
|
||||
|
||||
local f
|
||||
for f in podman.cfg containers.conf storage.conf registries.conf policy.json; do
|
||||
[ -f "$PODMAN_BOOT_DIR/$f" ] && cp "$PODMAN_BOOT_DIR/$f" "$dest/"
|
||||
done
|
||||
|
||||
podman_log "backup: config snapshot saved to $dest"
|
||||
echo "$ts"
|
||||
}
|
||||
|
||||
cmd_restore_config() {
|
||||
local ts="${1:?usage: podman-backup.sh restore-config <timestamp>}"
|
||||
local src="$PODMAN_BACKUP_DIR/config/$ts"
|
||||
|
||||
if [ ! -d "$src" ]; then
|
||||
podman_log_error "backup: no config snapshot found at $src"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local f
|
||||
for f in "$src"/*; do
|
||||
[ -f "$f" ] || continue
|
||||
cp "$f" "$PODMAN_BOOT_DIR/$(basename "$f")"
|
||||
done
|
||||
|
||||
podman_log "backup: config restored from snapshot $ts — restart podman (rc.podman restart) to apply"
|
||||
}
|
||||
|
||||
cmd_restore_packages() {
|
||||
local version="${1:?usage: podman-backup.sh restore-packages <version>}"
|
||||
local src="$PODMAN_BACKUP_DIR/packages/$version"
|
||||
|
||||
if [ ! -d "$src" ]; then
|
||||
podman_log_error "backup: no package backup found for version $version at $src"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
podman_require_command upgradepkg
|
||||
|
||||
local txz
|
||||
local restored=0
|
||||
for txz in "$src"/*.txz; do
|
||||
[ -f "$txz" ] || continue
|
||||
podman_log "backup: reinstalling $(basename "$txz") from backup (version $version)"
|
||||
upgradepkg --reinstall --install-new "$txz"
|
||||
restored=$((restored + 1))
|
||||
done
|
||||
|
||||
if [ "$restored" -eq 0 ]; then
|
||||
podman_log_error "backup: no .txz files found in $src"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
podman_notify "Podman packages rolled back" \
|
||||
"Reinstalled $restored package(s) from the version $version backup. Run 'rc.podman restart' to apply." \
|
||||
"warning"
|
||||
podman_log "backup: package rollback to version $version complete ($restored package(s))"
|
||||
}
|
||||
|
||||
cmd_list() {
|
||||
echo "Config snapshots ($PODMAN_BACKUP_DIR/config/):"
|
||||
if [ -d "$PODMAN_BACKUP_DIR/config" ]; then
|
||||
find "$PODMAN_BACKUP_DIR/config" -mindepth 1 -maxdepth 1 -type d -printf ' %f\n' 2> /dev/null | sort -r
|
||||
fi
|
||||
echo
|
||||
echo "Package backups ($PODMAN_BACKUP_DIR/packages/):"
|
||||
if [ -d "$PODMAN_BACKUP_DIR/packages" ]; then
|
||||
find "$PODMAN_BACKUP_DIR/packages" -mindepth 1 -maxdepth 1 -type d -printf ' %f\n' 2> /dev/null | sort -r
|
||||
fi
|
||||
}
|
||||
|
||||
cmd_prune() {
|
||||
local keep="$DEFAULT_KEEP"
|
||||
if [ "${1:-}" = "--keep" ] && [ -n "${2:-}" ]; then
|
||||
keep="$2"
|
||||
fi
|
||||
|
||||
local kind
|
||||
for kind in config packages; do
|
||||
local dir="$PODMAN_BACKUP_DIR/$kind"
|
||||
[ -d "$dir" ] || continue
|
||||
|
||||
# Sort newest-first by directory name (timestamps and semver both sort
|
||||
# correctly lexicographically here — timestamps are zero-padded ISO8601,
|
||||
# versions are compared via `sort -V`), then remove everything beyond
|
||||
# $keep.
|
||||
local sorted
|
||||
if [ "$kind" = "config" ]; then
|
||||
sorted=$(find "$dir" -mindepth 1 -maxdepth 1 -type d -printf '%f\n' | sort -r)
|
||||
else
|
||||
sorted=$(find "$dir" -mindepth 1 -maxdepth 1 -type d -printf '%f\n' | sort -rV)
|
||||
fi
|
||||
|
||||
local i=0
|
||||
local name
|
||||
while IFS= read -r name; do
|
||||
[ -z "$name" ] && continue
|
||||
i=$((i + 1))
|
||||
if [ "$i" -gt "$keep" ]; then
|
||||
podman_log "backup: pruning old $kind backup: $name"
|
||||
rm -rf "${dir:?}/$name"
|
||||
fi
|
||||
done <<< "$sorted"
|
||||
done
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
snapshot-config) cmd_snapshot_config ;;
|
||||
restore-config) shift; cmd_restore_config "$@" ;;
|
||||
restore-packages) shift; cmd_restore_packages "$@" ;;
|
||||
list) cmd_list ;;
|
||||
prune) shift; cmd_prune "$@" ;;
|
||||
*)
|
||||
echo "usage: $0 {snapshot-config|restore-config <ts>|restore-packages <version>|list|prune [--keep N]}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user