Ansible Dry Run: Running Playbook in Check Mode
Not sure of things with your playbook? Here's how you can test your Ansible playbook by using the dry run feature.
Ansible's dry run, also known as check mode, is a powerful tool that lets you simulate playbook execution without making any actual changes to your systems. This is incredibly useful for testing and debugging playbooks before unleashing them on your production environment.
Imagine you have a complex Ansible playbook that updates configurations across multiple servers. Before hitting that "run" button, you'd ideally want to test it to ensure everything works as planned.
A dry run allows you to do exactly that. It walks through your playbook, checks for errors, and displays what changes would be made on the target hosts, all without actually applying them.
Let's dive into how to perform a dry run in under 5 minutes, with examples ranging from super simple to a more practical scenario.
Prerequisites
To proceed with this tutorial, you will need the following:
- An Ansible management node with Ansible installed and configured.
- SSH key-based authentication between the management node and target nodes.
How to dry run
There are two main ways to perform a dry run with Ansible:
1. Command Line Flag
This is the quickest way. Run your playbook with the --check
flag like this:
ansible-playbook my_playbook.yml --check
2. Playbook Option
You can also define the check_mode: True
option within your playbook itself:
- hosts: all
become: true
tasks:
- name: Update package lists
apt: update_cache=yes
check_mode: True
Example 1: Super simple dry run
Let's say you have a simple task that updates the /etc/hostname
file on your target machine. Here's the playbook:
- hosts: all
become: true
tasks:
- name: Update system hostname
lineinfile:
path: /etc/hostname
create: yes
line: "newlinuxhost"
Now, run the playbook with the --check
flag:
ansible-playbook update_hostname.yml --check
This confirms that the playbook would add the line newlinuxhost
to the /etc/hostname
file, but since it's a dry run, no changes are actually made.
Example 2: Practical dry run with package installation
Now, let's look at a more practical scenario. Imagine you have a playbook that installs the apache2 web server package on your web servers:
- hosts: webservers
become: true
tasks:
- name: Install Apache web server
apt:
name: apache2
state: present
check_mode: True
Before unleashing this on your production servers, it's wise to do a dry run:
ansible-playbook install_apache.yml
The output will show you details about which packages would be installed and their versions. This allows you to verify if the playbook targets the correct packages and avoids any surprises during actual execution.
Example 3: Conditional task execution with check mode
Imagine a playbook that updates a system based on specific conditions. Here's an example:
- hosts: web1
become: true
tasks:
- name: Check if Python 3 is installed
command: python3 --version
register: python3_check
- name: Install Python 3 if not found (would only run in actual execution)
apt:
name: python3
state: present
when: python3_check.rc != 0 # Only run if Python 3 is not found
- name: Update system message for Python 3 users (dry run will show intended message)
lineinfile:
path: /etc/motd
line: "Welcome! Python 3 is now available."
when: python3_check.rc == 0 # Only run if Python 3 is found
Now, let's do a dry run:
ansible-playbook install_python3.yml --check
Running this with --check
won't actually install Python 3, but it will show the intended line that would be added to the /etc/motd
file if Python 3 is detected. This helps verify the conditional logic works as expected.
Example 4: Testing Jinja2 templating with check mode
Ansible uses Jinja2 templating for dynamic content. Dry runs can help test how variables are used within templates. Here's an example:
- hosts: webservers
become: true
tasks:
- name: Configure Apache with server name
template:
src: apache.conf.j2
dest: /etc/apache2/sites-available/{{ server_name }}.conf
owner: www-data
group: www-data
vars:
server_name: "mysite.com"
Now, try to run the above playbook with dry run:
ansible-playbook configure_apache.yml --check
Example 5: Testing with loops and conditionals
Ansible allows looping through lists and running tasks conditionally. Dry runs can help validate these constructs before actual execution. Here's an example:
---
- hosts: all
become: true
tasks:
- name: Loop through list of packages to install
apt:
name: "{{ item }}"
state: present
loop:
- nginx
- php
- php-fpm
- mariadb-server
when: ansible_os_family == "Debian" # Run only on Debian-based systems
- name: Loop through list of systemd services to enable (dry run shows intended service states)
systemd:
name: "{{ item }}"
state: enabled
loop:
- apache2.service
- php8.1-fpm.service
when: ansible_os_family == "Ubuntu" # Run only on Ubuntu systems
Now, run the above playbook using dry run:
ansible-playbook loop.yml --check
This playbook loops through package lists and systemd services based on the operating system. A dry run will iterate through the loops and show the intended actions for each item, even though no actual installation or enabling occurs.
Conclusion
Ansible's dry run functionality is a valuable asset for any Ansible user. By incorporating dry runs into your workflow, you can ensure your playbooks are error-free and make well-informed decisions before applying changes to your systems. So, next time you write a playbook, remember to take it for a spin in check mode first!
If you are new to Ansible and want to learn it from scratch, our Ansible tutorial series will be of great help. It's written for RHCE exam but it helps you the same whether you are preparing for the exam or not.
LHB Community is made of readers like you who share their expertise by writing helpful tutorials. Contact us if you would like to contribute.