config lookup can query plugin settings (#74186)
* config lookup can query plugin settings
This commit is contained in:
parent
bb7b17fded
commit
9f856a4964
3 changed files with 92 additions and 11 deletions
2
changelogs/fragments/config_lookup_plugins.yml
Normal file
2
changelogs/fragments/config_lookup_plugins.yml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
minor_changes:
|
||||||
|
- config lookup now can handle plugin settings.
|
|
@ -24,6 +24,15 @@ DOCUMENTATION = """
|
||||||
default: error
|
default: error
|
||||||
type: string
|
type: string
|
||||||
choices: ['error', 'skip', 'warn']
|
choices: ['error', 'skip', 'warn']
|
||||||
|
plugin_type:
|
||||||
|
description: the type of the plugin referenced by 'plugin_name' option.
|
||||||
|
choices: ['become', 'cache', 'callback', 'cliconf', 'connection', 'httpapi', 'inventory', 'lookup', 'netconf', 'shell', 'vars']
|
||||||
|
type: string
|
||||||
|
version_added: '2.12'
|
||||||
|
plugin_name:
|
||||||
|
description: name of the plugin for which you want to retrieve configuration settings.
|
||||||
|
type: string
|
||||||
|
version_added: '2.12'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
EXAMPLES = """
|
EXAMPLES = """
|
||||||
|
@ -47,6 +56,12 @@ EXAMPLES = """
|
||||||
debug: msg="{{ lookup('config', config_in_var, on_missing='skip')}}"
|
debug: msg="{{ lookup('config', config_in_var, on_missing='skip')}}"
|
||||||
var:
|
var:
|
||||||
config_in_var: UNKNOWN
|
config_in_var: UNKNOWN
|
||||||
|
|
||||||
|
- name: show remote user and port for ssh connection
|
||||||
|
debug: msg={{q("config", "remote_user", "port", plugin_type="connection", plugin_name="ssh", on_missing='skip')}}
|
||||||
|
|
||||||
|
- name: show remote_tmp setting for shell (sh) plugin
|
||||||
|
debug: msg={{q("config", "remote_tmp", plugin_type="shell", plugin_name="sh")}}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
RETURN = """
|
RETURN = """
|
||||||
|
@ -56,32 +71,81 @@ _raw:
|
||||||
type: raw
|
type: raw
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import ansible.plugins.loader as plugin_loader
|
||||||
|
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError, AnsibleLookupError, AnsibleOptionsError
|
||||||
|
from ansible.module_utils._text import to_native
|
||||||
from ansible.module_utils.six import string_types
|
from ansible.module_utils.six import string_types
|
||||||
from ansible.plugins.lookup import LookupBase
|
from ansible.plugins.lookup import LookupBase
|
||||||
|
from ansible.utils.sentinel import Sentinel
|
||||||
|
|
||||||
|
|
||||||
|
class MissingSetting(AnsibleOptionsError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def _get_plugin_config(pname, ptype, config, variables):
|
||||||
|
try:
|
||||||
|
# plugin creates settings on load, this is cached so not too expensive to redo
|
||||||
|
loader = getattr(plugin_loader, '%s_loader' % ptype)
|
||||||
|
dump = loader.get(pname, class_only=True)
|
||||||
|
result = C.config.get_config_value(config, plugin_type=ptype, plugin_name=pname, variables=variables)
|
||||||
|
except AnsibleError as e:
|
||||||
|
msg = to_native(e)
|
||||||
|
if 'was not defined' in msg:
|
||||||
|
raise MissingSetting(msg, orig_exc=e)
|
||||||
|
raise e
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _get_global_config(config):
|
||||||
|
try:
|
||||||
|
result = getattr(C, config)
|
||||||
|
if callable(result):
|
||||||
|
raise AnsibleLookupError('Invalid setting "%s" attempted' % config)
|
||||||
|
except AttributeError as e:
|
||||||
|
raise MissingSetting(to_native(e), orig_exc=e)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
class LookupModule(LookupBase):
|
class LookupModule(LookupBase):
|
||||||
|
|
||||||
def run(self, terms, variables=None, **kwargs):
|
def run(self, terms, variables=None, **kwargs):
|
||||||
|
|
||||||
missing = kwargs.get('on_missing', 'error').lower()
|
self.set_options(var_options=variables, direct=kwargs)
|
||||||
|
|
||||||
|
missing = self.get_option('on_missing')
|
||||||
|
ptype = self.get_option('plugin_type')
|
||||||
|
pname = self.get_option('plugin_name')
|
||||||
|
|
||||||
|
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')
|
||||||
|
|
||||||
if not isinstance(missing, string_types) or missing not in ['error', 'warn', 'skip']:
|
if not isinstance(missing, string_types) or missing not in ['error', 'warn', 'skip']:
|
||||||
raise AnsibleError('"on_missing" must be a string and one of "error", "warn" or "skip", not %s' % missing)
|
raise AnsibleOptionsError('"on_missing" must be a string and one of "error", "warn" or "skip", not %s' % missing)
|
||||||
|
|
||||||
ret = []
|
ret = []
|
||||||
for term in terms:
|
for term in terms:
|
||||||
if not isinstance(term, string_types):
|
if not isinstance(term, string_types):
|
||||||
raise AnsibleError('Invalid setting identifier, "%s" is not a string, its a %s' % (term, type(term)))
|
raise AnsibleOptionsError('Invalid setting identifier, "%s" is not a string, its a %s' % (term, type(term)))
|
||||||
|
|
||||||
|
result = Sentinel
|
||||||
try:
|
try:
|
||||||
result = getattr(C, term)
|
if pname:
|
||||||
if callable(result):
|
result = _get_plugin_config(pname, ptype, term, variables)
|
||||||
raise AnsibleError('Invalid setting "%s" attempted' % term)
|
else:
|
||||||
ret.append(result)
|
result = _get_global_config(term)
|
||||||
except AttributeError:
|
except MissingSetting as e:
|
||||||
if missing == 'error':
|
if missing == 'error':
|
||||||
raise AnsibleError('Unable to find setting %s' % term)
|
raise AnsibleLookupError('Unable to find setting %s' % term, orig_exc=e)
|
||||||
elif missing == 'warn':
|
elif missing == 'warn':
|
||||||
self._display.warning('Skipping, did not find setting %s' % term)
|
self._display.warning('Skipping, did not find setting %s' % term)
|
||||||
|
elif missing == 'skip':
|
||||||
|
pass # this is not needed, but added to have all 3 options stated
|
||||||
|
|
||||||
|
if result is not Sentinel:
|
||||||
|
ret.append(result)
|
||||||
return ret
|
return ret
|
||||||
|
|
|
@ -39,6 +39,19 @@
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
register: lookup_config_7
|
register: lookup_config_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")}}'
|
||||||
|
vars:
|
||||||
|
ansible_ssh_user: lola
|
||||||
|
ansible_ssh_port: 2022
|
||||||
|
|
||||||
|
- name: remote_tmp for sh shell plugin
|
||||||
|
set_fact:
|
||||||
|
yolo_remote: '{{q("config", "remote_tmp", plugin_type="shell", plugin_name="sh")}}'
|
||||||
|
vars:
|
||||||
|
ansible_remote_tmp: yolo
|
||||||
|
|
||||||
- name: Verify lookup_config
|
- name: Verify lookup_config
|
||||||
assert:
|
assert:
|
||||||
that:
|
that:
|
||||||
|
@ -52,8 +65,10 @@
|
||||||
- lookup_config_4 is success
|
- lookup_config_4 is success
|
||||||
- 'lookup4|length == 0'
|
- 'lookup4|length == 0'
|
||||||
- lookup_config_5 is failed
|
- lookup_config_5 is failed
|
||||||
- '"must be a string and one of" in lookup_config_5.msg'
|
- '"valid values are" in lookup_config_5.msg'
|
||||||
- lookup_config_6 is failed
|
- lookup_config_6 is failed
|
||||||
- '"Invalid setting identifier" in lookup_config_6.msg'
|
- '"Invalid setting identifier" in lookup_config_6.msg'
|
||||||
- lookup_config_7 is failed
|
- lookup_config_7 is failed
|
||||||
- '"Invalid setting" in lookup_config_7.msg'
|
- '"Invalid setting" in lookup_config_7.msg'
|
||||||
|
- ssh_user_and_port == ['lola', 2022]
|
||||||
|
- yolo_remote == ["yolo"]
|
||||||
|
|
Loading…
Reference in a new issue