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