- 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>
173 lines
6.0 KiB
Bash
Executable File
173 lines
6.0 KiB
Bash
Executable File
#!/bin/bash
|
|
# =============================================================================
|
|
# plugin/sbin/podman-autostart.sh
|
|
#
|
|
# "Autostart einrichten" — starts containers listed in
|
|
# /boot/config/plugins/podman/autostart, in file order, via the running
|
|
# Podman API service. Run by `rc.podman start` after the service is up.
|
|
# See docs/ARCHITECTURE.md section 12 (Autostart).
|
|
#
|
|
# Design constraints from the architecture doc, both implemented below:
|
|
# - A single container failing to start must NOT abort the rest of the
|
|
# chain (one broken container shouldn't take down everything else).
|
|
# - After repeated consecutive failures, a container is automatically
|
|
# paused out of the autostart chain ("Safe-Mode pro Container") so a
|
|
# persistently crash-looping container doesn't waste boot time or
|
|
# resources forever — with a GUI notification explaining why.
|
|
#
|
|
# File formats:
|
|
# autostart one container name per line; '#' starts a comment;
|
|
# blank lines ignored. Order = start order.
|
|
# autostart-delay optional "<container-name>=<seconds>" lines — sleep
|
|
# that many seconds AFTER starting that container
|
|
# before moving to the next (for startup dependencies,
|
|
# e.g. a database before the app that needs it).
|
|
#
|
|
# Failure tracking: a small per-container counter file under
|
|
# $PODMAN_BOOT_DIR/autostart-failures/<name> holds the consecutive-failure
|
|
# count. Reset to 0 on any successful start.
|
|
# =============================================================================
|
|
|
|
set -u
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
# shellcheck source=./podman-common.sh
|
|
. "$SCRIPT_DIR/podman-common.sh"
|
|
|
|
podman_load_cfg
|
|
|
|
# After this many consecutive failed autostart attempts, a container is
|
|
# skipped and flagged rather than retried again on the next boot, until a
|
|
# human clears it (see clear_failure_flag below).
|
|
MAX_CONSECUTIVE_FAILURES=3
|
|
|
|
FAILURES_DIR="$PODMAN_BOOT_DIR/autostart-failures"
|
|
mkdir -p "$FAILURES_DIR"
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# get_delay <container-name>
|
|
#
|
|
# Looks up an optional post-start delay for a container from
|
|
# autostart-delay ("name=seconds" lines). Returns 0 if not configured.
|
|
# -----------------------------------------------------------------------------
|
|
get_delay() {
|
|
local name="$1"
|
|
if [ -f "$PODMAN_AUTOSTART_DELAY_FILE" ]; then
|
|
awk -F= -v n="$name" '$1 == n { print $2; found=1 } END { if (!found) print 0 }' \
|
|
"$PODMAN_AUTOSTART_DELAY_FILE"
|
|
else
|
|
echo 0
|
|
fi
|
|
}
|
|
|
|
failure_count() {
|
|
local name="$1"
|
|
local f="$FAILURES_DIR/$name"
|
|
[ -f "$f" ] && cat "$f" || echo 0
|
|
}
|
|
|
|
record_failure() {
|
|
local name="$1"
|
|
local count
|
|
count=$(($(failure_count "$name") + 1))
|
|
echo "$count" > "$FAILURES_DIR/$name"
|
|
echo "$count"
|
|
}
|
|
|
|
clear_failure_flag() {
|
|
local name="$1"
|
|
rm -f "$FAILURES_DIR/$name"
|
|
}
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# start_one <container-name>
|
|
#
|
|
# Starts a single container via `podman start`, which talks to the already
|
|
# running API service over $PODMAN_SOCKET rather than spawning an unrelated
|
|
# podman process tree — see docs/ARCHITECTURE.md section 11 (Container).
|
|
# -----------------------------------------------------------------------------
|
|
start_one() {
|
|
local name="$1"
|
|
|
|
local prior_failures
|
|
prior_failures=$(failure_count "$name")
|
|
if [ "$prior_failures" -ge "$MAX_CONSECUTIVE_FAILURES" ]; then
|
|
podman_log_error "autostart: skipping '$name' — $prior_failures consecutive prior failures (Safe-Mode). Remove $FAILURES_DIR/$name to re-enable."
|
|
return 1
|
|
fi
|
|
|
|
podman_log "autostart: starting '$name'"
|
|
if podman --url "unix://$PODMAN_SOCKET" start "$name" > /tmp/podman-autostart-"$name".log 2>&1; then
|
|
clear_failure_flag "$name"
|
|
podman_log "autostart: '$name' started successfully"
|
|
return 0
|
|
fi
|
|
|
|
local new_count
|
|
new_count=$(record_failure "$name")
|
|
podman_log_error "autostart: '$name' failed to start (attempt $new_count/$MAX_CONSECUTIVE_FAILURES) — see /tmp/podman-autostart-$name.log"
|
|
|
|
if [ "$new_count" -ge "$MAX_CONSECUTIVE_FAILURES" ]; then
|
|
podman_notify "Podman container disabled from autostart" \
|
|
"'$name' failed to start $new_count times in a row and has been paused from autostart. Fix the underlying issue, then remove $FAILURES_DIR/$name to re-enable." \
|
|
"warning"
|
|
fi
|
|
|
|
return 1
|
|
}
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# main
|
|
# -----------------------------------------------------------------------------
|
|
if [ ! -f "$PODMAN_AUTOSTART_FILE" ]; then
|
|
podman_log "autostart: no autostart file at $PODMAN_AUTOSTART_FILE, nothing to do"
|
|
exit 0
|
|
fi
|
|
|
|
if [ ! -S "$PODMAN_SOCKET" ]; then
|
|
podman_log_error "autostart: podman API socket ($PODMAN_SOCKET) not present — is the service running?"
|
|
exit 1
|
|
fi
|
|
|
|
started=0
|
|
skipped=0
|
|
failed=0
|
|
|
|
while IFS= read -r raw_line || [ -n "$raw_line" ]; do
|
|
# Strip comments and surrounding whitespace; skip blank lines.
|
|
line="${raw_line%%#*}"
|
|
line="$(echo "$line" | xargs || true)"
|
|
[ -z "$line" ] && continue
|
|
|
|
if start_one "$line"; then
|
|
started=$((started + 1))
|
|
else
|
|
prior=$(failure_count "$line")
|
|
if [ "$prior" -ge "$MAX_CONSECUTIVE_FAILURES" ]; then
|
|
skipped=$((skipped + 1))
|
|
else
|
|
failed=$((failed + 1))
|
|
fi
|
|
# A single container's failure does not abort the loop — see file
|
|
# header. Continue to the next entry.
|
|
continue
|
|
fi
|
|
|
|
delay=$(get_delay "$line")
|
|
if [ "$delay" -gt 0 ] 2> /dev/null; then
|
|
podman_log "autostart: waiting ${delay}s after '$line' (configured dependency delay)"
|
|
sleep "$delay"
|
|
fi
|
|
done < "$PODMAN_AUTOSTART_FILE"
|
|
|
|
podman_log "autostart: complete (started=$started failed=$failed skipped-safe-mode=$skipped)"
|
|
|
|
# Exit non-zero only if EVERY entry failed outright (as opposed to a mix,
|
|
# or entries already in Safe-Mode) — rc.podman treats that as worth
|
|
# flagging loudly, whereas a partial failure is already individually
|
|
# notified above.
|
|
if [ "$started" -eq 0 ] && [ "$failed" -gt 0 ]; then
|
|
exit 1
|
|
fi
|
|
exit 0
|