Enhance docker infrastructure automation with staggered auto-reboot functionality and update README. Added support for scheduling reboots in the APT weekly script and introduced boot report automations for docker hosts. #1539

pull/1581/head
Carlo Costanzo 1 month ago
parent 84d638c1fc
commit 799a73dd7e

@ -45,7 +45,7 @@ Live collection of plug-and-play Home Assistant packages. Each YAML file in this
| [lightning.yaml](lightning.yaml) | Blitzortung lightning counter monitoring with snoozeable push actions. | `sensor.blitzortung_lightning_counter`, `input_boolean.snooze_lightning`, notify engine actions |
| [logbook_activity_feed.yaml](logbook_activity_feed.yaml) | Dummy `sensor.activity_feed` + helper to write clean Activity entries (Issue #1550). | `sensor.activity_feed`, `script.send_to_logbook` |
| [mariadb_monitoring.yaml](mariadb_monitoring.yaml) | MariaDB health sensors and Lovelace dashboard snippet for recorder stats. | `sensor.mariadb_status`, `sensor.database_size` |
| [docker_infrastructure.yaml](docker_infrastructure.yaml) | Docker host patching + container-down Repairs alerts. | `sensor.docker_*_apt_status`, `repairs.create` |
| [docker_infrastructure.yaml](docker_infrastructure.yaml) | Docker host patching + staggered auto-reboot flow + container-down Repairs alerts. | `sensor.docker_*_apt_status`, `repairs.create`, `repairs.remove` |
| [mariadb.yaml](mariadb.yaml) | MariaDB recorder health and capacity SQL sensors. | `sensor.mariadb_status`, `sensor.database_size` |
| [tugtainer_updates.yaml](tugtainer_updates.yaml) | Tugtainer container update notifications via webhook + persistent alerts. | `persistent_notification.create`, `input_datetime.tugtainer_last_update` |
| [phynplus.yaml](phynplus.yaml) | Phyn shutoff automations with push + Activity feed + Repairs issues for leak events. | `valve.phyn_shutoff_valve`, `binary_sensor.phyn_leak_test_running`, `repairs.create` |

@ -7,6 +7,8 @@
# APT webhook results and container down repairs.
# -------------------------------------------------------------------
# Notes: Hosts run weekly Wed 12:00 APT job and POST JSON to webhooks.
# Notes: If reboot is required, hosts auto-schedule reboot after posting status.
# Notes: Reboot staggering: docker_14 reboots first, docker_10 reboots later.
# Notes: Container watchlist is explicit; extend entity list as needed.
######################################################################
@ -179,17 +181,21 @@ automation:
updated: "{{ payload.get('updated', false) | bool }}"
packages: "{{ payload.get('packages', 0) | int(0) }}"
reboot_required: "{{ payload.get('reboot_required', false) | bool }}"
auto_reboot_scheduled: "{{ payload.get('auto_reboot_scheduled', false) | bool }}"
reboot_delay_minutes: "{{ payload.get('reboot_delay_minutes', 0) | int(0) }}"
message: "{{ payload.get('message', '') | string }}"
result: >-
{% if not success %}
ERROR{% if (message | trim) != '' %}: {{ message | trim }}{% endif %}
{% elif reboot_required and not updated %}
REBOOT REQUIRED{% if auto_reboot_scheduled %}; AUTO REBOOT {{ reboot_delay_minutes }}M{% endif %}
{% elif updated %}
UPDATED {{ packages }} PKGS{% if reboot_required %}; REBOOT REQUIRED{% endif %}
UPDATED {{ packages }} PKGS{% if reboot_required %}; REBOOT REQUIRED{% endif %}{% if auto_reboot_scheduled %}; AUTO REBOOT {{ reboot_delay_minutes }}M{% endif %}
{% else %}
NO UPDATES
{% endif %}
log_message: >-
docker_10 updated {{ packages }} package{% if packages != 1 %}s{% endif %}{% if reboot_required %} (reboot required){% endif %}.
docker_10 updated {{ packages }} package{% if packages != 1 %}s{% endif %}{% if reboot_required %} (reboot required){% endif %}{% if auto_reboot_scheduled %}; auto reboot in {{ reboot_delay_minutes }} minute{% if reboot_delay_minutes != 1 %}s{% endif %}{% endif %}.
action:
- service: input_datetime.set_datetime
target:
@ -240,17 +246,21 @@ automation:
updated: "{{ payload.get('updated', false) | bool }}"
packages: "{{ payload.get('packages', 0) | int(0) }}"
reboot_required: "{{ payload.get('reboot_required', false) | bool }}"
auto_reboot_scheduled: "{{ payload.get('auto_reboot_scheduled', false) | bool }}"
reboot_delay_minutes: "{{ payload.get('reboot_delay_minutes', 0) | int(0) }}"
message: "{{ payload.get('message', '') | string }}"
result: >-
{% if not success %}
ERROR{% if (message | trim) != '' %}: {{ message | trim }}{% endif %}
{% elif reboot_required and not updated %}
REBOOT REQUIRED{% if auto_reboot_scheduled %}; AUTO REBOOT {{ reboot_delay_minutes }}M{% endif %}
{% elif updated %}
UPDATED {{ packages }} PKGS{% if reboot_required %}; REBOOT REQUIRED{% endif %}
UPDATED {{ packages }} PKGS{% if reboot_required %}; REBOOT REQUIRED{% endif %}{% if auto_reboot_scheduled %}; AUTO REBOOT {{ reboot_delay_minutes }}M{% endif %}
{% else %}
NO UPDATES
{% endif %}
log_message: >-
docker_14 updated {{ packages }} package{% if packages != 1 %}s{% endif %}{% if reboot_required %} (reboot required){% endif %}.
docker_14 updated {{ packages }} package{% if packages != 1 %}s{% endif %}{% if reboot_required %} (reboot required){% endif %}{% if auto_reboot_scheduled %}; auto reboot in {{ reboot_delay_minutes }} minute{% if reboot_delay_minutes != 1 %}s{% endif %}{% endif %}.
action:
- service: input_datetime.set_datetime
target:
@ -301,17 +311,21 @@ automation:
updated: "{{ payload.get('updated', false) | bool }}"
packages: "{{ payload.get('packages', 0) | int(0) }}"
reboot_required: "{{ payload.get('reboot_required', false) | bool }}"
auto_reboot_scheduled: "{{ payload.get('auto_reboot_scheduled', false) | bool }}"
reboot_delay_minutes: "{{ payload.get('reboot_delay_minutes', 0) | int(0) }}"
message: "{{ payload.get('message', '') | string }}"
result: >-
{% if not success %}
ERROR{% if (message | trim) != '' %}: {{ message | trim }}{% endif %}
{% elif reboot_required and not updated %}
REBOOT REQUIRED{% if auto_reboot_scheduled %}; AUTO REBOOT {{ reboot_delay_minutes }}M{% endif %}
{% elif updated %}
UPDATED {{ packages }} PKGS{% if reboot_required %}; REBOOT REQUIRED{% endif %}
UPDATED {{ packages }} PKGS{% if reboot_required %}; REBOOT REQUIRED{% endif %}{% if auto_reboot_scheduled %}; AUTO REBOOT {{ reboot_delay_minutes }}M{% endif %}
{% else %}
NO UPDATES
{% endif %}
log_message: >-
docker_69 updated {{ packages }} package{% if packages != 1 %}s{% endif %}{% if reboot_required %} (reboot required){% endif %}.
docker_69 updated {{ packages }} package{% if packages != 1 %}s{% endif %}{% if reboot_required %} (reboot required){% endif %}{% if auto_reboot_scheduled %}; auto reboot in {{ reboot_delay_minutes }} minute{% if reboot_delay_minutes != 1 %}s{% endif %}{% endif %}.
action:
- service: input_datetime.set_datetime
target:
@ -346,6 +360,105 @@ automation:
topic: "APT"
message: "{{ log_message }}"
- alias: "APT Boot Report - docker_10"
id: apt_boot_report_docker_10
description: "Clear or keep reboot-required flag after docker_10 boots."
mode: queued
trigger:
- platform: webhook
webhook_id: !secret apt_boot_webhook_docker_10
allowed_methods:
- POST
local_only: true
variables:
payload: "{{ trigger.json | default({}) }}"
reboot_required: "{{ payload.get('reboot_required', false) | bool }}"
action:
- choose:
- conditions: "{{ reboot_required }}"
sequence:
- service: input_boolean.turn_on
target:
entity_id: input_boolean.apt_docker_10_reboot_required
- service: script.send_to_logbook
data:
topic: "APT"
message: "docker_10 boot report: reboot is still required."
default:
- service: input_boolean.turn_off
target:
entity_id: input_boolean.apt_docker_10_reboot_required
- service: script.send_to_logbook
data:
topic: "APT"
message: "docker_10 reboot completed and reboot flag cleared."
- alias: "APT Boot Report - docker_14"
id: apt_boot_report_docker_14
description: "Clear or keep reboot-required flag after docker_14 boots."
mode: queued
trigger:
- platform: webhook
webhook_id: !secret apt_boot_webhook_docker_14
allowed_methods:
- POST
local_only: true
variables:
payload: "{{ trigger.json | default({}) }}"
reboot_required: "{{ payload.get('reboot_required', false) | bool }}"
action:
- choose:
- conditions: "{{ reboot_required }}"
sequence:
- service: input_boolean.turn_on
target:
entity_id: input_boolean.apt_docker_14_reboot_required
- service: script.send_to_logbook
data:
topic: "APT"
message: "docker_14 boot report: reboot is still required."
default:
- service: input_boolean.turn_off
target:
entity_id: input_boolean.apt_docker_14_reboot_required
- service: script.send_to_logbook
data:
topic: "APT"
message: "docker_14 reboot completed and reboot flag cleared."
- alias: "APT Boot Report - docker_69"
id: apt_boot_report_docker_69
description: "Clear or keep reboot-required flag after docker_69 boots."
mode: queued
trigger:
- platform: webhook
webhook_id: !secret apt_boot_webhook_docker_69
allowed_methods:
- POST
local_only: true
variables:
payload: "{{ trigger.json | default({}) }}"
reboot_required: "{{ payload.get('reboot_required', false) | bool }}"
action:
- choose:
- conditions: "{{ reboot_required }}"
sequence:
- service: input_boolean.turn_on
target:
entity_id: input_boolean.apt_docker_69_reboot_required
- service: script.send_to_logbook
data:
topic: "APT"
message: "docker_69 boot report: reboot is still required."
default:
- service: input_boolean.turn_off
target:
entity_id: input_boolean.apt_docker_69_reboot_required
- service: script.send_to_logbook
data:
topic: "APT"
message: "docker_69 reboot completed and reboot flag cleared."
- alias: "APT Reboot Repairs"
id: apt_reboot_repairs
description: "Create or clear Repairs issues when Docker hosts need a reboot."

@ -27,6 +27,8 @@ Longer-running shell helpers referenced by automations, packages, or cron. Anyth
| File | Why it matters |
| --- | --- |
| [HAUpdate.sh](HAUpdate.sh) | One-command Home Assistant update helper. |
| [apt_weekly.sh](apt_weekly.sh) | Weekly APT updater that posts webhook status and can schedule reboot when needed. |
| [apt_reboot_report.sh](apt_reboot_report.sh) | Boot-time webhook status reporter that clears/keeps reboot-required state in HA. |
| [gitupdate.sh](gitupdate.sh) | Pull the latest config changes on demand. |
| [basketball.yaml](basketball.yaml) | ESPN stat scraping helper used by sensors. |
| [Jinja Code.py](Jinja Code.py) | Reference Jinja snippets for templating. |

@ -0,0 +1,13 @@
[Unit]
Description=Report boot completion for APT reboot tracking
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/apt_reboot_report.sh https://HOMEASSISTANT_HOST:8123/api/webhook/REPLACE_WITH_BOOT_WEBHOOK_ID docker_10
User=root
Group=root
[Install]
WantedBy=multi-user.target

@ -0,0 +1,29 @@
#!/usr/bin/env bash
set -euo pipefail
# Boot report for APT-managed hosts.
# Sends current reboot-required state after each system boot.
WEBHOOK_URL="$1"
HOST_NAME="${2:-$(hostname -s)}"
if [[ -z "$WEBHOOK_URL" ]]; then
echo "Usage: $0 <webhook_url> [host_name]" >&2
exit 1
fi
REBOOT_REQUIRED=false
if [[ -f /var/run/reboot-required ]]; then
REBOOT_REQUIRED=true
fi
payload=$(cat <<JSON
{
"event": "boot_report",
"host": "${HOST_NAME}",
"reboot_required": $( $REBOOT_REQUIRED && echo true || echo false )
}
JSON
)
curl -sS -X POST -H 'Content-Type: application/json' -d "$payload" "$WEBHOOK_URL" || true

@ -5,7 +5,7 @@ Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/apt_weekly.sh https://HOMEASSISTANT_HOST:8123/api/webhook/REPLACE_WITH_WEBHOOK_ID
ExecStart=/usr/local/sbin/apt_weekly.sh https://HOMEASSISTANT_HOST:8123/api/webhook/REPLACE_WITH_APT_WEBHOOK_ID docker_10 20
User=root
Group=root
Nice=10

@ -2,15 +2,27 @@
set -euo pipefail
# Weekly APT maintenance for docker hosts (runs Wednesdays at 12:00 local via systemd timer)
# Posts results to Home Assistant webhook.
# Posts results to Home Assistant webhook and optionally schedules reboot when required.
WEBHOOK_URL="$1"
HOST_NAME="${2:-$(hostname -s)}"
REBOOT_DELAY_MINUTES="${3:-}"
if [[ -z "$WEBHOOK_URL" ]]; then
echo "Usage: $0 <webhook_url>" >&2
echo "Usage: $0 <webhook_url> [host_name] [reboot_delay_minutes]" >&2
exit 1
fi
AUTO_REBOOT=false
if [[ -n "$REBOOT_DELAY_MINUTES" ]]; then
if [[ "$REBOOT_DELAY_MINUTES" =~ ^[0-9]+$ ]]; then
AUTO_REBOOT=true
else
echo "reboot_delay_minutes must be a non-negative integer" >&2
exit 1
fi
fi
log() { echo "[$(date --iso-8601=seconds)] $*"; }
UPDATED=false
@ -45,10 +57,13 @@ fi
payload=$(cat <<JSON
{
"host": "${HOST_NAME}",
"success": $( [[ "$MESSAGE" == "" ]] && echo true || echo false ),
"updated": $( $UPDATED && echo true || echo false ),
"packages": $PACKAGES,
"reboot_required": $( $REBOOT && echo true || echo false ),
"auto_reboot_scheduled": $( [[ "$REBOOT" == true && "$AUTO_REBOOT" == true && "$MESSAGE" == "" ]] && echo true || echo false ),
"reboot_delay_minutes": ${REBOOT_DELAY_MINUTES:-0},
"message": "${MESSAGE}"
}
JSON
@ -56,3 +71,14 @@ JSON
log "Posting results to Home Assistant"
curl -sS -X POST -H 'Content-Type: application/json' -d "$payload" "$WEBHOOK_URL" || true
if [[ "$REBOOT" == true && "$AUTO_REBOOT" == true && "$MESSAGE" == "" ]]; then
shutdown -c >/dev/null 2>&1 || true
if [[ "$REBOOT_DELAY_MINUTES" -eq 0 ]]; then
log "Reboot required; rebooting immediately."
shutdown -r now "APT weekly maintenance reboot"
else
log "Reboot required; scheduling reboot in ${REBOOT_DELAY_MINUTES} minute(s)."
shutdown -r +"$REBOOT_DELAY_MINUTES" "APT weekly maintenance reboot"
fi
fi

Loading…
Cancel
Save

Powered by TurnKey Linux.