5

I'm using Ansible to check hosts if they need to be rebooted if the /vmlinuz kernel doesn't resolve to uname -r.

The if condition is although always identifing a reboot even though the test machine has been rebooted and the kernel is resolving to the same kernel:

if [ $(readlink -f /vmlinuz) != /boot/vmlinuz-$(uname -r) ]; then echo 'reboot'; else echo 'no'; fi

- name: Check for reboot hint.
  shell: if [ $(readlink -f /vmlinuz) != /boot/vmlinuz-$(uname -r) ]; then echo 'reboot'; else echo 'no'; fi
  ignore_errors: true
  register: reboot_hint

- name: Rebooting ...
  command: shutdown -r now "Ansible kernel update applied"
  async: 0
  poll: 0
  ignore_errors: true
  when: kernelup|changed or reboot_hint.stdout.find("reboot") != -1
  register: rebooting

- name: Wait for thing to reboot...
  pause: seconds=45
  when: rebooting|changed
7
  • What is kernelup? Feb 27, 2015 at 13:20
  • I'm not using kernelup|changed in my yaml file. I assume it has to do with the wait for thing to reboot...
    – nicoX
    Feb 27, 2015 at 13:31
  • Could you then show exactly what is in your yaml file? Feb 27, 2015 at 13:31
  • 4
    You're assuming that a symlink /vmlinuz exists and points to the latest kernel. This is not a reasonable assumption, as on most distributions there is no such thing, and even on the oddball distributions which do have it, it may or may not even be present or kept up to date. Feb 27, 2015 at 13:35
  • 1
    @nicoX You are asking for help because your code does not work, however what you have pasted is not your code. We can't help if you don't show us the code that is failing. Feb 27, 2015 at 14:15

5 Answers 5

5

You could reliably determine the latest installed kernel version via the following rpm query:

rpm -q kernel --queryformat '%{installtime} %{version}-%{release}.%{arch}\n' | sort -n -k1 | tail -1 | cut -d ' ' -f 2

Sample output on RHEL 7:

3.10.0-229.11.1.el7.x86_64

Now just check whether the output of uname -r matches:

3.10.0-229.1.2.el7.x86_64

In this example, it does not match and a reboot is required.

You could use test to compare the strings:

if [ "`rpm -q kernel --queryformat '%{installtime} %{version}-%{release}.%{arch}\n' | sort -n -k1 | tail -1 | cut -d ' ' -f 2`" = "`uname -r`" ]; then echo "latest kernel already booted."; else echo "new kernel. reboot required."; fi
5

Answer for 2021

As @kawing-chiu mentioned in their answer, dnf now has a needs-restarting module which does just what the question requires. It determines if system packages have been updated since last boot, although that is not limited to only kernel changes. This behavior is arguably better than simply comparing kernel version with installed packages.

The needs-restarting dnf module is not accessible through the ansible.builtin.dnf Ansible module, but it can be called through ansible.builtin.shell or ansible.builtin.command by its alias needs-restarting -r, more directly with dnf needs-restarting -r, or even more explicitly with /usr/bin/dnf needs-restarting -r.

The -r flag does not seem to require root privileges and simply reports if a reboot is necessary. The return code is 0 if no reboot is necessary and 1 if it is. Therefore, we should be able to use a task such as this one, which is adapted from the one suggested by Joël Cattin:

- name: Check if a reboot is required
  ansible.builtin.command: needs-restarting -r
  register: reg_reboot_required
  ignore_errors: yes
  failed_when: false
  changed_when: reg_reboot_required.rc != 0
  notify:
    - Reboot server 

You will also need a handler named, or listening to, Reboot server to carry out the reboot task. Something like this will do the trick:

- name : Reboot server
  ansible.builtin.reboot:
    msg: "Reboot initiated by Ansible after OS update"
    reboot_timeout: 3600
    test_command: uptime

I hope this answer helps anyone who comes along seeking a solution to this problem.

1

OLD thread - but this helped me put together this quick ansible script which might help someone.

---
- hosts: allhosts
  gather_facts: False
  tasks:
    - name: check latest kernel installed
      shell: rpm -q kernel --queryformat '%{installtime} %{version}-%{release}.%{arch}\n' | sort -n -k1 | tail -1 | cut -d ' ' -f 2
      register: kernel_installed_latest
    - name: Check running kernel version
      shell: uname -r
      register: kernel_version
    - fail:
        msg: "latest kernel version {{kernel_installed_latest.stdout}} doesnt match running kernel {{kernel_version.stdout}}"
      when: (kernel_installed_latest.stdout != kernel_version.stdout)
1

Nowadays dnf has a "needs-restarting plugin" that helps to determine whether a restart is needed. For example:

[root@fedora ~]# dnf needs-restarting -r
Core libraries or services have been updated since boot-up:
  * glibc
  * kernel
  * linux-firmware
  * systemd

Reboot is required to fully utilize these updates.
More information: https://access.redhat.com/solutions/27943
[root@fedora ~]# echo $?
1
0

Another alternative is to do kernel updates separately and trigger a handler to restart the system if the kernel update was required.

  tasks
  - name: Upgrade all packages, excluding kernel
    ansible.builtin.yum:
      name: '*'
      state: latest
      exclude: kernel*
  - name: Upgrade kernel
    ansible.builtin.yum:
      name: 'kernel*'
      state: latest
    notify: restart host
  handlers:
    - name: restart host
      ansible.builtin.reboot:

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .