- 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>
174 lines
7.3 KiB
Bash
Executable File
174 lines
7.3 KiB
Bash
Executable File
#!/bin/bash
|
|
# =============================================================================
|
|
# plugin/sbin/podman-common.sh
|
|
#
|
|
# Shared constants and helper functions sourced by every other script under
|
|
# plugin/sbin/ and by plugin/rc.d/rc.podman. Centralizing these here means:
|
|
# - every script agrees on the same paths (no risk of one script writing
|
|
# config to a path another script reads from a slightly different one),
|
|
# - logging/notification behavior is consistent everywhere,
|
|
# - each individual script stays focused on its one job instead of
|
|
# re-implementing "how do I log this" or "where is podman.cfg".
|
|
#
|
|
# This file is NOT meant to be executed directly — it only defines
|
|
# functions/variables for other scripts to source:
|
|
# . "$(dirname "${BASH_SOURCE[0]}")/podman-common.sh"
|
|
#
|
|
# See docs/ARCHITECTURE.md sections 4 (Verzeichnislayout), 7 (Persistenz),
|
|
# 15 (Logging), 16 (Fehlerbehandlung) for the design this implements.
|
|
# =============================================================================
|
|
|
|
# We deliberately do NOT `set -e` in this file: it is sourced by scripts
|
|
# that set their own error-handling mode, and a library changing its
|
|
# caller's shell options would be a surprising action at a distance.
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Path constants.
|
|
#
|
|
# PODMAN_BOOT_DIR is the persistent, source-of-truth configuration directory
|
|
# on the Unraid flash device (survives reboots — see ARCHITECTURE.md 4.1).
|
|
# Everything under /etc, /var, /usr is RAM-root and rebuilt from here (or
|
|
# from the array/cache-backed storage dir) on every boot.
|
|
# -----------------------------------------------------------------------------
|
|
PODMAN_BOOT_DIR="/boot/config/plugins/podman"
|
|
PODMAN_CFG_FILE="$PODMAN_BOOT_DIR/podman.cfg"
|
|
PODMAN_AUTOSTART_FILE="$PODMAN_BOOT_DIR/autostart"
|
|
PODMAN_AUTOSTART_DELAY_FILE="$PODMAN_BOOT_DIR/autostart-delay"
|
|
PODMAN_NETWORKS_BOOT_DIR="$PODMAN_BOOT_DIR/networks"
|
|
PODMAN_BACKUP_DIR="$PODMAN_BOOT_DIR/backup"
|
|
PODMAN_PLUGIN_LOG="$PODMAN_BOOT_DIR/plugin.log"
|
|
|
|
# Runtime (RAM-root) locations rebuilt/synced on every rc.podman start.
|
|
PODMAN_ETC_DIR="/etc/containers"
|
|
PODMAN_RUN_DIR="/var/run/podman"
|
|
PODMAN_SOCKET="$PODMAN_RUN_DIR/podman.sock"
|
|
PODMAN_STATUS_FILE="$PODMAN_RUN_DIR/rc.podman.status"
|
|
PODMAN_SERVICE_PID_FILE="$PODMAN_RUN_DIR/podman-service.pid"
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# podman_load_cfg
|
|
#
|
|
# Sources /boot/config/plugins/podman/podman.cfg (the user-editable settings
|
|
# file, see config/podman.cfg.example) and applies safe defaults for any
|
|
# setting that file doesn't define — so every other script can simply
|
|
# reference $STORAGE_PATH, $PODMAN_ENABLED, etc. after calling this, without
|
|
# each script having its own copy of the defaults.
|
|
# -----------------------------------------------------------------------------
|
|
podman_load_cfg() {
|
|
# Defaults, applied BEFORE sourcing podman.cfg so the file only needs to
|
|
# override what the user actually wants to change.
|
|
STORAGE_PATH="/mnt/cache/system/podman"
|
|
STORAGE_IMAGE_SIZE_GB="20"
|
|
PODMAN_ENABLED="yes"
|
|
STOP_TIMEOUT="10"
|
|
CONFIG_SCHEMA_VERSION="1"
|
|
|
|
if [ -f "$PODMAN_CFG_FILE" ]; then
|
|
# shellcheck source=/dev/null
|
|
. "$PODMAN_CFG_FILE"
|
|
fi
|
|
|
|
# Values derived from STORAGE_PATH, computed after sourcing so a custom
|
|
# STORAGE_PATH is honored.
|
|
PODMAN_STORAGE_IMAGE="$STORAGE_PATH/podman.img"
|
|
PODMAN_LOG_DIR="$STORAGE_PATH/logs"
|
|
PODMAN_GRAPHROOT="/var/lib/containers/storage"
|
|
}
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# podman_log <message>
|
|
#
|
|
# Writes a timestamped line to both stdout (so it shows up in `rc.podman`
|
|
# invocations and CI/manual runs) and to the persistent plugin log on flash
|
|
# (so it survives a reboot — see ARCHITECTURE.md section 15, Logging). Kept
|
|
# deliberately terse (no log levels/rotation logic here) — this is for
|
|
# install/lifecycle events, not container output, which lives under
|
|
# $PODMAN_LOG_DIR instead.
|
|
# -----------------------------------------------------------------------------
|
|
podman_log() {
|
|
local msg="$1"
|
|
local line
|
|
line="$(date -u +'%Y-%m-%dT%H:%M:%SZ') [podman] $msg"
|
|
echo "$line"
|
|
# Best-effort: the boot directory should always exist post-install, but
|
|
# never let logging itself fail a caller that has `set -e`.
|
|
mkdir -p "$PODMAN_BOOT_DIR" 2> /dev/null || true
|
|
echo "$line" >> "$PODMAN_PLUGIN_LOG" 2> /dev/null || true
|
|
}
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# podman_log_error <message>
|
|
#
|
|
# Like podman_log, but also mirrors the message to the system log via
|
|
# `logger`, so it is visible in Unraid's Tools -> System Log GUI without the
|
|
# user having to know where the plugin's own log lives. Reserved for
|
|
# conditions the user should actually notice (see ARCHITECTURE.md 16.2).
|
|
# -----------------------------------------------------------------------------
|
|
podman_log_error() {
|
|
local msg="$1"
|
|
podman_log "ERROR: $msg"
|
|
if command -v logger > /dev/null 2>&1; then
|
|
logger -t podman-plugin "$msg"
|
|
fi
|
|
}
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# podman_notify <subject> <description> [importance]
|
|
#
|
|
# Surfaces a message via Unraid's own GUI notification system
|
|
# (/usr/local/emhttp/webGui/scripts/notify) instead of inventing a parallel
|
|
# notification mechanism — see ARCHITECTURE.md section 16.2. Silently
|
|
# no-ops if that script isn't present (e.g. when running outside a real
|
|
# Unraid system, such as in CI/lint contexts).
|
|
#
|
|
# importance: "normal" (default), "warning", or "alert".
|
|
# -----------------------------------------------------------------------------
|
|
podman_notify() {
|
|
local subject="$1"
|
|
local description="$2"
|
|
local importance="${3:-normal}"
|
|
local notify_bin="/usr/local/emhttp/webGui/scripts/notify"
|
|
|
|
podman_log "notify [$importance] $subject: $description"
|
|
|
|
if [ -x "$notify_bin" ]; then
|
|
"$notify_bin" -e "unraid-podman" -s "$subject" -d "$description" -i "$importance" \
|
|
> /dev/null 2>&1 || true
|
|
fi
|
|
}
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# podman_storage_path_is_safe
|
|
#
|
|
# Refuses storage paths under /mnt/user (FUSE/shfs) — see
|
|
# ARCHITECTURE.md section 4.3 for why the overlay storage driver must live
|
|
# on a real mounted filesystem (cache pool or a specific disk), not shfs.
|
|
# Returns 0 (safe) or 1 (unsafe) and prints a reason on failure.
|
|
# -----------------------------------------------------------------------------
|
|
podman_storage_path_is_safe() {
|
|
local path="$1"
|
|
case "$path" in
|
|
/mnt/user/*|/mnt/user)
|
|
echo "STORAGE_PATH ($path) is under /mnt/user (FUSE/shfs)." >&2
|
|
echo "The overlay storage driver needs a real mounted filesystem —" >&2
|
|
echo "use a cache pool or a specific disk path instead, e.g. /mnt/cache/system/podman." >&2
|
|
return 1
|
|
;;
|
|
esac
|
|
return 0
|
|
}
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# podman_require_command <binary>
|
|
#
|
|
# Fails loudly (rather than letting a script continue and fail confusingly
|
|
# three steps later) if a required binary isn't on PATH.
|
|
# -----------------------------------------------------------------------------
|
|
podman_require_command() {
|
|
local bin="$1"
|
|
if ! command -v "$bin" > /dev/null 2>&1; then
|
|
podman_log_error "required command not found: $bin"
|
|
return 1
|
|
fi
|
|
}
|