154 lines
5.0 KiB
YAML
154 lines
5.0 KiB
YAML
---
|
|
- name: Gather package facts before patching
|
|
ansible.builtin.package_facts:
|
|
manager: auto
|
|
|
|
- name: Store pre-patch package versions
|
|
ansible.builtin.set_fact:
|
|
packages_pre_patch: "{{ ansible_facts.packages }}"
|
|
|
|
- name: Check for available updates (Debian/Ubuntu)
|
|
ansible.builtin.apt:
|
|
update_cache: true
|
|
cache_valid_time: 3600
|
|
when: ansible_os_family == "Debian"
|
|
changed_when: false
|
|
|
|
- name: Get list of upgradable packages (Debian/Ubuntu)
|
|
ansible.builtin.shell: |
|
|
apt list --upgradable 2>/dev/null | grep -v "Listing..." | awk -F'/' '{print $1}'
|
|
register: upgradable_packages
|
|
changed_when: false
|
|
when: ansible_os_family == "Debian"
|
|
|
|
- name: Get list of upgradable packages (RHEL/CentOS)
|
|
ansible.builtin.shell: |
|
|
dnf check-update --quiet | awk '{print $1}' | grep -v "^$"
|
|
register: upgradable_packages
|
|
changed_when: false
|
|
failed_when: upgradable_packages.rc not in [0, 100]
|
|
when: ansible_os_family == "RedHat"
|
|
|
|
- name: Get list of upgradable packages (Alpine)
|
|
ansible.builtin.shell: |
|
|
apk list --upgradable 2>/dev/null | awk -F'-[0-9]' '{print $1}'
|
|
register: upgradable_packages
|
|
changed_when: false
|
|
when: ansible_os_family == "Alpine"
|
|
|
|
- name: Normalize upgradable packages list
|
|
ansible.builtin.set_fact:
|
|
upgradable_packages_list: "{{ upgradable_packages.stdout_lines | default([]) }}"
|
|
when: upgradable_packages is defined and upgradable_packages.stdout_lines is defined
|
|
|
|
- name: Normalize upgradable packages list (skipped/undefined fallback)
|
|
ansible.builtin.set_fact:
|
|
upgradable_packages_list: []
|
|
when: upgradable_packages is not defined or upgradable_packages.stdout_lines is not defined
|
|
|
|
- name: Log packages to be updated
|
|
ansible.builtin.debug:
|
|
msg: "Packages to be updated on {{ inventory_hostname }}: {{ upgradable_packages_list | length }} packages"
|
|
|
|
- name: Perform full upgrade (Debian/Ubuntu)
|
|
ansible.builtin.apt:
|
|
upgrade: dist
|
|
autoremove: true
|
|
autoclean: true
|
|
register: apt_upgrade_result
|
|
when:
|
|
- ansible_os_family == "Debian"
|
|
- patch_mode == "full" or patch_mode == "security"
|
|
|
|
- name: Perform security-only upgrade (RHEL/CentOS)
|
|
ansible.builtin.dnf:
|
|
name: "*"
|
|
state: latest
|
|
security: "{{ patch_mode == 'security' }}"
|
|
update_cache: true
|
|
register: dnf_upgrade_result
|
|
when: ansible_os_family == "RedHat"
|
|
|
|
- name: Perform upgrade (Alpine)
|
|
ansible.builtin.shell: |
|
|
apk update && apk upgrade
|
|
register: apk_upgrade_result
|
|
changed_when: "'OK' in apk_upgrade_result.stdout"
|
|
when: ansible_os_family == "Alpine"
|
|
|
|
- name: Gather package facts after patching
|
|
ansible.builtin.package_facts:
|
|
manager: auto
|
|
|
|
- name: Store post-patch package versions
|
|
ansible.builtin.set_fact:
|
|
packages_post_patch: "{{ ansible_facts.packages }}"
|
|
|
|
- name: Build packages updated list
|
|
ansible.builtin.set_fact:
|
|
packages_updated: >-
|
|
{%- set updated = [] -%}
|
|
{%- for pkg, details in packages_post_patch.items() -%}
|
|
{%- if pkg in packages_pre_patch -%}
|
|
{%- if details[0].version != packages_pre_patch[pkg][0].version -%}
|
|
{%- set _ = updated.append({
|
|
'name': pkg,
|
|
'version_before': packages_pre_patch[pkg][0].version,
|
|
'version_after': details[0].version,
|
|
'type': 'updated'
|
|
}) -%}
|
|
{%- endif -%}
|
|
{%- else -%}
|
|
{%- set _ = updated.append({
|
|
'name': pkg,
|
|
'version_before': 'not installed',
|
|
'version_after': details[0].version,
|
|
'type': 'new'
|
|
}) -%}
|
|
{%- endif -%}
|
|
{%- endfor -%}
|
|
{{ updated }}
|
|
|
|
- name: Log updated packages
|
|
ansible.builtin.debug:
|
|
msg: "Updated: {{ item.name }} {{ item.version_before }} -> {{ item.version_after }}"
|
|
loop: "{{ packages_updated }}"
|
|
|
|
- name: Check if reboot is required after patching (Debian/Ubuntu)
|
|
ansible.builtin.stat:
|
|
path: /var/run/reboot-required
|
|
register: reboot_required_post
|
|
when: ansible_os_family == "Debian"
|
|
|
|
- name: Update reboot required fact
|
|
ansible.builtin.set_fact:
|
|
host_reboot_required: "{{ reboot_required_post.stat.exists | default(false) }}"
|
|
when: ansible_os_family == "Debian"
|
|
|
|
- name: Check if reboot is required after patching (Alpine)
|
|
ansible.builtin.shell: |
|
|
apk version -l = 2>/dev/null | grep -q kernel && echo "yes" || echo "no"
|
|
register: alpine_reboot_check
|
|
changed_when: false
|
|
when: ansible_os_family == "Alpine"
|
|
|
|
- name: Update reboot required fact (Alpine)
|
|
ansible.builtin.set_fact:
|
|
host_reboot_required: "{{ alpine_reboot_check.stdout | trim == 'yes' }}"
|
|
when: ansible_os_family == "Alpine"
|
|
|
|
- name: Reboot if required and auto_reboot is enabled
|
|
ansible.builtin.reboot:
|
|
reboot_timeout: 300
|
|
pre_reboot_delay: 10
|
|
post_reboot_delay: 30
|
|
msg: "Rebooting after patch run — initiated by Ansible"
|
|
when:
|
|
- host_reboot_required | bool
|
|
- auto_reboot | bool
|
|
|
|
- name: Patching complete
|
|
ansible.builtin.debug:
|
|
msg: "Patching complete on {{ inventory_hostname }} — {{ packages_updated | length }} packages updated"
|
|
|