--- # 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 succeeded - name: Report offline hosts ansible.builtin.debug: msg: "{{ inventory_hostname }} - OFFLINE" when: ping_result is not succeeded 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 }} ======================================================