Parsing Command Output in Ansible with JC

Ansible is a popular automation framework that allows you to configure any number of remote hosts in a declarative and idempotent way. A common use-case is to run a shell command on the remote host, return the STDOUT output, loop through it and parse it.

Starting in Ansible 2.9 with the community.general collection, it is possible to use jc (https://github.com/kellyjonbrazil/jc) as a filter to automatically parse the command output for you so you can easily use the output as an object.

For more information on the motivations for creating jc, see my blog post.

Installation

To use the jc filter plugin, you just need to install jc and the community.general collection on the Ansible controller. Ansible version 2.9 or higher is required to install the community.general collection.

Installing jc:

$ pip3 install jc

Installing the community.general Ansible collection:

$ ansible-galaxy collection install community.general

Now we are ready to use the jc filter plugin!

Syntax

To use the jc filter plugin you just need to pipe the command output to the plugin and specify the parser as an argument. For example, this is how you would parse the output of ps on the remote host:

  tasks:
  - shell: ps aux
    register: result
  - set_fact:
      myvar: "{{ result.stdout | community.general.jc('ps') }}"

This will generate a myvar object that includes the exact same information you would have received by running jc ps aux on the remote host. Now you can use object notation to pull out the information you are interested in.

A Simple Example

Let’s put it all together with a very simple example. In this example we will run the date command on the remote host and print the timezone as a debug message:

- name: Get Timezone
  hosts: ubuntu
  tasks:
  - shell: date
    register: result
  - set_fact:
      myvar: "{{ result.stdout | community.general.jc('date') }}"
  - debug:
      msg: "The timezone is: {{ myvar.timezone }}"

Instead of parsing the STDOUT text manually, we used the timezone attribute of the myvar object that jc gave us. Let’s see this in action:

$ ansible-playbook get-timezone.yml 

PLAY [Get Timezone] *****************************************************************************

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

TASK [shell] ************************************************************************************
changed: [192.168.1.239]

TASK [set_fact] *********************************************************************************
ok: [192.168.1.239]

TASK [debug] ************************************************************************************
ok: [192.168.1.239] => {
    "msg": "The timezone is: UTC"
}

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

Simple – no more need to grep/awk/sed your way through the output to get what you are looking for!

For a complete list of jc parsers available and their associated schemas, see the parser documentation.

Happy parsing!

Published by kellyjonbrazil

I'm a cybersecurity and cloud computing nerd.

2 thoughts on “Parsing Command Output in Ansible with JC

  1. I am faced with below challenge:
    In a stacked switch, ‘ansible_net_filesystems_info’ of ios_facts module only shows free space of master switch. It doesn’t show space of member switches. But I need to write a script that will check for certain amountt of free space in EVERY member switch before copying ios image.

    Pyats/Genie parser (the only parser i finally managed to understand) doesn’t support ‘sh flash:’ command (it only supports ‘sh bootflash:’ which doesn’t work with my switch model). Is there any other parser that can parse above command?

    Thanks,
    Vikram

    1. Hi Vikram – jc is focused on parsing workstation/server OS commands like linux, macOS, BSD, Windows. I know there are many different parser packages for network appliance vendors like you mentioned. Maybe there is an Ansible collection plugin from Cisco that has a parser for that command?

Leave a Reply

%d bloggers like this: