Update, Upgrade, and Reboot

Now that we know how to install packages, let’s talk about something very important. If your machine is in any way connected to the Internet, you should keep the majority of your packages up to date. The reasoning behind this is security, and lots of packages get updated daily to fix important exploits and bugs.
Unless you have a good reason, upgrade your machine’s packages on a regular basis.

Upgrading Packages

Let’s look at how to do upgrade packages with Ansible using the following code in the vagrant.yml playbook:

(If you have contents already in this file, you can keep them there and just copy/paste the two new tasks).

---

- name: Upgrade and Reboot
  hosts: all
  tasks:

    - name: Update System Package Cache
      apt: update_cache=yes
      sudo: yes

    - name: Upgrade System Packages
      apt: upgrade=full
      sudo: yes

# [...CLIPPED...]

First, we use the “apt” module again to talk to the Apt package manager on Ubuntu. We need to update our package cache list first, in order to know what updates are available. Then, we run the second command which tells the “apt” module to upgrade all the packages that have updates available. (Note the distinction between the terms “update” and “upgrade”).

Run this yourself using the familiar “vagrant provision” command.

Rebooting the Machine

Now and then, a package will require a reboot of the entire machine. This is typical for kernel upgrades to take effect.

Traditionally there is a sense of pride in how long a machine is kept running, referred to as “uptime”, and reboots reset this metric. In the era of the cloud, I personally think uptime is less relevant as machines come and go frequently and are seen as expendable. It’s exactly like being a farmer. You have named pets that you build a life-long relationship with, but you also have livestock where each is little more than a number.

To reboot the machine, it’s a bit more involved because we will lose our SSH connection during the reboot.

# [...CLIPPED...]

  - name: Rebooting if needed...
    command: shutdown -r now removes=/var/run/reboot-required
    sudo: yes
    async: 0
    poll: 0
    ignore_errors: true
    register: restarted

  - name: Waiting for reboot...
    local_action: wait_for host=localhost port=2200 delay=15 state=started
    sudo: no
    when: restarted.changed

A search for a little-known file flag created by Apt /var/run/reboot-required, lets us know if we need to reboot.
We use the parameter keyword “removes” to indicate the state we want. If the file is there, rebooting will remove it, otherwise do nothing if the file flag isn’t there.
This is idempotency again, and I keep bringing it up because it’s a very important part of Ansible strategy.
Ignoring the rest of the options for now, we also have “register” which saves some information from the task into a variable-like item that we can use in other tasks.

In the following task, we wait on our local machine (with “local_action”) for the reboot to complete.
But this only runs when a reboot actually happened.
Using the “when” statement, we check to see if the “restart” variable we registered was changed.
The “when” statements act similarly to “if” statements, so the whole task will only be run “when” restarted.changed is true

If you ever want to get an idea for what variables contain, just use the “debug” module like so:

- name: Show a registered variable's contents
  debug: var=restarted

Run the playbook again to see the reboot task is marked as “ok” and the waiting for reboot task is “skipped” this time around (it was “changed” and “ok” before).

Here’s the final vagrant.yml playbook file:

---

- name: Upgrade and Reboot
  hosts: all
  tasks:

    - name: Update System Package Cache
      apt: update_cache=yes
      sudo: yes

    - name: Upgrade System Packages
      apt: upgrade=full
      sudo: yes

    - name: Rebooting if needed...
      command: shutdown -r now removes=/var/run/reboot-required
      sudo: yes
      async: 0
      poll: 0
      ignore_errors: true
      register: restarted

    - name: Waiting for reboot...
      local_action: wait_for host=localhost port=2200 delay=15 state=started
      sudo: no
      when: restarted.changed