--- - name: Patch Test Rocky servers and report to generic webhook hosts: prod_rocky_servers become: true gather_facts: true vars: discord_webhook_id: "1396804024942198794" discord_webhook_token: "zdT2wisqhAZuZ_UPKmAmtV0z_rX-PZnyHIXsjpPHQO3uakBO2xQ3R44kOxb9QZ4QxebL" tasks: - name: Verify target is RedHat family ansible.builtin.assert: that: - ansible_os_family == "RedHat" fail_msg: "This playbook is intended for Rocky/RHEL-family systems only." success_msg: "Target is RedHat family." - name: Ensure dnf-utils is installed for needs-restarting ansible.builtin.dnf: name: dnf-utils state: present register: dnf_utils_result - name: Update DNF metadata cache ansible.builtin.dnf: update_cache: true register: dnf_cache_result - name: Upgrade installed packages ansible.builtin.dnf: name: "*" state: latest update_only: true register: dnf_upgrade_result - name: Remove unneeded packages ansible.builtin.dnf: autoremove: true register: dnf_autoremove_result - name: Check if reboot is required ansible.builtin.command: cmd: needs-restarting -r register: reboot_required_check changed_when: false failed_when: reboot_required_check.rc not in [0, 1] - name: Set reboot required fact ansible.builtin.set_fact: reboot_required: "{{ reboot_required_check.rc == 1 }}" - name: Reboot server if required ansible.builtin.reboot: pre_reboot_delay: 60 post_reboot_delay: 60 reboot_timeout: 600 msg: "Rebooting in 60 seconds, initiated by Ansible" when: reboot_required register: reboot_result - name: Build per-host summary ansible.builtin.set_fact: patch_summary: | Host: {{ inventory_hostname }} OS: {{ ansible_distribution }} {{ ansible_distribution_version }} DNF Utils Changed: {{ 'Yes' if (dnf_utils_result.changed | default(false)) else 'No' }} DNF Cache Updated: {{ 'Yes' if (dnf_cache_result.changed | default(false)) else 'No' }} Packages Upgraded: {{ 'Yes' if (dnf_upgrade_result.changed | default(false)) else 'No' }} Autoremove Changed: {{ 'Yes' if (dnf_autoremove_result.changed | default(false)) else 'No' }} Reboot Required: {{ 'Yes' if (reboot_required | default(false)) else 'No' }} Reboot Performed: {{ 'Yes' if (reboot_result.changed | default(false)) else 'No' }} Reboot Check Output: {{ reboot_required_check.stdout | default('') | indent(10, true) }} - name: Build per-host summary ansible.builtin.set_fact: patch_summary: | Host: {{ inventory_hostname }} OS: {{ ansible_distribution }} {{ ansible_distribution_version }} DNF Utils Changed: {{ 'Yes' if (dnf_utils_result.changed | default(false)) else 'No' }} DNF Cache Updated: {{ 'Yes' if (dnf_cache_result.changed | default(false)) else 'No' }} Packages Upgraded: {{ 'Yes' if (dnf_upgrade_result.changed | default(false)) else 'No' }} Autoremove Changed: {{ 'Yes' if (dnf_autoremove_result.changed | default(false)) else 'No' }} Reboot Required: {{ 'Yes' if (reboot_required | default(false)) else 'No' }} Reboot Performed: {{ 'Yes' if (reboot_result.changed | default(false)) else 'No' }} Reboot Check Output: {{ reboot_required_check.stdout | default('') | indent(10, true) }} - name: Send Discord Rocky update report community.general.discord: webhook_id: "{{ discord_webhook_id }}" webhook_token: "{{ discord_webhook_token }}" username: "Ansible" content: | ====================================== Rocky Servers Update Report Generated: {{ lookup('pipe', 'date +%Y-%m-%dT%H:%M:%SZ') }} ====================================== Total Hosts: {{ ansible_play_hosts_all | length }} {% for host in ansible_play_hosts_all | sort %} {{ hostvars[host].patch_summary | default('Host: ' ~ host ~ '\n No summary generated\n') }} {% endfor %} ====================================== Summary ====================================== Hosts Requiring Reboot: {{ ansible_play_hosts_all | map('extract', hostvars) | selectattr('reboot_required', 'defined') | selectattr('reboot_required') | list | length }} Hosts Rebooted: {{ ansible_play_hosts_all | map('extract', hostvars) | selectattr('reboot_result.changed', 'defined') | selectattr('reboot_result.changed') | list | length }} delegate_to: localhost run_once: true become: false