Listing, Iterating, and Loading JSON in Ansible Playbooks

I just had to work with JSON in Ansible, and iterate through some data. It took me a few efforts of debugs before I got it, so putting it here for posterity, in hopes to help someone else.

Eventually, my Ansible playbook will be making a RESTful call to pull the data. So, to start, I put the example JSON data the call would get into a file. I called the file “data.json” and put it in the same directory as my playbook.

 .
 ├── data.json
 └── json_iter.yml

 0 directories, 2 files

My example data.json looks like this:

 {"webInfLib":[{"contextRoot":"Application1"},{"contextRoot":"Application2"},{"contextRoot":"Application3"}]}

So, I wanted to iterate the data for each “contextRoot” and do something with each application. First, I loaded the JSON into a var using the ‘lookup’ file plugin and used the “from_json” filter to bring it in as a workable object:

 tmpdata: "{{ lookup('file','data.json')|from_json }}"

Then, using that variable, I iterated each one using the “with_items” loop directive:

 debug: var=item.contextRoot
 with_items: "{{ tmpdata.webInfLib }}"

The full test playbook looks like this:

 ---
 - hosts: localhost
   vars:
     tmpdata: "{{ lookup('file','data.json')|from_json }}"

   tasks:
   - name: Iterate JSON
     debug: var=item.contextRoot
     with_items: "{{ tmpdata.webInfLib }}"

So, now that we have our list of data, we will want to store it for future use later, right? I mean, what good is getting this data if we don’t actually do anything with it? So, let’s add this list of items to a fact. We will be using the set_fact module, as well as using a couple of filters. Notably, the “map” and “list” filters.

So, let’s go back to our playbook, and instead of debugging we will be adding it to a fact.

   tasks:
   - name: Iterate JSON
     set_fact:
        app_item: "{{ item.contextRoot }}"
     with_items: "{{ tmpdata.webInfLib }}"

Now, if you actually run this, you will notice a minor inconvenience! We are replacing the previous item in the “app_item” fact variable, with the last iteration of item! Well, that’s not good! We need a list of items in a single fact! So, let’s do that. The first thing we will want to do, is grab the output of the entire set_fact module (which includes each iteration). We will do that in a "“register”" directive.

   - name: Iterate JSON
     set_fact:
       app_item: "{{ item.contextRoot }}"
     with_items: "{{ tmpdata.webInfLib }}"
     register: app_result

Excellent! Now, let’s move on to the next step. We have the output of all the iterations for set_fact. If you don’t believe me, go ahead and debug the variable “app_result” to see what it includes. Go ahead. It will help you understand what I’m doing below.

Now, comes the really cool part with filters. I hope you can follow along, as it can kinda get complex if you’ve never used them. First off, we are going to take the output from set_fact, and pull out only the attribute “app_item”, since that’s where the data we want resides. If you count, using my example json, you will see there are 3 iterations of “app_item” under the key “ansible_facts”

So, I’m going to extract the data following the attribute “app_item” from the results object of the registered variable “app_result”.

   - name: Create Fact List
     set_fact:
         apps: "{{ app_result.results | map(attribute='ansible_facts.app_item') | list }}"

So, what I’m doing is pulling out the data which the attribute “ansible_facts.app_item” is located inside the registered variable “app_result.results”. Now that I have all of the data, I’m sending it to the “list” filter, to create a list, and put THAT in the apps fact.

Finally, the playbook task:

   - name:  Print Fact
     debug: var=apps

Will give me a list of objects, to be used in a module:

 TASK [Print Fact] **************************************************************
 ok: [localhost] => {
     "apps": [
         "Application1",
         "Application2",
         "Application3"
     ]
 }

Ansiblized! Happy Automating!

Share This Page : Share on TwitterShare on FacebookShare on GooglePlusShare on PinterestShare on Linkedin