Ansible Register Module

Ansible Register Module

In this Article I will talk about how we can capture the output of the commands or Ansible tasks and take actions based on them.

By default, the output of any command or task is ignored. But at times its required to store that data for further usage, in that case you can use the Ansible register module.

Let us understand this by an example.

Example 1 - Find the status of a service running on remote nodes

Here is my playbook:

---
- name: Ansible register Module example -1
  hosts: workers
  become: true
  tasks:
    - name: starting vsftpd
      service: name=vsftpd state=started enabled=yes

    - name: vsftpd status
      command: service vsftpd status
      register: vsftpd_status

    - name: vsftpd status output
      debug:
        var: vsftpd_status

Our target is to find out the status of FTP service on both our worker nodes. In the above playbook we are storing vsftpd service status in an register variable called vsftpd_status.

And further using debug module we will be printing the registered variable's output.

Let us run the playbook now.

register_module $ ansible-playbook -i ../myinventory register_example.yml

PLAY [Ansible register Module example -1] **********************************************************************

TASK [Gathering Facts] *****************************************************************************************
ok: [worker2]
ok: [worker1]

TASK [starting vsftpd] *****************************************************************************************
fatal: [worker2]: FAILED! => {"changed": false, "msg": "Could not find the requested service vsftpd: host"}
changed: [worker1]

TASK [vsftpd status] *******************************************************************************************
[WARNING]: Consider using the service module rather than running 'service'.  If you need to use command because
service is insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in
ansible.cfg to get rid of this message.
changed: [worker1]

TASK [vsftpd status output] ************************************************************************************
ok: [worker1] => {
    "vsftpd_status": {
        "changed": true,
        "cmd": [
            "service",
            "vsftpd",
            "status"
        ],
        "delta": "0:00:00.057396",
        "end": "2021-01-27 10:56:19.458938",
        "failed": false,
        "rc": 0,
        "start": "2021-01-27 10:56:19.401542",
        "stderr": "Redirecting to /bin/systemctl status vsftpd.service",
        "stderr_lines": [
            "Redirecting to /bin/systemctl status vsftpd.service"
        ],
        "stdout": "● vsftpd.service - Vsftpd ftp daemon\n   Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; enabled; vendor preset: disabled)\n   Active: active (running) since Wed 2021-01-27 10:56:18 UTC; 499ms ago\n  Process: 3664 ExecStart=/usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf (code=exited, status=0/SUCCESS)\n Main PID: 3665 (vsftpd)\n   CGroup: /system.slice/vsftpd.service\n           └─3665 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf\n\nJan 27 10:56:18 lco-worker1.example.com systemd[1]: Starting Vsftpd ftp daemon...\nJan 27 10:56:18 lco-worker1.example.com systemd[1]: Started Vsftpd ftp daemon.",
        "stdout_lines": [
            "● vsftpd.service - Vsftpd ftp daemon",
            "   Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; enabled; vendor preset: disabled)",
            "   Active: active (running) since Wed 2021-01-27 10:56:18 UTC; 499ms ago",
            "  Process: 3664 ExecStart=/usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf (code=exited, status=0/SUCCESS)",
            " Main PID: 3665 (vsftpd)",
            "   CGroup: /system.slice/vsftpd.service",
            "           └─3665 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf",
            "",
            "Jan 27 10:56:18 lco-worker1.example.com systemd[1]: Starting Vsftpd ftp daemon...",
            "Jan 27 10:56:18 lco-worker1.example.com systemd[1]: Started Vsftpd ftp daemon."
        ],
        "warnings": [
            "Consider using the service module rather than running 'service'.  If you need to use command because service is insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message."
        ]
    }
}

PLAY RECAP *****************************************************************************************************
worker1                    : ok=4    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
worker2                    : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

Before I decode the above output I want to mention one thing that whenever you use register module for storing values it outputs following values:

changed - A Boolean indicating if the task had to make changes.

cmd – The actual command which ran to generate the output.

stdout – The output of the command.

stderr – The error output of the command.

start – The command execution begin time

end – The command execution finished time

delta – The total time taken to run the command. The value of this property is the difference between the end and the start time outputs.

