Files
ansible/playbooks/reboot_check.yml
T
Harwinder Sekhon 006103760f Fix playbook bugs from review, add Telegram alerts to health and service checks
Review fixes:
- Availability plays: "ping_result is succeeded" is true for unreachable
  hosts, so offline hosts were added to reachable_hosts and failed the
  next play. Test reachability explicitly (7 playbooks).
- bootstrap_lxc: vim-enhanced and mtr-tiny package names, enable CRB next
  to EPEL, add the root key without replacing authorized_keys, validate
  sshd_config edits and restart sshd only on change.
- backup_docker: the command module does not expand $(...); fix rsync
  filter order and add --exclude=*; restart only the containers that were
  stopped, even when rsync fails; read the storage address from the
  inventory; keep semaphore and semaphore-db running.
- new_lxc: community.general.proxmox no longer exists, use
  community.proxmox; node is mini-pc; valid hostname; password or token
  auth; let the module pick the VMID; longer timeout.
- proxmox-backup: surface the vzdump exit code, let vzdump prune with
  keep-last, drop the rename/prune steps that globbed *.zstd.
- time-region: chrony regex no longer comments out its own server line;
  /etc/localtime as a symlink; reuse facts across plays.
- update_pihole_blocklists: FQCN, become: true, changed_when.
- ansible.cfg gathering = smart; update_system only pings ubuntu/rocky.

Telegram alerts:
- health_check: filesystems above disk_warn_pct (default 80), excluding
  efivarfs, and offline hosts.
- service_check: services not running.
- One message per run from localhost, credentials from Semaphore
  (TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID), no_log on the send task,
  prints the alert text when Telegram is not configured.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEizHawueRXUcxQELRZ8kq
2026-09-06 23:06:18 -04:00

147 lines
5.0 KiB
YAML

---
# Reports which Ubuntu/Rocky guests need a reboot and, only when asked,
# reboots them. LXC containers restart via Proxmox when they reboot themselves.
#
# Extra vars (optional):
# do_reboot - default false (report only)
# reboot_exclude - hosts never rebooted by this playbook (default: [docker],
# which most likely runs Semaphore itself)
- name: Check Host Availability
hosts: ubuntu:rocky
gather_facts: false
ignore_unreachable: true
tasks:
- name: Ping hosts to check availability
ansible.builtin.ping:
register: ping_result
ignore_errors: true
ignore_unreachable: true
- name: Add reachable hosts to group
ansible.builtin.group_by:
key: reachable_hosts
when: ping_result is reachable and ping_result is succeeded
- name: Report offline hosts
ansible.builtin.debug:
msg: "{{ inventory_hostname }} - OFFLINE"
when: ping_result is unreachable or ping_result is failed
delegate_to: localhost
- name: Reboot Check - Ubuntu
hosts: ubuntu:&reachable_hosts
become: true
gather_facts: true
tasks:
- name: Check for the reboot-required flag
ansible.builtin.stat:
path: /var/run/reboot-required
register: reboot_flag
- name: Read the packages that requested a reboot
ansible.builtin.slurp:
src: /var/run/reboot-required.pkgs
register: reboot_pkgs
when: reboot_flag.stat.exists
failed_when: false
- name: Record reboot status
ansible.builtin.set_fact:
reboot_needed: "{{ reboot_flag.stat.exists }}"
reboot_reason: "{{ (reboot_pkgs.content | default('') | b64decode | trim | replace('\n', ', ')) if reboot_flag.stat.exists else '' }}"
- name: Reboot Check - Rocky Linux
hosts: rocky:&reachable_hosts
become: true
gather_facts: true
tasks:
- name: Ensure needs-restarting is available
ansible.builtin.dnf:
name: yum-utils
state: present
# needs-restarting -r compares package install times against the kernel boot
# time, which inside an LXC container is the host's boot time, so the flag
# would never clear. Containers use the process-based check instead.
- name: Check whether a reboot is required (VM)
ansible.builtin.command: needs-restarting -r
register: needs_reboot
failed_when: needs_reboot.rc not in [0, 1]
changed_when: false
when: ansible_virtualization_type != "lxc"
- name: Check for processes using updated libraries (LXC)
ansible.builtin.command: needs-restarting
register: stale_procs
failed_when: stale_procs.rc not in [0, 1]
changed_when: false
when: ansible_virtualization_type == "lxc"
- name: Record reboot status
ansible.builtin.set_fact:
reboot_needed: >-
{{ (needs_reboot.rc == 1) if ansible_virtualization_type != 'lxc'
else ((stale_procs.stdout | trim | length) > 0) }}
reboot_reason: >-
{{ (needs_reboot.stdout | default('') | trim | replace('\n', '; ')) if ansible_virtualization_type != 'lxc'
else ((stale_procs.stdout_lines | default([]) | length | string) ~ ' process(es) using updated libraries') }}
- name: Reboot Check - Report
hosts: reachable_hosts
gather_facts: false
tasks:
- name: Print reboot status
ansible.builtin.debug:
msg: >-
{{ inventory_hostname }} ({{ ansible_virtualization_type | default('unknown') }}) -
REBOOT NEEDED: {{ 'YES' if reboot_needed | default(false) | bool else 'no' }}
{{ ('- ' ~ reboot_reason) if (reboot_needed | default(false) | bool and reboot_reason | default('') | length > 0) else '' }}
- name: Reboot Check - Reboot hosts that need it
hosts: reachable_hosts
become: true
gather_facts: false
vars:
do_reboot: false
reboot_exclude:
- docker
tasks:
- name: Report hosts skipped because they are excluded
ansible.builtin.debug:
msg: "SKIPPED: {{ inventory_hostname }} needs a reboot but is listed in reboot_exclude"
when:
- do_reboot | bool
- reboot_needed | default(false) | bool
- inventory_hostname in reboot_exclude
# Inside a container the default boot_id belongs to the host and never
# changes, so the reboot module would wait forever. PID 1's start time does
# change when the container restarts.
- name: Reboot LXC container
ansible.builtin.reboot:
boot_time_command: "awk '{print $22}' /proc/1/stat"
reboot_timeout: 300
msg: "Reboot initiated by Ansible (reboot_check.yml)"
when:
- do_reboot | bool
- reboot_needed | default(false) | bool
- inventory_hostname not in reboot_exclude
- ansible_virtualization_type == "lxc"
- name: Reboot VM
ansible.builtin.reboot:
reboot_timeout: 300
msg: "Reboot initiated by Ansible (reboot_check.yml)"
when:
- do_reboot | bool
- reboot_needed | default(false) | bool
- inventory_hostname not in reboot_exclude
- ansible_virtualization_type != "lxc"