unattended-upgrades was already active on the host, just never documented or closed. Adds a generic, reusable systemd timer + script that fires before the daily update window and notifies via email and a Matrix thread reply if any packages are actually pending - reusing the mas-cli bot account pattern established for Draupnir. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
103 lines
3.5 KiB
Bash
Executable File
103 lines
3.5 KiB
Bash
Executable File
#!/bin/bash
|
|
# Pre-update maintenance notification. Runs as a systemd oneshot service, well
|
|
# before apt-daily-upgrade.timer's own window, and tells you (Mail + Matrix)
|
|
# which packages are about to be auto-upgraded - so a post-update problem can
|
|
# immediately be traced back to "the update ran, that's probably it".
|
|
#
|
|
# Generic by design: no instance-specific values are hardcoded here. All of
|
|
# them live in /etc/maintenance-notify/config - see config.example in this
|
|
# same directory, and docs/deployment-guides/07-host-maintenance-notifications.md
|
|
# for the full setup guide.
|
|
set -euo pipefail
|
|
|
|
CONFIG_FILE="/etc/maintenance-notify/config"
|
|
MATRIX_TOKEN_FILE="/etc/maintenance-notify/matrix-token"
|
|
|
|
if [ ! -f "$CONFIG_FILE" ]; then
|
|
echo "Missing $CONFIG_FILE - see docs/deployment-guides/07-host-maintenance-notifications.md" >&2
|
|
exit 1
|
|
fi
|
|
# shellcheck source=/dev/null
|
|
. "$CONFIG_FILE"
|
|
|
|
: "${MATRIX_HOMESERVER:?MATRIX_HOMESERVER not set in $CONFIG_FILE}"
|
|
: "${MATRIX_ROOM_ID:?MATRIX_ROOM_ID not set in $CONFIG_FILE}"
|
|
: "${MATRIX_THREAD_EVENT_ID:?MATRIX_THREAD_EVENT_ID not set in $CONFIG_FILE}"
|
|
: "${MAIL_FROM:?MAIL_FROM not set in $CONFIG_FILE}"
|
|
: "${MAIL_TO:?MAIL_TO not set in $CONFIG_FILE}"
|
|
|
|
apt-get update -qq
|
|
|
|
DRYRUN_OUTPUT="$(unattended-upgrade --dry-run -v 2>&1)"
|
|
|
|
# Exact log strings taken from /usr/bin/unattended-upgrade itself (verified
|
|
# live on the target host), not guessed - this is the one message emitted
|
|
# when there is nothing to do, and the one line emitted with the package
|
|
# list otherwise. They're mutually exclusive.
|
|
if echo "$DRYRUN_OUTPUT" | grep -q "No packages found that can be upgraded unattended"; then
|
|
echo "No pending upgrades - nothing to notify."
|
|
exit 0
|
|
fi
|
|
|
|
PENDING_PKGS="$(echo "$DRYRUN_OUTPUT" | sed -n 's/^.*Packages that will be upgraded: //p' | tail -1)"
|
|
|
|
if [ -z "$PENDING_PKGS" ]; then
|
|
echo "No pending upgrade packages parsed - nothing to notify."
|
|
exit 0
|
|
fi
|
|
|
|
HOST_LABEL="$(hostname -f 2>/dev/null || hostname)"
|
|
NOW="$(date '+%Y-%m-%d %H:%M %Z')"
|
|
|
|
BODY="Host: ${HOST_LABEL}
|
|
Zeitpunkt: ${NOW}
|
|
|
|
Im naechsten apt-daily-upgrade.timer-Fenster werden folgende Pakete automatisch aktualisiert:
|
|
|
|
${PENDING_PKGS}
|
|
|
|
Automatische Vorab-Benachrichtigung, keine Aktion erforderlich."
|
|
|
|
send_mail() {
|
|
if ! command -v msmtp >/dev/null 2>&1; then
|
|
echo "msmtp not installed, skipping mail notification" >&2
|
|
return 1
|
|
fi
|
|
{
|
|
echo "From: ${MAIL_FROM}"
|
|
echo "To: ${MAIL_TO}"
|
|
echo "Subject: [${HOST_LABEL}] Anstehendes Update"
|
|
echo
|
|
echo "$BODY"
|
|
} | msmtp -a maintenance-notify -- "${MAIL_TO}"
|
|
}
|
|
|
|
send_matrix() {
|
|
if [ ! -f "$MATRIX_TOKEN_FILE" ]; then
|
|
echo "Missing $MATRIX_TOKEN_FILE, skipping Matrix notification" >&2
|
|
return 1
|
|
fi
|
|
local token txn_id encoded_room payload
|
|
token="$(cat "$MATRIX_TOKEN_FILE")"
|
|
txn_id="$(uuidgen)"
|
|
encoded_room="$(jq -rn --arg s "$MATRIX_ROOM_ID" '$s|@uri')"
|
|
payload="$(jq -n --arg body "$BODY" --arg event_id "$MATRIX_THREAD_EVENT_ID" \
|
|
'{msgtype: "m.text", body: $body, "m.relates_to": {rel_type: "m.thread", event_id: $event_id}}')"
|
|
curl -sS -f -X PUT \
|
|
-H "Authorization: Bearer ${token}" \
|
|
-H "Content-Type: application/json" \
|
|
--data "$payload" \
|
|
"${MATRIX_HOMESERVER}/_matrix/client/v3/rooms/${encoded_room}/send/m.room.message/${txn_id}" \
|
|
> /dev/null
|
|
}
|
|
|
|
mail_ok=0
|
|
matrix_ok=0
|
|
send_mail && mail_ok=1
|
|
send_matrix && matrix_ok=1
|
|
|
|
if [ "$mail_ok" -eq 0 ] && [ "$matrix_ok" -eq 0 ]; then
|
|
echo "Both mail and Matrix notification failed" >&2
|
|
exit 1
|
|
fi
|