- Tue 03 March 2015
- Linux
- James Oguya
- #linux, #ansible
Of late, I've seen a lot of guys on #ansible irc channel & google groups asking questions about rebooting servers/nodes & temporarily pausing the playbook for a given amount of time before continuing with the execution of the playbook. In some cases, you'd want to set some kernel parameters which take effect at boot time or perform major upgrades which might require a reboot before configuring the server/node.
Using ansible's wait_for module[1], we can temporarily stop running the playbook while we wait for the server to finish rebooting or for a service to start & bind to a port. We can also use the same module to wait for a port to become available which can be useful in situations where services are not immediately available after their init scripts finish running - as is the case with Java application server e.g. Tomcat.
Gettin' Started
Basically, we can break our problem into 4 sections for easier conceptualization:
-
Section 1: Pre-reboot: Run your pre-reboot task, it can be performing major upgrades and/or performing some configuration which only take effect at boot time. For example - upgrade all packages using
yummodule[2]- name: upgrade all packages yum: name=* state=latest -
Section 2: Reboot: In this stage we'll use the
commandmodule[3] to reboot the remote machine/server by running therebootcommand - nothing fancy - you can also useshutdown --reboot.- name: reboot server command: /sbin/reboot -
Section 3: Pause the playbook: We'll use the
wait_formodule to wait for 300 seconds for port 22 to become available before resuming the playbook. I'm using port 22 because most servers run openssh-server on port 22 & if we were to telnet to that port we'd probably see something like :SSH-2.0-OpenSSH_6.6.1, so we can use regex to check whether the output matches "OpenSSH". I'm also using atimeoutvalue of 300 seconds because most physical servers take 3 - 5 minutes to finish rebooting due to hardware checks e.t.c. but you can use any value that suites you. For example: - wait for 300 seconds for port 22 to become available & containOpenSSH- name: wait for the server to finish rebooting local_action: wait_for host="web01" search_regex=OpenSSH port=22 timeout=300 -
Section 4: Resume the playbook: After we've got a response from port 22, we can resume running the playbook. This step can be optional depending on your needs.
Puttin' It All Together
- We can merge all the above sections into one playbook as shown below:
- hosts: all sudo: yes tasks: - name: Upgrade all packages in RedHat-based machines when: ansible_os_family == "Redhat" yum: name=* state=latest - name: Upgrade all packages in Debian-based machines when: ansible_os_family == "Debian" apt: upgrade=dist update_cache=yes - name: Reboot server command: /sbin/reboot - name: Wait for the server to finish rebooting sudo: no local_action: wait_for host="{{ inventory_hostname }}" search_regex=OpenSSH port=22 timeout=300
Stuff to Note
- I know you might be wondering why we didn't use handlers. Well,
notifytasks[4] are only executed at the end of the playbook regardless of their location in the playbook - remember we're interested in rebooting the server & waiting for a given amount of time for the server to finish rebooting. inventory_hostnamevariable[5] is the name of the remote server as stated in the ansible hosts filelocal_actiondirective[6] runs the given step on the local machine, for example, it would run thewait_fortask on your local machine.yummodule only works on RedHat based OS e.g. Fedora, CentOS & RHEL - and so we'll also use theaptmodule for Debian based OS e.g. Ubuntu, Debian e.t.c.