Baeldung Pro – Ops – NPI EA (cat = Baeldung on Ops)
announcement - icon

Learn through the super-clean Baeldung Pro experience:

>> Membership and Baeldung Pro.

No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.

Partner – Orkes – NPI EA (cat=Kubernetes)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

1. Overview

Ansible is a powerful configuration management tool designed to streamline server configuration, particularly through its playbook feature. Within a playbook, we define multiple tasks that execute specific commands on the target servers. However, by default, Ansible doesn’t display the output of these commands, which makes it challenging to monitor or troubleshoot the execution process.

In this tutorial, we’ll explore several methods to display the output of commands executed on a remote server using an Ansible playbook.

2. Using Verbose Mode

Perhaps the easiest way to display command output from a playbook is by using the -v option, which activates verbose mode. Once enabled, this mode ensures that all commands in the playbook print their output directly to the terminal in JSON format.

To demonstrate, let’s create a simple playbook named check_resources.yml that monitors the server’s memory usage. Additionally, when using this playbook template, let’s ensure to update the hosts value with the appropriate hostnames:

$ cat check_resources.yml
---
- name: Checking System Resources
  hosts: web-servers
  tasks:
    - name: Check Memory Usage
      command: free

With the playbook file prepared, let’s execute it using the -v flag for verbose output:

$ ansible-playbook check_resources.yml -v

The command’s output appears on the terminal screen:

...
TASK [Check Memory Usage] *****************************************************************************
changed: [172.31.4.218] => {"changed": true, "cmd": ["free"], "delta": "0:00:00.004289", "end": "2024-09-20 08:49:26.995004", "msg": "", "rc": 0, "start": "2024-09-20 08:49:26.990715", "stderr": "", "stderr_lines": [], "stdout": "               total        used        free      shared  buff/cache   available\nMem:          980416      367084      219444         916      568032      613332\nSwap:              0           0           0", "stdout_lines": ["               total        used        free      shared  buff/cache   available", "Mem:          980416      367084      219444         916      568032      613332", "Swap:              0           0           0"]}
...

When using this method, the terminal screen displays the command output. However, one challenge arises as we can see the output for every command listed in the assigned playbook by default.

Therefore, if the playbook is complex and includes many commands, printing the output for each one might not always be needed or desired. Instead, we can use the register and debug modules to selectively print the output of specific commands in the playbook.

3. Printing Single Command Output

Ansible provides the register and debug modules, which work together seamlessly:

  • register module assigns a variable name to capture the output of specific tasks
  • debug module enables the display of stored output directly on the terminal screen

To demonstrate, let’s use the same playbook template we saw earlier to create a register and debug parameter for the specified command. The variable name declared in the register parameter and assigned to the debug parameter can take on any name:

$ cat check_resources.yml
---
- name: Checking System Resources
  hosts: web-servers
  tasks:
    - name: Check Memory Usage
      command: free
      register: print_memory_usage

    - debug:
        var: print_memory_usage.stdout_lines

Let’s go ahead and run the playbook:

$ ansible-playbook check_resources.yml
...

TASK [Check Memory Usage] *****************************************************************************
changed: [172.31.4.218]

TASK [debug] *****************************************************************************
ok: [172.31.4.218] => {
    "print_memory_usage.stdout_lines": [
        "               total        used        free      shared  buff/cache   available",
        "Mem:          980416      360224      226288         916      568056      620192",
        "Swap:              0           0           0"
    ]
}
...

The benefit of using this method over the verbose option is that it provides a clear and structured output without any additional information, which usually eases the understanding compared to the verbose mode.

4. Printing Multiple Command Outputs

To display the output of multiple commands listed in the playbook, let’s again use the register and debug modules. By creating a dedicated debug task for each command, the desired outputs are effectively printed.

To demonstrate, let’s create an additional task that runs the df command on the remote server. Following this, we define a debug parameter for both the free and df commands to display their output on the terminal screen:

$ cat check_resources.yml
---
- name: Checking System Resources
  hosts: web-servers
  tasks:
    - name: Check Memory Usage
      command: free
      register: print_memory_usage

    - name: Check Disk Usage
      command: df /dev/root -h
      register: print_disk_usage

    - name: Print Memory Usage
      debug:
        var: print_memory_usage.stdout_lines

    - name: Print Disk Usage
      debug:
        var: print_disk_usage.stdout_lines

Next, we execute the playbook file:

$ ansible-playbook check_resources.yml
...
TASK [Check Memory Usage] *****************************************************************************
changed: [172.31.4.218]

TASK [Check Disk Usage] *****************************************************************************
changed: [172.31.4.218]

TASK [Print Memory Usage] *****************************************************************************
ok: [172.31.4.218] => {
    "print_memory_usage.stdout_lines": [
        "               total        used        free      shared  buff/cache   available",
        "Mem:          980416      360876      225116         916      568576      619540",
        "Swap:              0           0           0"
    ]
}

TASK [Print Disk Usage] *****************************************************************************
ok: [172.31.4.218] => {
    "print_disk_usage.stdout_lines": [
        "Filesystem      Size  Used Avail Use% Mounted on",
        "/dev/root       6.8G  2.0G  4.8G  30% /"
    ]
}
...

The output on the terminal screen shows that both commands run successfully on the server. Further, we can see the results from each.

5. Conclusion

In this article, we discussed how to effectively display the output of commands run on a remote server using an Ansible playbook.

First, we learned how to use the verbose mode to obtain command output in JSON format. Subsequently, we learned to use the register and debug modules, which provided us with more focused and insightful results than the verbose mode alone.