From 67005aad2a4193a4b0237707620f3362883b6087 Mon Sep 17 00:00:00 2001 From: Alex Schultz Date: Fri, 20 Dec 2019 14:24:38 -0700 Subject: [PATCH] Add recursive get key from dict The docker_config (and other data) that we have in tripleo is a complex dict but we need a way to fetch a specific key from a larget structure. This change adds a filter called recursive_get_key_from_dict which will traverse all the dictionaries in a given dataset and return a list containing all the values of the requested key. Partial-Bug: #1870557 Change-Id: I952df4d4a7700eccdb2d49a7fba271518058771a (cherry picked from commit c072a6bf9d3ca3e264ac9055af13c2a4385895b1) --- .../ansible_plugins/filter/helpers.py | 19 +++++++++++++++++- .../tests/plugins/filter/test_helpers.py | 20 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/tripleo_ansible/ansible_plugins/filter/helpers.py b/tripleo_ansible/ansible_plugins/filter/helpers.py index 1c79639a3..265d3bbb8 100644 --- a/tripleo_ansible/ansible_plugins/filter/helpers.py +++ b/tripleo_ansible/ansible_plugins/filter/helpers.py @@ -42,7 +42,8 @@ class FilterModule(object): 'get_role_assignments': self.get_role_assignments, 'get_domain_id': self.get_domain_id, 'get_changed_containers': self.get_changed_containers, - 'get_failed_containers': self.get_failed_containers + 'get_failed_containers': self.get_failed_containers, + 'recursive_get_key_from_dict': self.recursive_get_key_from_dict } def subsort(self, dict_to_sort, attribute, null_value=0): @@ -264,6 +265,22 @@ class FilterModule(object): returned_list.append(value) return returned_list + def recursive_get_key_from_dict(self, data, key): + """Recursively return values for keys in a dict + + This filter will traverse all the dictionaries in the provided + dictionary and return any values for a specified key. This is useful + if you have a complex dictionary containing dynamic keys but want to + fetch a commonly named key. + """ + val = [] + if key in data: + val.append(data.get(key)) + for k, v in data.items(): + if isinstance(v, dict): + val.extend(self.recursive_get_key_from_dict(v, key)) + return val + def list_or_dict_arg(self, data, cmd, key, arg): """Utility to build a command and its argument with list or dict data. diff --git a/tripleo_ansible/tests/plugins/filter/test_helpers.py b/tripleo_ansible/tests/plugins/filter/test_helpers.py index 427cc33af..ac4df3a9d 100644 --- a/tripleo_ansible/tests/plugins/filter/test_helpers.py +++ b/tripleo_ansible/tests/plugins/filter/test_helpers.py @@ -687,6 +687,26 @@ class TestHelperFilters(tests_base.TestCase): result = self.filters.get_key_from_dict(data, key='users') self.assertEqual(result, expected_list) + def test_recursive_get_key_from_dict(self): + data = { + 'step': {'container': {'name': 'foo', 'image': 'bar'}, + 'other_container': {'name': 'meh', 'image': 'baz'} + } + } + expected_list = ['bar', 'baz'] + result = self.filters.recursive_get_key_from_dict(data, 'image') + self.assertEqual(result, expected_list) + + def test_recursive_get_key_from_dict_multiple_levels(self): + data = { + 'a': {'b': {'val': 1}, + 'c': {'val': 2, 'd': {'val': 3}} + } + } + expected_list = [1, 2, 3] + result = self.filters.recursive_get_key_from_dict(data, 'val') + self.assertEqual(result, expected_list) + def test_container_exec_cmd(self): data = { "action": "exec",