Files
unraid-podman/plugin/podman.plg
T
maggesandClaude Sonnet 5 2b79411b68 Replace vendored docker-compose with podman-compose
podman-compose and docker-compose aren't discovered the same way by
`podman compose` - verified live (a fake-binary test reading podman's own
provider-search error output) that docker-compose is searched for by
exact path across a fixed list of CLI-plugin directories, while
podman-compose is instead looked up as a plain command on $PATH. This
package installs to /usr/local/bin/podman-compose accordingly, not under
any cli-plugins/ directory.

Unlike docker-compose (a single static Go binary), podman-compose is a
Python script with two runtime dependencies neither of which ship with
Unraid's own Python3 - PyYAML and python-dotenv, vendored here as plain
pure-Python source (no C extension build; PyYAML's own fallback handles
its optional C accelerator being absent).

Verified end-to-end on a real host: with the previous docker-compose
binary temporarily moved aside to confirm podman-compose was actually the
one invoked, `podman compose up/ps/down` ran a real compose project
correctly, including a live HTTP check against the started service.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-12 18:35:38 +00:00

424 lines
18 KiB
XML

<?xml version="1.0" standalone="yes"?>
<!--
podman.plg — Unraid plugin manifest for unraid-podman.
This file is the single entry point Unraid's Plugin Manager uses to
install, update, and remove the plugin. Everything it does is built on
OFFICIAL Unraid plugin mechanisms only — verified directly against the
real source of two long-established, widely used Unraid plugins
(unraid/community.applications and unraid/unassigned.devices) rather than
guessed:
- A FILE block with a Name attribute, an upgradepkg Run command (using
its install new and reinstall flags together), and a URL/MD5 child
pair is the standard way to download and install a Slackware .txz
package, and the same command works for both a fresh install and an
update in one step (confirmed: both reference plugins use exactly
this pattern rather than separate installpkg/upgradepkg branches).
- Plugin uninstall logic lives in a <FILE Run="/bin/bash" Method="remove">
block — this exact `Method="remove"` attribute is what Unraid's
plugin manager looks for when the user clicks "Remove" (confirmed
against community.applications.plg).
- Boot/shutdown integration uses the official Unraid plugin EVENT
mechanism: any executable at
/usr/local/emhttp/plugins/<name>/event/<eventname> is run automatically
by emhttpd as the corresponding event fires (confirmed against
unassigned.devices, which uses this exact convention for its own
disks_mounted/started/stopping_svcs hooks). This project deliberately
does NOT hand-edit /boot/config/go — see plugin/event/disks_mounted
and plugin/event/stopping for the two hooks used here, and
docs/ARCHITECTURE.md section 6.2 for the full event-ordering rationale.
Structure of this file:
1. DOCTYPE entity block — plugin metadata + one version/file/md5 triple
per package (the seven upstream components, catatonit/nftables/
podman-compose as vendored runtime dependencies, plus this
project's own "unraid-podman" scaffolding package, see
packages/unraid-podman/).
Entities are rewritten automatically by scripts/release.sh; never
hand-edit a *_txz_version/_file/_md5 entity — see that script.
2. <PLUGIN> body:
a. <CHANGES> — kept in sync with CHANGELOG.md by hand for now.
b. Pre-install architecture sanity check.
c. Eleven <FILE> package install/update blocks.
d. Postinstall <FILE Run="/bin/bash"> — directory/config seeding,
install-manifest generation, first start.
e. <FILE Run="/bin/bash" Method="remove"> — uninstall.
-->
<!DOCTYPE PLUGIN [
<!ENTITY name "podman">
<!ENTITY author "unraid-podman contributors">
<!ENTITY version "0.0.0">
<!-- "Podman" (no parent) — Podman.page declares Menu="Podman", making it
its own top-level nav tab next to Docker/VMs, not nested under
Settings — see webui/plugins/podman/Podman.page. -->
<!ENTITY launch "Podman">
<!ENTITY github "OWNER/unraid-podman">
<!ENTITY gitURL "https://raw.githubusercontent.com/&github;/main">
<!ENTITY pluginURL "&gitURL;/plugin/podman.plg">
<!ENTITY supportURL "https://github.com/&github;/discussions">
<!-- Release asset base — matches scripts/release.sh's RELEASE_BASE_URL
exactly; both must agree since release.sh is what publishes the
packages this URL is expected to find. -->
<!ENTITY baseURL "https://github.com/&github;/releases/download/v&version;">
<!-- Slackware package naming components — must match versions.env's
PKG_ARCH/PKG_BUILD/PKG_TAG (see that file). Kept as entities here so
the eleven removepkg calls in the Method="remove" block don't have to
repeat "x86_64-1_unraidpodman" eleven times by hand. -->
<!ENTITY pkgArch "x86_64">
<!ENTITY pkgBuild "1">
<!ENTITY pkgTag "_unraidpodman">
<!-- One version/file/md5 entity triple per package, filled in by
scripts/release.sh from dist/*.txz.md5 at release time (see that
script's "Update per-package entities" step). Until a release has been
cut, these are placeholders and the FILE blocks below will correctly
fail to download anything — that is intentional; there is nothing to
install before the first tagged release. -->
<!ENTITY podman_txz_version "0.0.0">
<!ENTITY podman_txz_file "podman-&podman_txz_version;-&pkgArch;-&pkgBuild;&pkgTag;.txz">
<!ENTITY podman_txz_md5 "00000000000000000000000000000000">
<!ENTITY conmon_txz_version "0.0.0">
<!ENTITY conmon_txz_file "conmon-&conmon_txz_version;-&pkgArch;-&pkgBuild;&pkgTag;.txz">
<!ENTITY conmon_txz_md5 "00000000000000000000000000000000">
<!ENTITY crun_txz_version "0.0.0">
<!ENTITY crun_txz_file "crun-&crun_txz_version;-&pkgArch;-&pkgBuild;&pkgTag;.txz">
<!ENTITY crun_txz_md5 "00000000000000000000000000000000">
<!ENTITY netavark_txz_version "0.0.0">
<!ENTITY netavark_txz_file "netavark-&netavark_txz_version;-&pkgArch;-&pkgBuild;&pkgTag;.txz">
<!ENTITY netavark_txz_md5 "00000000000000000000000000000000">
<!ENTITY aardvark_dns_txz_version "0.0.0">
<!ENTITY aardvark_dns_txz_file "aardvark-dns-&aardvark_dns_txz_version;-&pkgArch;-&pkgBuild;&pkgTag;.txz">
<!ENTITY aardvark_dns_txz_md5 "00000000000000000000000000000000">
<!ENTITY passt_txz_version "0.0.0">
<!ENTITY passt_txz_file "passt-&passt_txz_version;-&pkgArch;-&pkgBuild;&pkgTag;.txz">
<!ENTITY passt_txz_md5 "00000000000000000000000000000000">
<!ENTITY fuse_overlayfs_txz_version "0.0.0">
<!ENTITY fuse_overlayfs_txz_file "fuse-overlayfs-&fuse_overlayfs_txz_version;-&pkgArch;-&pkgBuild;&pkgTag;.txz">
<!ENTITY fuse_overlayfs_txz_md5 "00000000000000000000000000000000">
<!-- catatonit and nftables are runtime dependencies this plugin ships,
not upstream podman-ecosystem components — see packages/catatonit/
and packages/nftables/ READMEs for why each is needed (pod infra
container init; netavark's only viable firewall driver, since it
dropped iptables in 2.0 and Unraid has neither `nft` nor
systemd/dbus for firewalld) and why neither is built from source. -->
<!ENTITY catatonit_txz_version "0.0.0">
<!ENTITY catatonit_txz_file "catatonit-&catatonit_txz_version;-&pkgArch;-&pkgBuild;&pkgTag;.txz">
<!ENTITY catatonit_txz_md5 "00000000000000000000000000000000">
<!ENTITY nftables_txz_version "0.0.0">
<!ENTITY nftables_txz_file "nftables-&nftables_txz_version;-&pkgArch;-&pkgBuild;&pkgTag;.txz">
<!ENTITY nftables_txz_md5 "00000000000000000000000000000000">
<!-- podman-compose is the external Compose provider `podman compose`
shells out to (see packages/podman-compose/README.md) — without it
every Compose panel action fails outright on a clean install. -->
<!ENTITY podman_compose_txz_version "0.0.0">
<!ENTITY podman_compose_txz_file "podman-compose-&podman_compose_txz_version;-&pkgArch;-&pkgBuild;&pkgTag;.txz">
<!ENTITY podman_compose_txz_md5 "00000000000000000000000000000000">
<!-- unraid-podman is this project's OWN scaffolding package (rc.podman,
sbin/ scripts, event/ hooks, config templates — see
packages/unraid-podman/README.md), not an upstream component. Its
version always equals the plugin's own &version; — see
packages/unraid-podman/unraid-podman.SlackBuild, which reads it
straight out of this very file rather than tracking it twice. -->
<!ENTITY unraid_podman_txz_version "&version;">
<!ENTITY unraid_podman_txz_file "unraid-podman-&unraid_podman_txz_version;-&pkgArch;-&pkgBuild;&pkgTag;.txz">
<!ENTITY unraid_podman_txz_md5 "00000000000000000000000000000000">
]>
<PLUGIN name="&name;"
author="&author;"
version="&version;"
launch="&launch;"
pluginURL="&pluginURL;"
support="&supportURL;"
icon="cubes"
min="6.12.0">
<!--
min="6.12.0": Unraid 6.12 introduced folder-based (non-loopback) Docker
storage and is a reasonably conservative baseline for the cgroup v2 /
kernel networking features netavark, aardvark-dns, and passt assume. See
docs/ARCHITECTURE.md section 21 (open question — revisit if real-world
testing shows an earlier or later minimum is actually required).
-->
<CHANGES>
##podman
###0.0.0
- Initial scaffolding. Not a functional release — see CHANGELOG.md for the
authoritative, up-to-date history; this block is kept in sync with it by
hand at release time (scripts/release.sh does not touch this section).
</CHANGES>
<!--
Pre-install sanity check: this project only builds/ships x86_64 packages
(see versions.env's PKG_ARCH) — fail with a clear message on any other
architecture rather than letting eleven package downloads 404 one by one.
-->
<FILE Run="/bin/bash">
<INLINE>
if [ "$(uname -m)" != "x86_64" ]; then
echo "unraid-podman only supports x86_64 (detected: $(uname -m)) - aborting install."
exit 1
fi
</INLINE>
</FILE>
<!--
The seven upstream component packages, plus catatonit, nftables, and
podman-compose (runtime dependencies vendored as-is — see the entity
block above for why). Each is downloaded straight into
its backup slot under /boot/config/plugins/&name;/backup/packages/&version;/
(grouped by PLUGIN version, not each component's own version — a rollback
targets "this plugin release" as one unit, see
plugin/sbin/podman-backup.sh's header comment) and installed from there
in place via upgradepkg's install new / reinstall flags, which handle
both a fresh install and an update to a newer version identically (see
file header comment). This download-destination-doubles-as-backup approach is
what makes plugin/sbin/podman-backup.sh's restore-packages command work
with no separate copy step.
-->
<FILE Name="/boot/config/plugins/&name;/backup/packages/&version;/&podman_txz_file;" Run="upgradepkg --install-new --reinstall">
<URL>
&baseURL;/&podman_txz_file;
</URL>
<MD5>
&podman_txz_md5;
</MD5>
</FILE>
<FILE Name="/boot/config/plugins/&name;/backup/packages/&version;/&conmon_txz_file;" Run="upgradepkg --install-new --reinstall">
<URL>
&baseURL;/&conmon_txz_file;
</URL>
<MD5>
&conmon_txz_md5;
</MD5>
</FILE>
<FILE Name="/boot/config/plugins/&name;/backup/packages/&version;/&crun_txz_file;" Run="upgradepkg --install-new --reinstall">
<URL>
&baseURL;/&crun_txz_file;
</URL>
<MD5>
&crun_txz_md5;
</MD5>
</FILE>
<FILE Name="/boot/config/plugins/&name;/backup/packages/&version;/&netavark_txz_file;" Run="upgradepkg --install-new --reinstall">
<URL>
&baseURL;/&netavark_txz_file;
</URL>
<MD5>
&netavark_txz_md5;
</MD5>
</FILE>
<FILE Name="/boot/config/plugins/&name;/backup/packages/&version;/&aardvark_dns_txz_file;" Run="upgradepkg --install-new --reinstall">
<URL>
&baseURL;/&aardvark_dns_txz_file;
</URL>
<MD5>
&aardvark_dns_txz_md5;
</MD5>
</FILE>
<FILE Name="/boot/config/plugins/&name;/backup/packages/&version;/&passt_txz_file;" Run="upgradepkg --install-new --reinstall">
<URL>
&baseURL;/&passt_txz_file;
</URL>
<MD5>
&passt_txz_md5;
</MD5>
</FILE>
<FILE Name="/boot/config/plugins/&name;/backup/packages/&version;/&fuse_overlayfs_txz_file;" Run="upgradepkg --install-new --reinstall">
<URL>
&baseURL;/&fuse_overlayfs_txz_file;
</URL>
<MD5>
&fuse_overlayfs_txz_md5;
</MD5>
</FILE>
<FILE Name="/boot/config/plugins/&name;/backup/packages/&version;/&catatonit_txz_file;" Run="upgradepkg --install-new --reinstall">
<URL>
&baseURL;/&catatonit_txz_file;
</URL>
<MD5>
&catatonit_txz_md5;
</MD5>
</FILE>
<FILE Name="/boot/config/plugins/&name;/backup/packages/&version;/&nftables_txz_file;" Run="upgradepkg --install-new --reinstall">
<URL>
&baseURL;/&nftables_txz_file;
</URL>
<MD5>
&nftables_txz_md5;
</MD5>
</FILE>
<FILE Name="/boot/config/plugins/&name;/backup/packages/&version;/&podman_compose_txz_file;" Run="upgradepkg --install-new --reinstall">
<URL>
&baseURL;/&podman_compose_txz_file;
</URL>
<MD5>
&podman_compose_txz_md5;
</MD5>
</FILE>
<!--
The plugin's own scaffolding package — rc.podman, sbin/ helper scripts,
the event/ hooks below, and default config templates. See
packages/unraid-podman/README.md.
-->
<FILE Name="/boot/config/plugins/&name;/backup/packages/&version;/&unraid_podman_txz_file;" Run="upgradepkg --install-new --reinstall">
<URL>
&baseURL;/&unraid_podman_txz_file;
</URL>
<MD5>
&unraid_podman_txz_md5;
</MD5>
</FILE>
<!--
Postinstall: everything that has to happen AFTER the eleven packages above
are on disk, but isn't itself package content — directory/config
seeding, the install-manifest that plugin/sbin/podman-verify-packages.sh
and podman-update-packages.sh read, and the first start. Runs on both
fresh install and every update (Unraid re-runs the whole .plg either way)
— every step here is written to be idempotent, per
docs/ARCHITECTURE.md section 7.
-->
<!--
IMPORTANT for anyone editing this block: it is deliberately NOT wrapped
in <![CDATA[ ]]>. CDATA sections suppress XML entity expansion entirely,
which would leave literal, unexpanded text like "&version;" in the
generated installed-versions.env instead of the real version number —
confirmed by direct testing against this exact file. This is also why
real Unraid plugins (community.applications, unassigned.devices) never
wrap their entity-referencing INLINE scripts in CDATA either. The
practical consequence: avoid literal '<' in this script (heredocs
included) — a sequence of individual "echo >>" lines is used below
instead for exactly that reason. A lone '>' is fine unescaped in XML
content (only '<' and '&' are not) — verified empirically, not assumed.
-->
<FILE Run="/bin/bash">
<INLINE>
set -u
echo "Setting permissions..."
chmod 0755 /etc/rc.d/rc.podman
chmod 0755 /usr/local/sbin/*.sh
chmod 0755 /usr/local/emhttp/plugins/podman/event/disks_mounted
chmod 0755 /usr/local/emhttp/plugins/podman/event/stopping
echo "Writing installed-package manifest..."
mkdir -p /usr/local/share/unraid-podman
MANIFEST=/usr/local/share/unraid-podman/installed-versions.env
echo "# Generated by podman.plg postinstall - do not edit by hand." > "$MANIFEST"
echo "# Read by podman-verify-packages.sh and podman-update-packages.sh." >> "$MANIFEST"
echo "PLUGIN_VERSION=\"&version;\"" >> "$MANIFEST"
echo "PODMAN_INSTALLED_VERSION=\"&podman_txz_version;\"" >> "$MANIFEST"
echo "CONMON_INSTALLED_VERSION=\"&conmon_txz_version;\"" >> "$MANIFEST"
echo "CRUN_INSTALLED_VERSION=\"&crun_txz_version;\"" >> "$MANIFEST"
echo "NETAVARK_INSTALLED_VERSION=\"&netavark_txz_version;\"" >> "$MANIFEST"
echo "AARDVARK_DNS_INSTALLED_VERSION=\"&aardvark_dns_txz_version;\"" >> "$MANIFEST"
echo "PASST_INSTALLED_VERSION=\"&passt_txz_version;\"" >> "$MANIFEST"
echo "FUSE_OVERLAYFS_INSTALLED_VERSION=\"&fuse_overlayfs_txz_version;\"" >> "$MANIFEST"
echo "CATATONIT_INSTALLED_VERSION=\"&catatonit_txz_version;\"" >> "$MANIFEST"
echo "NFTABLES_INSTALLED_VERSION=\"&nftables_txz_version;\"" >> "$MANIFEST"
echo "PODMAN_COMPOSE_INSTALLED_VERSION=\"&podman_compose_txz_version;\"" >> "$MANIFEST"
echo "UNRAID_PODMAN_INSTALLED_VERSION=\"&unraid_podman_txz_version;\"" >> "$MANIFEST"
echo "Seeding /boot/config/plugins/podman/ configuration (existing files left untouched)..."
/usr/local/sbin/podman-config.sh seed
echo "Verifying package installation..."
if /usr/local/sbin/podman-verify-packages.sh --quiet; then
echo "Package verification OK."
else
echo "WARNING: package verification reported problems - see /boot/config/plugins/podman/plugin.log"
fi
echo "Starting podman..."
if /etc/rc.d/rc.podman start; then
echo ""
echo "----------------------------------------------------"
echo " unraid-podman &version; has been installed and started."
echo " CLI: podman --url unix:///var/run/podman/podman.sock ..."
echo " Docs: https://github.com/&github;"
echo "----------------------------------------------------"
echo ""
else
echo ""
echo "----------------------------------------------------"
echo " unraid-podman &version; was installed but did not start cleanly."
echo " It will be retried automatically the next time the array starts"
echo " (see /usr/local/emhttp/plugins/podman/event/disks_mounted)."
echo " Check /boot/config/plugins/podman/plugin.log for details."
echo "----------------------------------------------------"
echo ""
fi
</INLINE>
</FILE>
<!--
Uninstall. Triggered by Unraid's Plugin Manager when the user clicks
"Remove" — the Method="remove" attribute is what makes this block
(rather than any of the install blocks above) run in that case.
Order matters: podman-uninstall-cleanup.sh runs FIRST, while the
unraid-podman package (which contains it, at /usr/local/sbin/) is still
on disk — removepkg-ing it out from under itself mid-script would be a
mistake. See that script's own header comment for exactly what is and
is not removed by default (user data is preserved unless the purge-data
flag is passed, which this normal removal flow deliberately never does).
-->
<!-- Not CDATA-wrapped — see the comment above the postinstall block for why: this content needs its &..._txz_file; entity references expanded, and CDATA would suppress that. Nothing here needs an unescaped '<'. -->
<FILE Run="/bin/bash" Method="remove">
<INLINE>
echo "Running unraid-podman cleanup..."
/usr/local/sbin/podman-uninstall-cleanup.sh
echo "Removing packages..."
removepkg &podman_txz_file;
removepkg &conmon_txz_file;
removepkg &crun_txz_file;
removepkg &netavark_txz_file;
removepkg &aardvark_dns_txz_file;
removepkg &passt_txz_file;
removepkg &fuse_overlayfs_txz_file;
removepkg &catatonit_txz_file;
removepkg &nftables_txz_file;
removepkg &podman_compose_txz_file;
removepkg &unraid_podman_txz_file;
echo ""
echo "unraid-podman removed. Your configuration, backups, and container"
echo "storage under /boot/config/plugins/podman/ and the configured"
echo "STORAGE_PATH were left in place - see docs/INSTALL.md if you want"
echo "to remove them too."
echo ""
</INLINE>
</FILE>
</PLUGIN>