diff --git a/incus-container-upgrade.sh b/incus-container-upgrade.sh index 42a4e0a..6251062 100755 --- a/incus-container-upgrade.sh +++ b/incus-container-upgrade.sh @@ -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