Introduction to Ansible wait_for module
Ansible wait_for module can be used to pause your playbook execution and to wait for many different things or conditions before continuing with the execution. The wait_for module of ansible is to make your playbook or task execution halt or pause for various reasons and for numerous conditions.
You can compare it with the sleep of any given programming language but it is more than that. Yes, it does have a conditional validation.
Take our real-life examples.
We Sleep When we are expecting our friend who is always late, We Sleep till mom kicks us out of bed, We Sleep till our spouse spill water at our face and angrily say "WAKE UP"
Besides all, there are few like me. We Sleep for no specific reason.
Ansible Wait_for module is capable to make your playbook Sleep for no specific reason ( Simply Sleep) as well as while we wait for something ( A Conditional Sleep)
Like people, Our playbooks also have different conditions to wait for and sleep and we have listed some of the most known and used conditions where ansible playbook has to go sleep or wait for.
- wait_for the port to be available or not available
- wait_for the file to be created with a state, present or absent
- wait_for some period of time, Simply sleep for a specified time (in seconds)
- wait_for the server to come up or get rebooted.
- wait_for a String to be available in the log file Like Log Parsing or Searching
- wait_for SSH to be ready at the remote servers
We are going to see all these aforementioned usage scenarios (or) test cases of ansible wait_for module with the examples (playbooks) I have written. one by one.
Ansible wait_for examples
We have given short snippets of ansible task and playbooks for each of the aforementioned scenarios.
These are examples we have covered in this post
- ansible wait_for the port to open
- ansible wait_for the port to close
- ansible wait_for the port to drain and close active connections
- ansible Wait_for file to be created
- ansible Wait_for file to be deleted or lock file to be removed
- ansible wait_for seconds or sleep for seconds
- ansible Wait_for reboot ( wait_for SSH )
- ansible Wait_for the string to be available in the log file
- ansible wait_for the process to finish
Ansible wait for the port to open
Using ansible wait_for module along with host
and port
, we can wait a maximum of timeout
seconds for the port to be available or not available.
Consider the following task snippet which waits for the port to be available. Actually, this task is validating if the server has come up and RUNNING by validating that the port is open.
The Playbook Snippet
- name: Validating if the WebServer is UP and OPENED the PORT
tags: amvalidate1
wait_for:
host: "{{inventory_hostname}}"
port: "{{webserver_port}}"
delay: 10
timeout: 30
state: started
msg: "WebServer PORT is not Listening"
when: ansible_hostname == "{{inventory_hostname}}"
register: amvalidate1
ignore_errors: true
Explanation:
host: The Hostname
port: The port to listen
delay: Delay in seconds before starting the validation
timeout: timeout after defined seconds.
state: Make sure the Port if OPEN
msg: A Custom message to be printed in case of failure after the allocated time(timeout) elapsed.
While the previous snippet was designed to run in the remote node, Here we present another way around to accomplish the same using local_action
module.
Running the same task Local ( An Another Approach)
The Playbook Snippet ( local_action)
- name: Wait for webserver to start.
local_action:
module: wait_for
host: "{{ inventory_hostname }}"
port: "{{ webserver_port }}"
delay: 10
timeout: 300
state: started
ansible wait for the port to close
If you modify the playbook given in Example 1 a little bit. you would be able to achieve the requirement of waiting till the port to close
- name: Validating if the WebServer port is closed.
tags: amvalidate1
wait_for:
host: "{{inventory_hostname}}"
port: "{{webserver_port}}"
delay: 10
timeout: 30
state: stopped
msg: "WebServer PORT is not yet stopped"
when: ansible_hostname == "{{inventory_hostname}}"
register: amvalidate1
ignore_errors: true
ansible wait_for the port to drain and close active connections
you can wait_for the port to drain its active connections (or) close its active connections using the state: drained
argument
- name: Validating if the port is drained
tags: portvalidate
wait_for:
host: "{{inventory_hostname}}"
port: "{{webserver_port}}"
delay: 10
timeout: 30
state: drained
ansible Wait_for file to be created
The following task snippet is to validate if the file is present in other it will validate if the file is created already using state: present
If you change the state argument of wait_for to state: absent
it will make sure that the file is not present (absent) in other words removed or deleted.
The Playbook Snippet
- name: Making sure that the Log file is present in the corresponding directory
tags: filepresensevalidation
register: filepresensevalidation
wait_for:
path: "{{logfile}}"
delay: 10
timeout: 30
state: present
msg: "Specified LOG FILE is not present"
when: ansible_hostname == "{{groups['app'][0]}}" and adminlogfile is defined
ignore_errors: true
Explanation:
path: The fully qualified location of the file we are validating.
delay: Delay in seconds before starting the validation
timeout: timeout after defined seconds.
state: Make sure the file is available(present)
msg: A Custom message to be printed in case of failure. which is when the file is not present.
ansible Wait_for file to be deleted or lock file to be removed
we can use wait_for module to wait for the file deletion as well. such as waiting for the lock file to be deleted before starting the instance
- name: Making sure that the lock file is not present (or) removed
wait_for:
path: "{{lockfile}}"
delay: 10
timeout: 30
state: absent
msg: "Specified LOCK FILE is still present"
ansible wait for seconds or sleep for seconds
wait_for module can also be used to simply make the execution of the play to sleep for certain seconds. in other words, simply pause the playbook execution.
This can be done with simply setting the delay
and timeout
arguments. Consider the following playbook with the task to sleep for
The Playbook Snippet
---
- name: Sleep Playbook
hosts: app
gather_facts: no
tasks:
- name: Sleep for 60 seconds and timeout
tags: sleep60
wait_for:
delay: 60
timeout: 0
Explanation:
delay: Delay in seconds before starting the validation (or) processing
timeout: timeout after defined seconds.
Here no validation is being performed like file presence or port status. The task is just to pause the execution for 60 seconds just like sleep statement in any programming language
ansible Wait_for reboot ( wait_for SSH )
There are cases where we want our remote nodes to be rebooted or restarted. For example, Take the Patching as an example. As part of quarterly patching, we upgrade the installed software and packages and do various other stuff along with a final reboot to make the changes effective.
When we reboot the box. you might get your ansible play failed with the error "Shared connection closed"
But this can be avoided and you can reboot the box and wait for the server to come back up and execute the post-reboot validations or checks.
There are many methods to accomplish this
For Ansible 2.7 and more - There is a dedicated reboot module
For previous versions - Either use ansible wait_for or ansible wait_for_connection
Since this post is about ansible wait_for module. Let us go with the same option. Consider the following playbook I have created for linux patching. It performs yum update
and reboot
the box and print the uptime
The Playbook
---
- name: Patch the server and Reboot
hosts: app
gather_facts: no
tasks:
- name: Patch the server
become: yes
become_user: root
tags: Patch
shell: "yum -y update"
register: patchresult
- name: Reboot the server
tags: reboot
become: yes
become_user: root
shell: "sleep 5 & reboot"
async: 1
poll: 0
- name: Wait for the reboot and reconnect
wait_for:
port: 22
host: '{{ (ansible_ssh_host|default(ansible_host))|default(inventory_hostname) }}'
search_regex: OpenSSH
delay: 10
timeout: 60
connection: local
- name: Check the Uptime of the servers
shell: "uptime"
register: Uptime
- debug: var=Uptime
Explanation
In the preceding playbook, we have four tasks.
The first task is running a single command "yum -y update" over the shell module, which is responsible for updating the packages and software in the boxes.
The Second task is to reboot the server. we execute the reboot command over shell module. The task contains two important arguments which are async and poll
async: By default, the tasks in playbook block the execution till it gets completed. If you mention async in the task. It will be run asynchronously, in other words, it runs detached and in the background. ansible master keeps track of this task by using the poll interval. it accepts the time in seconds it should keep the connection open before times out
poll: Time in seconds, at what interval the ansible master should poll the Job/task to know whether it is completed.
when the poll is set to 0 seconds, Ansible will fire the task and forget it. which is used specifically in here so that despite the remote servers shutdown the playbook will still be on
The Third task is wait_for. which is our primary focus so let me explain all the arguments of this task
port: we are waiting for the port 22 (SSH Default port) to be open
host: we are using the ansible built-in variables here inventory_hostname
or ansible_host
which will represent the current host from of the host group defined in the playbook (app)
search_regex: we are looking for a word OpenSSH
once the Port is open.
delay: Delay in seconds before starting the validation
timeout: timeout the execution after defined seconds.
connection: Execute the connection from local (master)
When the connection is set to local. The Master will try to connect to the remote boxes from the master. It is more like executing
nc
ortelnet
command to make sure the port is open
ansible Wait_for the string to be available in the log file
Log files are the Swiss Army Knife of every IT analyst. We rely on the logs for various things in our day to day life. Let it be for troubleshooting or for quick validation like making sure the server is UP and RUNNING.
Let us take some real-time examples, The task snippet given below is created to validate if the Weblogic AdminServer is successfully started.
Weblogic will write clear information in the log file similar to what is given below.
<Dec 28, 2018 3:23:07,661 PM IST> <Notice> <WebLogicServer> <Saravanans-MacBook-Air.local> <AdminServer> <[STANDBY] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <d5ba0f5f-250c-4991-aa59-e6d3f3cb0ec7-0000001a> <1545990787661> <[severity-value: 32] [rid: 0] [partition-id: 0] [partition-name: DOMAIN] > <BEA-000360> <The server started in RUNNING mode.>
So here our search string is
The server started in RUNNING mode
The Playbook Snippet
- name: Validating if the AdminServer state is RUNNING
tags: validatestart
wait_for:
path: "{{serverlogfile}}"
search_regex: "The server started in RUNNING mode"
delay: 10
timeout: 60
msg: "Not able to find the String RUNNING in the Logfile"
when: ansible_hostname == "{{groups['app'][0]}}" and serverlogfile is defined
register: validatestart
Explanation
path: Fully Qualified log file name including the path
search_regex: The Search String we are going look for in the log file, Also support regular expressions
delay: Start the task after a defined second of initial delay
timeout: When to stop and time out the task, in seconds
msg: Custom message in case of failure
in the when conditional statement, you can also see that we have pre-validation to make sure that the serverlogfile
variable is defined
this example can also be interpreted for ansible wait_for service to start. you can use ansible wait_for till the service is starting. Here we have taken weblogic application server. you can choose any other and apply the same example. Hope it helps.
ansible wait_for some process to finish
In Linux based Operating System, if you want to wait for the process to finish. The best approach to get that done is using the PID and the proc file.
Whenever the process is started in the Linux based os, there will be a PID assigned to it and the pid will have a reference in the /proc directory of linux. in other words, there will be a new file created in the /proc directory with the pid.
All you have to do is wait for that file to be removed. When the file is removed you can consider the process is died or finished.
let us say our process has the PID 8798 and here is the playbook snippet you could use to wait for it to get completed (or) finish.
- name: Wait until the process is finished and pid was destroyed
wait_for:
path: /proc/8798/status
state: absent
Further References: Ansible Wait_for module - Ansible documentation
Rate this article [ratings]
Thanks,
SaravAK
Follow me on Linkedin My Profile Follow DevopsJunction onFacebook orTwitter For more practical videos and tutorials. Subscribe to our channel
Signup for Exclusive "Subscriber-only" Content