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
nicoX
  • 611
  • 9
  • 18
  • What is `kernelup`? – Antonis Christofides Feb 27 '15 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 '15 at 13:31
  • Could you then show exactly what is in your yaml file? – Antonis Christofides Feb 27 '15 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. – Michael Hampton Feb 27 '15 at 13:35
  • Is there a different command you can use instead of `readlink` to do the check? If it can be kept simple. – nicoX Feb 27 '15 at 14:05
  • 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. – Antonis Christofides Feb 27 '15 at 14:15
  • @AntonisChristofides I didn't realise or check the symlink status. As I see now, that they are not symlinked, it wouldn't matter, and I have to rewrite it differently. – nicoX Feb 27 '15 at 14:18

5 Answers5

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
Reiner Rottmann
  • 623
  • 1
  • 7
  • 19
4

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.

FlippingBinary
  • 260
  • 2
  • 7
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
kawing-chiu
  • 111
  • 2
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:
Jeter-work
  • 825
  • 4
  • 15