Harden incus-container-upgrade: containers only, flock, error reporting

- filter type=container (a running VM without apt/agent would hang)
- skip containers without apt-get instead of erroring
- flock against overlapping runs, csv parsing, apt-get instead of apt
- capture stderr into the log, report per-container failures and
  exit non-zero so cron/monitoring can alert

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Julien Lutran
2026-08-09 22:50:26 +02:00
co-authored by Claude Fable 5
parent 856ea28d93
commit 43b3ab5841
+32 -8
View File
@@ -1,16 +1,40 @@
#!/bin/bash
#
# apt dist-upgrade of all RUNNING containers (containers only — VMs are
# excluded, they may not run an agent or apt at all). Containers without
# apt are skipped. Exits non-zero if any upgrade failed.
set -uo pipefail
INCUS=/usr/bin/incus
LOG=/var/log/incus-container-upgrade.log
LOCKFILE=/run/lock/incus-container-upgrade.lock
# refuse to overlap with a previous, still-running invocation
exec 9> "$LOCKFILE"
if ! flock -n 9; then
echo "another incus-container-upgrade run holds $LOCKFILE, aborting" >&2
exit 1
fi
distUpgrade() {
CT=$1
DATE=$(date '+%Y-%m-%d %H:%M:%S')
echo -e "\n*** [$DATE] - Dist-upgrading $CT container ***\n"
incus exec $CT --env DEBIAN_FRONTEND=noninteractive -- apt -qq update
incus exec $CT --env DEBIAN_FRONTEND=noninteractive -- apt list --upgradable
incus exec $CT --env DEBIAN_FRONTEND=noninteractive -- apt -qq -y dist-upgrade
local CT=$1
echo -e "\n*** [$(date '+%F %T')] - Dist-upgrading $CT container ***\n"
if ! $INCUS exec "$CT" -- sh -c 'command -v apt-get >/dev/null'; then
echo "$CT: no apt-get in container, skipping"
return 0
fi
$INCUS exec "$CT" --env DEBIAN_FRONTEND=noninteractive -- apt-get -qq update &&
$INCUS exec "$CT" -- sh -c 'apt list --upgradable 2>/dev/null' &&
$INCUS exec "$CT" --env DEBIAN_FRONTEND=noninteractive -- apt-get -qq -y dist-upgrade
}
for CT in $(incus ls -c n -f compact,noheader status=RUNNING) ; do
distUpgrade "$CT" | tee -a /var/log/incus-container-upgrade.log
RC=0
for CT in $($INCUS list -c n -f csv status=RUNNING type=container); do
if ! distUpgrade "$CT" 2>&1 | tee -a "$LOG"; then
echo "[$(date '+%F %T')] FAILED: $CT" | tee -a "$LOG" >&2
RC=1
fi
done
exit $RC