Files
ansible/playbooks/auto_updates.yml
T
Harwinder Sekhon 5aaa7020ac 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.

Claude-Session: https://claude.ai/code/session_01XEizHawueRXUcxQELRZ8kq
2026-09-06 23:06:18 -04:00

145 lines
4.7 KiB
YAML

---
# Enables automatic security updates: unattended-upgrades on Ubuntu and
# dnf-automatic on Rocky Linux. Neither reboots automatically; use
# reboot_check.yml for that.
- 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: Auto Updates - Ubuntu
hosts: ubuntu:&reachable_hosts
become: true
gather_facts: false
tasks:
- name: Install unattended-upgrades
ansible.builtin.apt:
name: unattended-upgrades
state: present
update_cache: true
cache_valid_time: 3600
- name: Enable periodic package list refresh and upgrades
ansible.builtin.copy:
dest: /etc/apt/apt.conf.d/20auto-upgrades
content: |
// Managed by Ansible (playbooks/auto_updates.yml)
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "7";
owner: root
group: root
mode: '0644'
- name: Configure unattended-upgrades behaviour
ansible.builtin.copy:
dest: /etc/apt/apt.conf.d/52unattended-upgrades-local
content: |
// Managed by Ansible (playbooks/auto_updates.yml)
// Allowed origins (security / ESM) come from the stock 50unattended-upgrades.
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "false";
owner: root
group: root
mode: '0644'
- name: Enable apt timers
ansible.builtin.systemd:
name: "{{ item }}"
enabled: true
state: started
loop:
- apt-daily.timer
- apt-daily-upgrade.timer
- name: Dry-run unattended-upgrade
ansible.builtin.command: unattended-upgrade --dry-run -v
register: uu_dry_run
changed_when: false
failed_when: false
- name: List apt timers # noqa: command-instead-of-module (read-only listing)
ansible.builtin.command: systemctl list-timers apt-daily* --no-pager --all
register: apt_timers
changed_when: false
- name: Print report
ansible.builtin.debug:
msg: |
======================================================
HOST: {{ inventory_hostname }} ({{ ansible_host }})
======================================================
TIMERS:
{{ apt_timers.stdout }}
------------------------------------------------------
DRY RUN (last lines):
{{ (uu_dry_run.stdout_lines + uu_dry_run.stderr_lines)[-6:] | join('\n') }}
======================================================
- name: Auto Updates - Rocky Linux
hosts: rocky:&reachable_hosts
become: true
gather_facts: false
tasks:
- name: Install dnf-automatic
ansible.builtin.dnf:
name: dnf-automatic
state: present
- name: Configure dnf-automatic for security updates
community.general.ini_file:
path: /etc/dnf/automatic.conf
section: "{{ item.section }}"
option: "{{ item.option }}"
value: "{{ item.value }}"
mode: '0644'
loop:
- { section: commands, option: upgrade_type, value: security }
- { section: commands, option: download_updates, value: "yes" }
- { section: commands, option: apply_updates, value: "yes" }
- { section: emitters, option: emit_via, value: stdio }
loop_control:
label: "{{ item.section }}/{{ item.option }} = {{ item.value }}"
- name: Enable dnf-automatic timer
ansible.builtin.systemd:
name: dnf-automatic.timer
enabled: true
state: started
- name: List dnf-automatic timers # noqa: command-instead-of-module (read-only listing)
ansible.builtin.command: systemctl list-timers dnf-automatic* --no-pager --all
register: dnf_timers
changed_when: false
- name: Print report
ansible.builtin.debug:
msg: |
======================================================
HOST: {{ inventory_hostname }} ({{ ansible_host }})
======================================================
TIMERS:
{{ dnf_timers.stdout }}
======================================================