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
as a filter to automatically parse the command output for you so you can easily use the output as an object. The official filter documentation can be found here. Even more detailed documentation can be found here.
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') }}"
Note: Use underscores instead of dashes (if any) in the parser name. e.g.
git-log
becomesgit_log
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!
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
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?