Tapping Ansible Debug to Troubleshoot Playbooks and Roles

Published:15 April 2022 - 7 min. read

Nicholas Xuan Nguyen Image

Nicholas Xuan Nguyen

Read more tutorials by Nicholas Xuan Nguyen!

Azure Cloud Labs: these FREE, on‑demand Azure Cloud Labs will get you into a real‑world environment and account, walking you through step‑by‑step how to best protect, secure, and recover Azure data.

If you are reading this tutorial, chances are you use Ansible for automation in your daily workloads. But as with all software, Ansible can occasionally have issues. Worry not, though. Command-line options and Ansible debug can help!

In this tutorial, you’ll learn to troubleshoot playbooks, resolving any potential issues as quickly as possible, so you can get back to automating.

Read on and smoothly run your playbooks without messing things up!

Prerequisites

This tutorial will be a hands-on demonstration. If you’d like to follow along, be sure you have the following.

  • An Ansible control node with Ansible installed.
  • A managed node or host that the control node can access via SSH. Here’s a guide in starting SSH with Powershell.
  • Python 3.x is installed on both the control node and the managed node (host).

Troubleshooting Using the Command-Line Options

Running into errors when executing your playbooks can be a pain. Naturally, you’d need a way to troubleshoot and debug your playbooks to avoid messing things up. Luckily, Ansible lets you troubleshoot playbooks by appending options in the ansible-playbook command.

By default, Ansible has a built-in syntax checker called --syntax-check. This syntax checker is a great way to catch mistakes in your YML files before running your playbooks.

To demonstrate how the syntax checker works:

1. Create a YAML file (playbook) in your current working directory on your control node using your preferred text editor and populate the following code. You can name the file as you like, but for this tutorial, the file is named create_user.yml.

The code below runs a task to create a user named ata on your managed node.

---
- name: Ansible Create user
  hosts: all
  become: true

  tasks: # Runs a task to create a user named 'ata'
   - name: Create ata user
     user:
        name: ata
        state: present

2. Next, open your terminal, and run the following command to test the create_user.yml playbook for syntax errors (--syntax-check).

The syntax checker parses the YAML file and looks for any potential errors without running any of your playbook tasks.

ansible-playbook --syntax-check create_user.yml

If your playbook passes the syntax check without errors, you’ll see the name of your playbook (create_user.yml) as in the following screenshot. But if there are errors in your playbook, you’ll see an error message and the line number where the error occurred explicitly (step four).

Checking Syntax Errors in Playbook
Checking Syntax Errors in Playbook

3. Open the create_user.yml file in a text editor and add a line that says “This is an error!!!” at the bottom to cause a syntax error, then save and close the file.

Adding a Random Line to Cause an Error
Adding a Random Line to Cause an Error

4. Now, rerun the below command to perform a --syntax-check on your playbook (create_user.yml).

ansible-playbook --syntax-check create_user.yml

As you can see below, the syntax checker caught the error and displayed the message Syntax Error while loading YAML, followed by the line number where the error occurred (12).

Checking Syntax of Playbook (Caught an Error)
Checking Syntax of Playbook (Caught an Error)

5. Go back to the create_user.yml file and remove the random line you added to cause an error. Save the changes you made and close the file.

6. Next, rerun the below command to perform a --syntax-check to ensure there are no more errors in your playbook (create_user.yml).

ansible-playbook --syntax-check create_user.yml
Rechecking Syntax on Playbook
Rechecking Syntax on Playbook

7. Run the below command to perform a dry run (--check) on your playbook (create_user.yml).

Performing a dry run is a great way to test your playbook for errors before running it on live systems. A dry run lets you simulate running a playbook without changing any data or taking any action on the hosts.

ansible-playbook --check create_user.yml
Performing a Dry Run on Playbook
Performing a Dry Run on Playbook

Note that not all modules support the –check flag. For example, modules that change data or the system do not support the –check flag.

Tasks using modules that support the –check flag shows the output of running the task on target hosts and any changes made if the module were executed.

8. After the dry run, execute the below command to connect to one of the hosts via ssh to verify no changes are made on the managed hosts. Replace root and 159.223.233.161 with your managed host’s actual username and IP address.

Connecting to Managed Host via SSH
Connecting to Managed Host via SSH

9. Now, run the tail command below to check if the user ata was created in the /etc/passwd file.

tail /etc/passwd

You’ll see that no ata user was created after the dry run, as shown below since the dry run only checked for errors without actually running the playbook.

Verifying No User Named ata Exists
Verifying No User Named ata Exists

10. Finally, run logout to leave the managed host.

logout
Logging out from the Managed Host
Logging out from the Managed Host

Enabling Playbook Debugger to Start When Running a Playbook

You’ve seen that troubleshooting playbooks using options in the ansible-playbook command works like a charm. But apart from those options, Ansible also has the built-in playbook debugger.

The Ansible playbook debugger is a powerful tool that allows you to step through your playbook and see the results of each task as they execute.

1. Run the below command to create a config file called ansible.cfg in your home directory (the root directory in this example). This file contains configuration options for the playbook debugger.

ansible-config init --disabled > ansible.cfg
Creating a Config File Called ansible.cfg
Creating a Config File Called ansible.cfg

2. Next, open the ansible.cfg file in a text editor and add the enable_task_debugger = True line under the defaults section, as shown below. This setting enables the playbook debugger to start automatically when you run the playbook. Save the changes and close the file.

Once the playbook debugger is enabled, any failed or unreachable task will begin the inline debugger interaction prompt.

Enabling the Playbook Debugger
Enabling the Playbook Debugger

3. Run the below command to ensure that you are using the correct config file, which should be ansible.cfg in your home directory, as shown below.

ansible -­-version
Ensuring the Correct Config File is Set
Ensuring the Correct Config File is Set

Troubleshooting with the Ansible Debug

Since you’ve set the playbook debugger to start whenever you run a playbook, you can now put the debugger keyword anywhere in a playbook. Doing so enables task debugging, such as playbooks, roles, blocks, or even individual tasks.

The debugger keyword supports five values, including the most commonly used value (on_failed) when debugging a play:

ValueResult
alwaysThe debugger will always run when specified, regardless of the outcome.
neverThe debugger will never run, regardless of the outcome.
on_failedThe debugger will only run if the task fails (for debugging task failures).
on_unreachableThe debugger will only run if the task is unreachable. Use this value when your managed host is unreachable or when a task has a timeout.
on_skippedThe debugger will only run if the task skipped itself by execution

To troubleshoot a playbook with Ansible debug:

1. Create a debugger_demo.yml playbook in your favorite editor, and populate the following code. Save the changes and close the playbook.

The code below installs a package called does_not_exist on the managed host using yum. But since the package doesn’t exist in the yum repository, the task will fail and invoke the debugger.

---
- name: Debugger demo
  hosts: all
	# Enable debugging for a task.
  debugger: on_failed # Invokes the debugger if the task fails
  vars: # Set a variable to hold the package name
    - pkg_name: does_not_exist 
  tasks:
   - name: Install a package # Installs the package the pkg_name variable holds
     yum: 
      name: "{{ pkg_name }}" 
      state: present

2. Next, run the below command to execute the playbook (debugger_demo.yml).

ansible-playbook debugger_demo.yml

The task fails since the debugger_demo.yml playbook tries to install a package that doesn’t exist, as shown below. You’ll also notice an inline debugger prompt.

Attempting to Execute the debugger_demo.yml Playbook
Attempting to Execute the debugger_demo.yml Playbook

Once you invoke the debugger, you will have access to many debugger arguments/commands that help you step through the playbook, as shown below.

CommandShortcutAction
printpPrint the value of a variable. For example, you can use it to print the value of a task’s result.
task.args[key] = valueno shortcutSets the value of a task’s argument directly in the debugger inline prompt. This argument is useful when testing the behavior of a task with different arguments.

For example, to set the value of a task’s hostname argument to “www.example.com”, use this argument like so: task.args[‘hostname’] = ‘www.example.com’.
task_vars[key] = valueno shortcutUpdates the task variables (you must use update_task next)
update_taskuRecreate a task with updated task variables.
redorRestarts the playbook from the beginning and reruns the entire play. But any new changes you made to task arguments using the task.args argument will remain in effect.

You can use this argument to correct any issues you’ve discovered quickly.
continuecContinue executing, starting with the next task.
quitqQuit the debugger.

3. Run the below command to inspect what task argument values (task.args) are used during task execution.

p task.args

In the output below, you can see the task is using the default values for the name and state arguments. These default values are defined in the vars section of the debugger_demo.yml playbook. Notice the package name (does_not_exist) with a state of present.

Inspecting Task Arguments
Inspecting Task Arguments

4. Now, run the following command to update the state argument to a package (bash) that exists in the managed host’s repository.

task.args['name']='bash'

At this point, you have a new inline value for the task.args[‘name’] argument(bash). You’re no longer using the variable defined in the vars section of the playbook.

5. Rerun the command below to inspect task argument values and verify the changes.

p task.args

Below, the bash package is now being used as the value for the task argument.

Verifying Task Argument Changes
Verifying Task Argument Changes

6. Finally, run the redo debugger argument to restart the playbook and rerun the entire play.

redo

This time, the task runs, as shown below. Notice that you get an ok status since the Bash package exists in the managed host’s repository.

Rerunning the Ansible Task
Rerunning the Ansible Task

Conclusion

Debugging playbooks can be a challenge, but Ansible provides tools to make the process easier. And in this article, you’ve learned how to use the command-line options and the Ansible debugger to help you step through your playbook and troubleshoot issues.

You also learned to get around the debugger’s arguments/commands to inspect and modify task arguments during playbook execution. At this point, you already have a fully functional Ansible environment and the knowledge required to start debugging your automation.

Why not try the Ansible debugger on some of your playbooks to Ansible debug network automation? You’ll find the Ansible debugger is an invaluable tool for troubleshooting issues and understanding the behavior of your automation.

Hate ads? Want to support the writer? Get many of our tutorials packaged as an ATA Guidebook.

Explore ATA Guidebooks

Looks like you're offline!