Wednesday, May 11, 2022

Ansible - Extract Dictionary Values When Nested Inside A List - Python solution

Ansible has some great built-in filters that can be found here. Two filters worth noting is items2dict and dict2items. These two filters enable you to either convert a list to a dictionary format, or a dictionary to a list format.

There is one problem though. What if you have a dictionary that is embedded into a list and want to extract dictionary values into a list? This is where it gets complicated.

OR, you can take advantage of the Ansible custom filter option and create your own filter.


#!/usr/bin/python3
#
# itemdict_to_item.py
# This iterates through a list of dictionaries,
#   extracts a dictionary value and combines
#   the values into a list.
#
# Example:
#   my_list[{'my_key': 'value1'},{'my_key': 'value2'}]
#
#   Apply the filter as so:
#     {{ my_list | itemdict_to_item('my_key') }}
#
#   Returned result:
#     ['value1', 'value2']
#
class FilterModule(object):
  def filters(self):
    return {'itemdict_to_item': self.extracted_values}

  def extracted_values(self, outer_list, passed_key):
    # Create a blank list that will hold the extracted
    #   values.
    ret_list = []
    
    # Loop through the list. If the key exists in the
    #   nested dictionary, append its paired value to
    #   ret_list
    for nested_dict in outer_list:
      if passed_key in nested_dict:
        ret_list.append(nested_dict[passed_key])
        
    return ret_list

You'll need to create a directory called filter_plugins within the same directory as the playbook you're running. Your Python script will go in the filter_plugins directory. The file name is irrelevant, just be sure it ends with .py


[dan@localhost playbooks]$ ls
my_playbook.yml filter_plugins

[dan@localhost playbooks]$ ls filter_plugins/
my_custom_filter.py

Finally, I use it in an Ansible play. I want to create a list of files that are in a directory.


- name: Get files in directory
  ansible.builtin.find:
    paths: /some/directory
  register: search_results
  
- name: Set Fact
  ansible.builtin.set_fact:
    search_list: "{{ search_results['files'] | itemdict_to_item('path') }}"

No comments:

Post a Comment