From 0830b6905996fb02eefcba79a9b055961e251078 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Thu, 11 May 2023 11:54:41 -0400 Subject: config lookup, new option to show origin of value (#80651) --- changelogs/fragments/config_origins_option.yml | 2 ++ lib/ansible/plugins/__init__.py | 13 +++++++++---- lib/ansible/plugins/lookup/config.py | 20 +++++++++++++++----- .../integration/targets/lookup_config/tasks/main.yml | 2 ++ 4 files changed, 28 insertions(+), 9 deletions(-) create mode 100644 changelogs/fragments/config_origins_option.yml diff --git a/changelogs/fragments/config_origins_option.yml b/changelogs/fragments/config_origins_option.yml new file mode 100644 index 0000000000..ac9263ccf6 --- /dev/null +++ b/changelogs/fragments/config_origins_option.yml @@ -0,0 +1,2 @@ +minor_changes: + - config lookup new option show_origin to also return the origin of a configuration value. diff --git a/lib/ansible/plugins/__init__.py b/lib/ansible/plugins/__init__.py index 63988e80d3..9260ba0f61 100644 --- a/lib/ansible/plugins/__init__.py +++ b/lib/ansible/plugins/__init__.py @@ -69,12 +69,17 @@ class AnsiblePlugin(ABC): possible_fqcns.add(name) return bool(possible_fqcns.intersection(set(self.ansible_aliases))) + def get_option_and_origin(self, option, hostvars=None): + try: + option_value, origin = C.config.get_config_value_and_origin(option, plugin_type=self.plugin_type, plugin_name=self._load_name, variables=hostvars) + except AnsibleError as e: + raise KeyError(to_native(e)) + return option_value, origin + def get_option(self, option, hostvars=None): + if option not in self._options: - try: - option_value = C.config.get_config_value(option, plugin_type=self.plugin_type, plugin_name=self._load_name, variables=hostvars) - except AnsibleError as e: - raise KeyError(to_native(e)) + option_value, dummy = self.get_option_and_origin(option, hostvars=hostvars) self.set_option(option, option_value) return self._options.get(option) diff --git a/lib/ansible/plugins/lookup/config.py b/lib/ansible/plugins/lookup/config.py index b31572e6b5..b476b53df4 100644 --- a/lib/ansible/plugins/lookup/config.py +++ b/lib/ansible/plugins/lookup/config.py @@ -33,6 +33,10 @@ DOCUMENTATION = """ description: name of the plugin for which you want to retrieve configuration settings. type: string version_added: '2.12' + show_origin: + description: toggle the display of what configuration subsystem the value came from + type: bool + version_added: '2.16' """ EXAMPLES = """ @@ -67,7 +71,8 @@ EXAMPLES = """ RETURN = """ _raw: description: - - value(s) of the key(s) in the config + - A list of value(s) of the key(s) in the config if show_origin is false (default) + - Optionally, a list of 2 element lists (value, origin) if show_origin is true type: raw """ @@ -92,7 +97,7 @@ def _get_plugin_config(pname, ptype, config, variables): p = loader.get(pname, class_only=True) if p is None: raise AnsibleLookupError('Unable to load %s plugin "%s"' % (ptype, pname)) - result = C.config.get_config_value(config, plugin_type=ptype, plugin_name=p._load_name, variables=variables) + result, origin = C.config.get_config_value_and_origin(config, plugin_type=ptype, plugin_name=p._load_name, variables=variables) except AnsibleLookupError: raise except AnsibleError as e: @@ -101,7 +106,7 @@ def _get_plugin_config(pname, ptype, config, variables): raise MissingSetting(msg, orig_exc=e) raise e - return result + return result, origin def _get_global_config(config): @@ -124,6 +129,7 @@ class LookupModule(LookupBase): missing = self.get_option('on_missing') ptype = self.get_option('plugin_type') pname = self.get_option('plugin_name') + show_origin = self.get_option('show_origin') if (ptype or pname) and not (ptype and pname): raise AnsibleOptionsError('Both plugin_type and plugin_name are required, cannot use one without the other') @@ -138,9 +144,10 @@ class LookupModule(LookupBase): raise AnsibleOptionsError('Invalid setting identifier, "%s" is not a string, its a %s' % (term, type(term))) result = Sentinel + origin = None try: if pname: - result = _get_plugin_config(pname, ptype, term, variables) + result, origin = _get_plugin_config(pname, ptype, term, variables) else: result = _get_global_config(term) except MissingSetting as e: @@ -152,5 +159,8 @@ class LookupModule(LookupBase): pass # this is not needed, but added to have all 3 options stated if result is not Sentinel: - ret.append(result) + if show_origin: + ret.append((result, origin)) + else: + ret.append(result) return ret diff --git a/test/integration/targets/lookup_config/tasks/main.yml b/test/integration/targets/lookup_config/tasks/main.yml index 356d2f8057..e5699d3484 100644 --- a/test/integration/targets/lookup_config/tasks/main.yml +++ b/test/integration/targets/lookup_config/tasks/main.yml @@ -42,6 +42,7 @@ - name: remote user and port for ssh connection set_fact: ssh_user_and_port: '{{q("config", "remote_user", "port", plugin_type="connection", plugin_name="ssh")}}' + ssh_user_and_port_and_origin: '{{q("config", "remote_user", "port", plugin_type="connection", plugin_name="ssh", show_origin=True)}}' vars: ansible_ssh_user: lola ansible_ssh_port: 2022 @@ -71,4 +72,5 @@ - lookup_config_7 is failed - '"Invalid setting" in lookup_config_7.msg' - ssh_user_and_port == ['lola', 2022] + - "ssh_user_and_port_and_origin == [['lola', 'var: ansible_ssh_user'], [2022, 'var: ansible_ssh_port']]" - yolo_remote == ["yolo"] -- cgit v1.2.1