stdout_lines – An array of stdout lines one per line. When stdout is returned, Ansible always provides a list of strings, each containing one item per line from the original output.

stderr_lines – An array of stderrlines one per line. When stderr is returned we also always provide this field which is a list of strings, one item per line from the original.

Now I will come to the output which we have got after our playbook execution. It displayed the complete output for all the properties listed above.

If you have noticed we have got an error for our playbook while running on worker2 machine because vsftpd service is not present on that host.

Now we want to filter out the useful information out of the whole output which we have got.

Filter the output with stderr_line

Here is my updated playbook file.

---
- name: Ansible register Module example -1
  hosts: workers
  become: true
  tasks:
    - name: starting vsftpd
      service: name=vsftpd state=started enabled=yes

    - name: vsftpd status
      command: service vsftpd status
      register: vsftpd_status

    - name: vsftpd status output
      debug:
        var: vsftpd_status.stderr_lines

Let us execute the playbook.

register_module $ ansible-playbook -i ../myinventory register_example.yml

PLAY [Ansible register Module example -1] **********************************************************************

TASK [Gathering Facts] *****************************************************************************************
ok: [worker1]
ok: [worker2]

TASK [starting vsftpd] *****************************************************************************************
fatal: [worker2]: FAILED! => {"changed": false, "msg": "Could not find the requested service vsftpd: host"}
ok: [worker1]

TASK [vsftpd status] *******************************************************************************************
[WARNING]: Consider using the service module rather than running 'service'.  If you need to use command because
service is insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in
ansible.cfg to get rid of this message.
changed: [worker1]

TASK [vsftpd status output] ************************************************************************************
ok: [worker1] => {
    "vsftpd_status.stderr_lines": [
        "Redirecting to /bin/systemctl status vsftpd.service"
    ]
}

PLAY RECAP *****************************************************************************************************
worker1                    : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
worker2                    : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

You can see that we have filtered out the stderr output from the whole output displayed on stdout.

Similarly you can filter the output with stdout_lines by using vsftpd_status.stdout_lines.

Example 2 - Take action based on register variable output

You can take actions based on the register variable outputs. Here we will use with_items statement which will iterate through the stored register values and take action accordingly.

Here is my playbook which will find the video files ending with .mov extension and based on the list will delete them:

---
- name: Ansible register Module example 2
  hosts: master
  become: true
  tasks:
    - name: Find video files
      shell: "find *.mov"
      args:
        chdir: "/home/ansible_user/ansible/register_module/downloads"
      register: file_output
    - shell: "rm -rf {{ item }}"
      args:
        chdir: "/home/ansible_user/ansible/register_module/downloads"
      with_items:
        - "{{ file_output.stdout_lines }}"

chdir argument - It changes into the specified directory before running the command.

Here is the content of that directory:

downloads $ pwd
/home/ansible_user/ansible/register_module/downloads
downloads $ tree
.
├── docs
├── hello.txt
├── links.txt
├── one_upon_a_time_in_hollywood.mov
└── titanic.mov

1 directory, 4 files

Let us execute our playbook.

register_module $ ansible-playbook -i ../myinventory register_example-2.yml

PLAY [Ansible register Module example 2] ***********************************************************************

TASK [Gathering Facts] *****************************************************************************************
ok: [master]

TASK [Find video files] ****************************************************************************************
changed: [master]

TASK [shell] ***************************************************************************************************
changed: [master] => (item=one_upon_a_time_in_hollywood.mov)
changed: [master] => (item=titanic.mov)

PLAY RECAP *****************************************************************************************************
master                     : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Now verify of those files have been deleted or not.

register_module $ tree downloads/
downloads/
├── docs
├── hello.txt
└── links.txt

1 directory, 2 files

Great! They have been deleted.

Conclusion

Ansible Register module is extremely useful and important when you perform server automation. I am sure you will find yourself comfortable with that after going through this article.

That's all for now.

Hope you like the article. Stay Tuned for more.

Thank you. Happy learning!

Did you find this article valuable?

Support Learn Code Online by becoming a sponsor. Any amount is appreciated!