mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Lookups: use Ansible's config manager whenever possible (#5440)
* Start using Ansible's config manager to handle options. * Docs improvements. * Fix documentation, make options actual lookup options. * The cyberarkpassword lookup does too strange things. * The onepassword lookups are converted in #4728, let's not interfere. * Improve docs. * Skip shelvefile as well. * Convert lmdb_kv. * Convert and fix credstash. * Convert manifold. * Drop chef_databag. * Convert dig. * Update examples. * Forgot the most important part. * Fix lmdb_kv docs. * Python 2.6 compatibility. * Convert AnsibleUnicode to str. * Load lookup with lookup loader. * Fix environment handling and error message checking. * Improve docs formatting.
This commit is contained in:
parent
dc66aefa40
commit
e718bd8445
17 changed files with 161 additions and 91 deletions
1
.github/workflows/docs-pr.yml
vendored
1
.github/workflows/docs-pr.yml
vendored
|
@ -26,6 +26,7 @@ jobs:
|
||||||
init-fail-on-error: true
|
init-fail-on-error: true
|
||||||
provide-link-targets: |
|
provide-link-targets: |
|
||||||
ansible_collections.ansible.builtin.dict2items_filter
|
ansible_collections.ansible.builtin.dict2items_filter
|
||||||
|
ansible_collections.ansible.builtin.items_lookup
|
||||||
ansible_collections.ansible.builtin.path_join_filter
|
ansible_collections.ansible.builtin.path_join_filter
|
||||||
ansible_collections.community.kubevirt.kubevirt_cdi_upload_module
|
ansible_collections.community.kubevirt.kubevirt_cdi_upload_module
|
||||||
ansible_collections.community.kubevirt.kubevirt_inventory
|
ansible_collections.community.kubevirt.kubevirt_inventory
|
||||||
|
|
14
changelogs/fragments/lookup-options.yml
Normal file
14
changelogs/fragments/lookup-options.yml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
minor_changes:
|
||||||
|
- "cartesian lookup plugin - start using Ansible's configuration manager to parse options (https://github.com/ansible-collections/community.general/pull/5440)."
|
||||||
|
- "credstash lookup plugin - start using Ansible's configuration manager to parse options (https://github.com/ansible-collections/community.general/pull/5440)."
|
||||||
|
- "dependent lookup plugin - start using Ansible's configuration manager to parse options (https://github.com/ansible-collections/community.general/pull/5440)."
|
||||||
|
- "dig lookup plugin - start using Ansible's configuration manager to parse options. All documented options can now also be passed as lookup parameters (https://github.com/ansible-collections/community.general/pull/5440)."
|
||||||
|
- "dnstxt lookup plugin - start using Ansible's configuration manager to parse options (https://github.com/ansible-collections/community.general/pull/5440)."
|
||||||
|
- "filetree lookup plugin - start using Ansible's configuration manager to parse options (https://github.com/ansible-collections/community.general/pull/5440)."
|
||||||
|
- "flattened lookup plugin - start using Ansible's configuration manager to parse options (https://github.com/ansible-collections/community.general/pull/5440)."
|
||||||
|
- "hiera lookup plugin - start using Ansible's configuration manager to parse options. The Hiera executable and config file can now also be passed as lookup parameters (https://github.com/ansible-collections/community.general/pull/5440)."
|
||||||
|
- "keyring lookup plugin - start using Ansible's configuration manager to parse options (https://github.com/ansible-collections/community.general/pull/5440)."
|
||||||
|
- "lmdb_kv lookup plugin - start using Ansible's configuration manager to parse options (https://github.com/ansible-collections/community.general/pull/5440)."
|
||||||
|
- "manifold lookup plugin - start using Ansible's configuration manager to parse options (https://github.com/ansible-collections/community.general/pull/5440)."
|
||||||
|
bugfixes:
|
||||||
|
- "credstash lookup plugin - pass plugin options to credstash for all terms, not just for the first (https://github.com/ansible-collections/community.general/pull/5440)."
|
|
@ -15,9 +15,11 @@ DOCUMENTATION = '''
|
||||||
- It is clearer with an example, it turns [1, 2, 3], [a, b] into [1, a], [1, b], [2, a], [2, b], [3, a], [3, b].
|
- It is clearer with an example, it turns [1, 2, 3], [a, b] into [1, a], [1, b], [2, a], [2, b], [3, a], [3, b].
|
||||||
You can see the exact syntax in the examples section.
|
You can see the exact syntax in the examples section.
|
||||||
options:
|
options:
|
||||||
_raw:
|
_terms:
|
||||||
description:
|
description:
|
||||||
- a set of lists
|
- a set of lists
|
||||||
|
type: list
|
||||||
|
elements: list
|
||||||
required: true
|
required: true
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
@ -69,6 +71,7 @@ class LookupModule(LookupBase):
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def run(self, terms, variables=None, **kwargs):
|
def run(self, terms, variables=None, **kwargs):
|
||||||
|
self.set_options(var_options=variables, direct=kwargs)
|
||||||
|
|
||||||
terms = self._lookup_variables(terms)
|
terms = self._lookup_variables(terms)
|
||||||
|
|
||||||
|
|
|
@ -22,25 +22,33 @@ DOCUMENTATION = '''
|
||||||
required: true
|
required: true
|
||||||
table:
|
table:
|
||||||
description: name of the credstash table to query
|
description: name of the credstash table to query
|
||||||
|
type: str
|
||||||
default: 'credential-store'
|
default: 'credential-store'
|
||||||
version:
|
version:
|
||||||
description: Credstash version
|
description: Credstash version
|
||||||
|
type: str
|
||||||
|
default: ''
|
||||||
region:
|
region:
|
||||||
description: AWS region
|
description: AWS region
|
||||||
|
type: str
|
||||||
profile_name:
|
profile_name:
|
||||||
description: AWS profile to use for authentication
|
description: AWS profile to use for authentication
|
||||||
|
type: str
|
||||||
env:
|
env:
|
||||||
- name: AWS_PROFILE
|
- name: AWS_PROFILE
|
||||||
aws_access_key_id:
|
aws_access_key_id:
|
||||||
description: AWS access key ID
|
description: AWS access key ID
|
||||||
|
type: str
|
||||||
env:
|
env:
|
||||||
- name: AWS_ACCESS_KEY_ID
|
- name: AWS_ACCESS_KEY_ID
|
||||||
aws_secret_access_key:
|
aws_secret_access_key:
|
||||||
description: AWS access key
|
description: AWS access key
|
||||||
|
type: str
|
||||||
env:
|
env:
|
||||||
- name: AWS_SECRET_ACCESS_KEY
|
- name: AWS_SECRET_ACCESS_KEY
|
||||||
aws_session_token:
|
aws_session_token:
|
||||||
description: AWS session token
|
description: AWS session token
|
||||||
|
type: str
|
||||||
env:
|
env:
|
||||||
- name: AWS_SESSION_TOKEN
|
- name: AWS_SESSION_TOKEN
|
||||||
'''
|
'''
|
||||||
|
@ -100,28 +108,39 @@ except ImportError:
|
||||||
|
|
||||||
|
|
||||||
class LookupModule(LookupBase):
|
class LookupModule(LookupBase):
|
||||||
def run(self, terms, variables, **kwargs):
|
def run(self, terms, variables=None, **kwargs):
|
||||||
|
|
||||||
if not CREDSTASH_INSTALLED:
|
if not CREDSTASH_INSTALLED:
|
||||||
raise AnsibleError('The credstash lookup plugin requires credstash to be installed.')
|
raise AnsibleError('The credstash lookup plugin requires credstash to be installed.')
|
||||||
|
|
||||||
|
self.set_options(var_options=variables, direct=kwargs)
|
||||||
|
|
||||||
|
version = self.get_option('version')
|
||||||
|
region = self.get_option('region')
|
||||||
|
table = self.get_option('table')
|
||||||
|
profile_name = self.get_option('profile_name')
|
||||||
|
aws_access_key_id = self.get_option('aws_access_key_id')
|
||||||
|
aws_secret_access_key = self.get_option('aws_secret_access_key')
|
||||||
|
aws_session_token = self.get_option('aws_session_token')
|
||||||
|
|
||||||
|
context = dict(
|
||||||
|
(k, v) for k, v in kwargs.items()
|
||||||
|
if k not in ('version', 'region', 'table', 'profile_name', 'aws_access_key_id', 'aws_secret_access_key', 'aws_session_token')
|
||||||
|
)
|
||||||
|
|
||||||
|
kwargs_pass = {
|
||||||
|
'profile_name': profile_name,
|
||||||
|
'aws_access_key_id': aws_access_key_id,
|
||||||
|
'aws_secret_access_key': aws_secret_access_key,
|
||||||
|
'aws_session_token': aws_session_token,
|
||||||
|
}
|
||||||
|
|
||||||
ret = []
|
ret = []
|
||||||
for term in terms:
|
for term in terms:
|
||||||
try:
|
try:
|
||||||
version = kwargs.pop('version', '')
|
ret.append(credstash.getSecret(term, version, region, table, context=context, **kwargs_pass))
|
||||||
region = kwargs.pop('region', None)
|
|
||||||
table = kwargs.pop('table', 'credential-store')
|
|
||||||
profile_name = kwargs.pop('profile_name', os.getenv('AWS_PROFILE', None))
|
|
||||||
aws_access_key_id = kwargs.pop('aws_access_key_id', os.getenv('AWS_ACCESS_KEY_ID', None))
|
|
||||||
aws_secret_access_key = kwargs.pop('aws_secret_access_key', os.getenv('AWS_SECRET_ACCESS_KEY', None))
|
|
||||||
aws_session_token = kwargs.pop('aws_session_token', os.getenv('AWS_SESSION_TOKEN', None))
|
|
||||||
kwargs_pass = {'profile_name': profile_name, 'aws_access_key_id': aws_access_key_id,
|
|
||||||
'aws_secret_access_key': aws_secret_access_key, 'aws_session_token': aws_session_token}
|
|
||||||
val = credstash.getSecret(term, version, region, table, context=kwargs, **kwargs_pass)
|
|
||||||
except credstash.ItemNotFound:
|
except credstash.ItemNotFound:
|
||||||
raise AnsibleError('Key {0} not found'.format(term))
|
raise AnsibleError('Key {0} not found'.format(term))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise AnsibleError('Encountered exception while fetching {0}: {1}'.format(term, e))
|
raise AnsibleError('Encountered exception while fetching {0}: {1}'.format(term, e))
|
||||||
ret.append(val)
|
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
|
@ -174,7 +174,6 @@ class LookupModule(LookupBase):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def run(self, terms, variables=None, **kwargs):
|
def run(self, terms, variables=None, **kwargs):
|
||||||
|
|
||||||
display.vvvv("%s" % terms)
|
display.vvvv("%s" % terms)
|
||||||
if isinstance(terms, list):
|
if isinstance(terms, list):
|
||||||
return_values = []
|
return_values = []
|
||||||
|
|
|
@ -16,7 +16,7 @@ description:
|
||||||
or template expressions which evaluate to lists or dicts, composed of the elements of
|
or template expressions which evaluate to lists or dicts, composed of the elements of
|
||||||
the input evaluated lists and dictionaries."
|
the input evaluated lists and dictionaries."
|
||||||
options:
|
options:
|
||||||
_raw:
|
_terms:
|
||||||
description:
|
description:
|
||||||
- A list where the elements are one-element dictionaries, mapping a name to a string, list, or dictionary.
|
- A list where the elements are one-element dictionaries, mapping a name to a string, list, or dictionary.
|
||||||
The name is the index that is used in the result object. The value is iterated over as described below.
|
The name is the index that is used in the result object. The value is iterated over as described below.
|
||||||
|
@ -180,6 +180,8 @@ class LookupModule(LookupBase):
|
||||||
|
|
||||||
def run(self, terms, variables=None, **kwargs):
|
def run(self, terms, variables=None, **kwargs):
|
||||||
"""Generate list."""
|
"""Generate list."""
|
||||||
|
self.set_options(var_options=variables, direct=kwargs)
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
if len(terms) > 0:
|
if len(terms) > 0:
|
||||||
templar = Templar(loader=self._templar._loader)
|
templar = Templar(loader=self._templar._loader)
|
||||||
|
|
|
@ -21,22 +21,26 @@ DOCUMENTATION = '''
|
||||||
- In addition to (default) A record, it is also possible to specify a different record type that should be queried.
|
- In addition to (default) A record, it is also possible to specify a different record type that should be queried.
|
||||||
This can be done by either passing-in additional parameter of format qtype=TYPE to the dig lookup, or by appending /TYPE to the FQDN being queried.
|
This can be done by either passing-in additional parameter of format qtype=TYPE to the dig lookup, or by appending /TYPE to the FQDN being queried.
|
||||||
- If multiple values are associated with the requested record, the results will be returned as a comma-separated list.
|
- If multiple values are associated with the requested record, the results will be returned as a comma-separated list.
|
||||||
In such cases you may want to pass option wantlist=True to the plugin, which will result in the record values being returned as a list
|
In such cases you may want to pass option I(wantlist=true) to the lookup call, or alternatively use C(query) instead of C(lookup),
|
||||||
over which you can iterate later on.
|
which will result in the record values being returned as a list over which you can iterate later on.
|
||||||
- By default, the lookup will rely on system-wide configured DNS servers for performing the query.
|
- By default, the lookup will rely on system-wide configured DNS servers for performing the query.
|
||||||
It is also possible to explicitly specify DNS servers to query using the @DNS_SERVER_1,DNS_SERVER_2,...,DNS_SERVER_N notation.
|
It is also possible to explicitly specify DNS servers to query using the @DNS_SERVER_1,DNS_SERVER_2,...,DNS_SERVER_N notation.
|
||||||
This needs to be passed-in as an additional parameter to the lookup
|
This needs to be passed-in as an additional parameter to the lookup
|
||||||
options:
|
options:
|
||||||
_terms:
|
_terms:
|
||||||
description: Domain(s) to query.
|
description: Domain(s) to query.
|
||||||
|
type: list
|
||||||
|
elements: str
|
||||||
qtype:
|
qtype:
|
||||||
description:
|
description:
|
||||||
- Record type to query.
|
- Record type to query.
|
||||||
- C(DLV) has been removed in community.general 6.0.0.
|
- C(DLV) has been removed in community.general 6.0.0.
|
||||||
|
type: str
|
||||||
default: 'A'
|
default: 'A'
|
||||||
choices: [A, ALL, AAAA, CNAME, DNAME, DNSKEY, DS, HINFO, LOC, MX, NAPTR, NS, NSEC3PARAM, PTR, RP, RRSIG, SOA, SPF, SRV, SSHFP, TLSA, TXT]
|
choices: [A, ALL, AAAA, CNAME, DNAME, DNSKEY, DS, HINFO, LOC, MX, NAPTR, NS, NSEC3PARAM, PTR, RP, RRSIG, SOA, SPF, SRV, SSHFP, TLSA, TXT]
|
||||||
flat:
|
flat:
|
||||||
description: If 0 each record is returned as a dictionary, otherwise a string.
|
description: If 0 each record is returned as a dictionary, otherwise a string.
|
||||||
|
type: int
|
||||||
default: 1
|
default: 1
|
||||||
retry_servfail:
|
retry_servfail:
|
||||||
description: Retry a nameserver if it returns SERVFAIL.
|
description: Retry a nameserver if it returns SERVFAIL.
|
||||||
|
@ -59,6 +63,11 @@ DOCUMENTATION = '''
|
||||||
default: false
|
default: false
|
||||||
type: bool
|
type: bool
|
||||||
version_added: 6.0.0
|
version_added: 6.0.0
|
||||||
|
class:
|
||||||
|
description:
|
||||||
|
- "Class."
|
||||||
|
type: str
|
||||||
|
default: 'IN'
|
||||||
notes:
|
notes:
|
||||||
- ALL is not a record per-se, merely the listed fields are available for any record results you retrieve in the form of a dictionary.
|
- ALL is not a record per-se, merely the listed fields are available for any record results you retrieve in the form of a dictionary.
|
||||||
- While the 'dig' lookup plugin supports anything which dnspython supports out of the box, only a subset can be converted into a dictionary.
|
- While the 'dig' lookup plugin supports anything which dnspython supports out of the box, only a subset can be converted into a dictionary.
|
||||||
|
@ -74,7 +83,7 @@ EXAMPLES = """
|
||||||
|
|
||||||
- name: "The TXT record for example.org."
|
- name: "The TXT record for example.org."
|
||||||
ansible.builtin.debug:
|
ansible.builtin.debug:
|
||||||
msg: "{{ lookup('community.general.dig', 'example.org.', 'qtype=TXT') }}"
|
msg: "{{ lookup('community.general.dig', 'example.org.', qtype='TXT') }}"
|
||||||
|
|
||||||
- name: "The TXT record for example.org, alternative syntax."
|
- name: "The TXT record for example.org, alternative syntax."
|
||||||
ansible.builtin.debug:
|
ansible.builtin.debug:
|
||||||
|
@ -83,24 +92,24 @@ EXAMPLES = """
|
||||||
- name: use in a loop
|
- name: use in a loop
|
||||||
ansible.builtin.debug:
|
ansible.builtin.debug:
|
||||||
msg: "MX record for gmail.com {{ item }}"
|
msg: "MX record for gmail.com {{ item }}"
|
||||||
with_items: "{{ lookup('community.general.dig', 'gmail.com./MX', wantlist=True) }}"
|
with_items: "{{ lookup('community.general.dig', 'gmail.com./MX', wantlist=true) }}"
|
||||||
|
|
||||||
- ansible.builtin.debug:
|
- ansible.builtin.debug:
|
||||||
msg: "Reverse DNS for 192.0.2.5 is {{ lookup('community.general.dig', '192.0.2.5/PTR') }}"
|
msg: "Reverse DNS for 192.0.2.5 is {{ lookup('community.general.dig', '192.0.2.5/PTR') }}"
|
||||||
- ansible.builtin.debug:
|
- ansible.builtin.debug:
|
||||||
msg: "Reverse DNS for 192.0.2.5 is {{ lookup('community.general.dig', '5.2.0.192.in-addr.arpa./PTR') }}"
|
msg: "Reverse DNS for 192.0.2.5 is {{ lookup('community.general.dig', '5.2.0.192.in-addr.arpa./PTR') }}"
|
||||||
- ansible.builtin.debug:
|
- ansible.builtin.debug:
|
||||||
msg: "Reverse DNS for 192.0.2.5 is {{ lookup('community.general.dig', '5.2.0.192.in-addr.arpa.', 'qtype=PTR') }}"
|
msg: "Reverse DNS for 192.0.2.5 is {{ lookup('community.general.dig', '5.2.0.192.in-addr.arpa.', qtype='PTR') }}"
|
||||||
- ansible.builtin.debug:
|
- ansible.builtin.debug:
|
||||||
msg: "Querying 198.51.100.23 for IPv4 address for example.com. produces {{ lookup('dig', 'example.com', '@198.51.100.23') }}"
|
msg: "Querying 198.51.100.23 for IPv4 address for example.com. produces {{ lookup('dig', 'example.com', '@198.51.100.23') }}"
|
||||||
|
|
||||||
- ansible.builtin.debug:
|
- ansible.builtin.debug:
|
||||||
msg: "XMPP service for gmail.com. is available at {{ item.target }} on port {{ item.port }}"
|
msg: "XMPP service for gmail.com. is available at {{ item.target }} on port {{ item.port }}"
|
||||||
with_items: "{{ lookup('community.general.dig', '_xmpp-server._tcp.gmail.com./SRV', 'flat=0', wantlist=True) }}"
|
with_items: "{{ lookup('community.general.dig', '_xmpp-server._tcp.gmail.com./SRV', flat=0, wantlist=true) }}"
|
||||||
|
|
||||||
- name: Retry nameservers that return SERVFAIL
|
- name: Retry nameservers that return SERVFAIL
|
||||||
ansible.builtin.debug:
|
ansible.builtin.debug:
|
||||||
msg: "{{ lookup('community.general.dig', 'example.org./A', 'retry_servfail=True') }}"
|
msg: "{{ lookup('community.general.dig', 'example.org./A', retry_servfail=true) }}"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
RETURN = """
|
RETURN = """
|
||||||
|
@ -279,21 +288,26 @@ class LookupModule(LookupBase):
|
||||||
|
|
||||||
... flat=0 # returns a dict; default is 1 == string
|
... flat=0 # returns a dict; default is 1 == string
|
||||||
'''
|
'''
|
||||||
|
|
||||||
if HAVE_DNS is False:
|
if HAVE_DNS is False:
|
||||||
raise AnsibleError("The dig lookup requires the python 'dnspython' library and it is not installed")
|
raise AnsibleError("The dig lookup requires the python 'dnspython' library and it is not installed")
|
||||||
|
|
||||||
|
self.set_options(var_options=variables, direct=kwargs)
|
||||||
|
|
||||||
# Create Resolver object so that we can set NS if necessary
|
# Create Resolver object so that we can set NS if necessary
|
||||||
myres = dns.resolver.Resolver(configure=True)
|
myres = dns.resolver.Resolver(configure=True)
|
||||||
edns_size = 4096
|
edns_size = 4096
|
||||||
myres.use_edns(0, ednsflags=dns.flags.DO, payload=edns_size)
|
myres.use_edns(0, ednsflags=dns.flags.DO, payload=edns_size)
|
||||||
|
|
||||||
domain = None
|
domain = None
|
||||||
qtype = 'A'
|
qtype = self.get_option('qtype')
|
||||||
flat = True
|
flat = self.get_option('flat')
|
||||||
fail_on_error = False
|
fail_on_error = self.get_option('fail_on_error')
|
||||||
real_empty = False
|
real_empty = self.get_option('real_empty')
|
||||||
rdclass = dns.rdataclass.from_text('IN')
|
try:
|
||||||
|
rdclass = dns.rdataclass.from_text(self.get_option('class'))
|
||||||
|
except Exception as e:
|
||||||
|
raise AnsibleError("dns lookup illegal CLASS: %s" % to_native(e))
|
||||||
|
myres.retry_servfail = self.get_option('retry_servfail')
|
||||||
|
|
||||||
for t in terms:
|
for t in terms:
|
||||||
if t.startswith('@'): # e.g. "@10.0.1.2,192.0.2.1" is ok.
|
if t.startswith('@'): # e.g. "@10.0.1.2,192.0.2.1" is ok.
|
||||||
|
@ -316,7 +330,7 @@ class LookupModule(LookupBase):
|
||||||
continue
|
continue
|
||||||
if '=' in t:
|
if '=' in t:
|
||||||
try:
|
try:
|
||||||
opt, arg = t.split('=')
|
opt, arg = t.split('=', 1)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,7 @@ from ansible.plugins.lookup import LookupBase
|
||||||
class LookupModule(LookupBase):
|
class LookupModule(LookupBase):
|
||||||
|
|
||||||
def run(self, terms, variables=None, **kwargs):
|
def run(self, terms, variables=None, **kwargs):
|
||||||
|
self.set_options(var_options=variables, direct=kwargs)
|
||||||
|
|
||||||
if HAVE_DNS is False:
|
if HAVE_DNS is False:
|
||||||
raise AnsibleError("Can't LOOKUP(dnstxt): module dns.resolver is not installed")
|
raise AnsibleError("Can't LOOKUP(dnstxt): module dns.resolver is not installed")
|
||||||
|
|
|
@ -201,6 +201,8 @@ def file_props(root, path):
|
||||||
class LookupModule(LookupBase):
|
class LookupModule(LookupBase):
|
||||||
|
|
||||||
def run(self, terms, variables=None, **kwargs):
|
def run(self, terms, variables=None, **kwargs):
|
||||||
|
self.set_options(var_options=variables, direct=kwargs)
|
||||||
|
|
||||||
basedir = self.get_basedir(variables)
|
basedir = self.get_basedir(variables)
|
||||||
|
|
||||||
ret = []
|
ret = []
|
||||||
|
|
|
@ -11,14 +11,17 @@ DOCUMENTATION = '''
|
||||||
author: Serge van Ginderachter (!UNKNOWN) <serge@vanginderachter.be>
|
author: Serge van Ginderachter (!UNKNOWN) <serge@vanginderachter.be>
|
||||||
short_description: return single list completely flattened
|
short_description: return single list completely flattened
|
||||||
description:
|
description:
|
||||||
- given one or more lists, this lookup will flatten any list elements found recursively until only 1 list is left.
|
- Given one or more lists, this lookup will flatten any list elements found recursively until only 1 list is left.
|
||||||
options:
|
options:
|
||||||
_terms:
|
_terms:
|
||||||
description: lists to flatten
|
description: lists to flatten
|
||||||
|
type: list
|
||||||
|
elements: raw
|
||||||
required: true
|
required: true
|
||||||
notes:
|
notes:
|
||||||
- unlike 'items' which only flattens 1 level, this plugin will continue to flatten until it cannot find lists anymore.
|
- Unlike the R(items lookup,ansible_collections.ansible.builtin.items_lookup) which only flattens 1 level,
|
||||||
- aka highlander plugin, there can only be one (list).
|
this plugin will continue to flatten until it cannot find lists anymore.
|
||||||
|
- Aka highlander plugin, there can only be one (list).
|
||||||
'''
|
'''
|
||||||
|
|
||||||
EXAMPLES = """
|
EXAMPLES = """
|
||||||
|
@ -78,9 +81,10 @@ class LookupModule(LookupBase):
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def run(self, terms, variables, **kwargs):
|
def run(self, terms, variables=None, **kwargs):
|
||||||
|
|
||||||
if not isinstance(terms, list):
|
if not isinstance(terms, list):
|
||||||
raise AnsibleError("with_flattened expects a list")
|
raise AnsibleError("with_flattened expects a list")
|
||||||
|
|
||||||
|
self.set_options(var_options=variables, direct=kwargs)
|
||||||
|
|
||||||
return self._do_flatten(terms, variables)
|
return self._do_flatten(terms, variables)
|
||||||
|
|
|
@ -14,23 +14,23 @@ DOCUMENTATION = '''
|
||||||
requirements:
|
requirements:
|
||||||
- hiera (command line utility)
|
- hiera (command line utility)
|
||||||
description:
|
description:
|
||||||
- Retrieves data from an Puppetmaster node using Hiera as ENC
|
- Retrieves data from an Puppetmaster node using Hiera as ENC.
|
||||||
options:
|
options:
|
||||||
_hiera_key:
|
_terms:
|
||||||
description:
|
description:
|
||||||
- The list of keys to lookup on the Puppetmaster
|
- The list of keys to lookup on the Puppetmaster.
|
||||||
type: list
|
type: list
|
||||||
elements: string
|
elements: string
|
||||||
required: true
|
required: true
|
||||||
_bin_file:
|
executable:
|
||||||
description:
|
description:
|
||||||
- Binary file to execute Hiera
|
- Binary file to execute Hiera.
|
||||||
default: '/usr/bin/hiera'
|
default: '/usr/bin/hiera'
|
||||||
env:
|
env:
|
||||||
- name: ANSIBLE_HIERA_BIN
|
- name: ANSIBLE_HIERA_BIN
|
||||||
_hierarchy_file:
|
config_file:
|
||||||
description:
|
description:
|
||||||
- File that describes the hierarchy of Hiera
|
- File that describes the hierarchy of Hiera.
|
||||||
default: '/etc/hiera.yaml'
|
default: '/etc/hiera.yaml'
|
||||||
env:
|
env:
|
||||||
- name: ANSIBLE_HIERA_CFG
|
- name: ANSIBLE_HIERA_CFG
|
||||||
|
@ -67,25 +67,28 @@ from ansible.plugins.lookup import LookupBase
|
||||||
from ansible.utils.cmd_functions import run_cmd
|
from ansible.utils.cmd_functions import run_cmd
|
||||||
from ansible.module_utils.common.text.converters import to_text
|
from ansible.module_utils.common.text.converters import to_text
|
||||||
|
|
||||||
ANSIBLE_HIERA_CFG = os.getenv('ANSIBLE_HIERA_CFG', '/etc/hiera.yaml')
|
|
||||||
ANSIBLE_HIERA_BIN = os.getenv('ANSIBLE_HIERA_BIN', '/usr/bin/hiera')
|
|
||||||
|
|
||||||
|
|
||||||
class Hiera(object):
|
class Hiera(object):
|
||||||
|
def __init__(self, hiera_cfg, hiera_bin):
|
||||||
|
self.hiera_cfg = hiera_cfg
|
||||||
|
self.hiera_bin = hiera_bin
|
||||||
|
|
||||||
def get(self, hiera_key):
|
def get(self, hiera_key):
|
||||||
pargs = [ANSIBLE_HIERA_BIN]
|
pargs = [self.hiera_bin]
|
||||||
pargs.extend(['-c', ANSIBLE_HIERA_CFG])
|
pargs.extend(['-c', self.hiera_cfg])
|
||||||
|
|
||||||
pargs.extend(hiera_key)
|
pargs.extend(hiera_key)
|
||||||
|
|
||||||
rc, output, err = run_cmd("{0} -c {1} {2}".format(
|
rc, output, err = run_cmd("{0} -c {1} {2}".format(
|
||||||
ANSIBLE_HIERA_BIN, ANSIBLE_HIERA_CFG, hiera_key[0]))
|
self.hiera_bin, self.hiera_cfg, hiera_key[0]))
|
||||||
|
|
||||||
return to_text(output.strip())
|
return to_text(output.strip())
|
||||||
|
|
||||||
|
|
||||||
class LookupModule(LookupBase):
|
class LookupModule(LookupBase):
|
||||||
def run(self, terms, variables=''):
|
def run(self, terms, variables=None, **kwargs):
|
||||||
hiera = Hiera()
|
self.set_options(var_options=variables, direct=kwargs)
|
||||||
|
|
||||||
|
hiera = Hiera(self.get_option('config_file'), self.get_option('executable'))
|
||||||
ret = [hiera.get(terms)]
|
ret = [hiera.get(terms)]
|
||||||
return ret
|
return ret
|
||||||
|
|
|
@ -26,7 +26,9 @@ EXAMPLES = """
|
||||||
- 'servicename username'
|
- 'servicename username'
|
||||||
|
|
||||||
- name: access mysql with password from keyring
|
- name: access mysql with password from keyring
|
||||||
mysql_db: login_password={{lookup('community.general.keyring','mysql joe')}} login_user=joe
|
community.mysql.mysql_db:
|
||||||
|
login_password: "{{ lookup('community.general.keyring', 'mysql joe') }}"
|
||||||
|
login_user: joe
|
||||||
"""
|
"""
|
||||||
|
|
||||||
RETURN = """
|
RETURN = """
|
||||||
|
@ -53,10 +55,12 @@ display = Display()
|
||||||
|
|
||||||
class LookupModule(LookupBase):
|
class LookupModule(LookupBase):
|
||||||
|
|
||||||
def run(self, terms, **kwargs):
|
def run(self, terms, variables=None, **kwargs):
|
||||||
if not HAS_KEYRING:
|
if not HAS_KEYRING:
|
||||||
raise AnsibleError(u"Can't LOOKUP(keyring): missing required python library 'keyring'")
|
raise AnsibleError(u"Can't LOOKUP(keyring): missing required python library 'keyring'")
|
||||||
|
|
||||||
|
self.set_options(var_options=variables, direct=kwargs)
|
||||||
|
|
||||||
display.vvvv(u"keyring: %s" % keyring.get_keyring())
|
display.vvvv(u"keyring: %s" % keyring.get_keyring())
|
||||||
ret = []
|
ret = []
|
||||||
for term in terms:
|
for term in terms:
|
||||||
|
|
|
@ -13,15 +13,20 @@ DOCUMENTATION = '''
|
||||||
version_added: '0.2.0'
|
version_added: '0.2.0'
|
||||||
short_description: fetch data from LMDB
|
short_description: fetch data from LMDB
|
||||||
description:
|
description:
|
||||||
- This lookup returns a list of results from an LMDB DB corresponding to a list of items given to it
|
- This lookup returns a list of results from an LMDB DB corresponding to a list of items given to it.
|
||||||
requirements:
|
requirements:
|
||||||
- lmdb (python library https://lmdb.readthedocs.io/en/release/)
|
- lmdb (python library https://lmdb.readthedocs.io/en/release/)
|
||||||
options:
|
options:
|
||||||
_terms:
|
_terms:
|
||||||
description: list of keys to query
|
description: List of keys to query.
|
||||||
|
type: list
|
||||||
|
elements: str
|
||||||
db:
|
db:
|
||||||
description: path to LMDB database
|
description: Path to LMDB database.
|
||||||
|
type: str
|
||||||
default: 'ansible.mdb'
|
default: 'ansible.mdb'
|
||||||
|
vars:
|
||||||
|
- name: lmdb_kv_db
|
||||||
'''
|
'''
|
||||||
|
|
||||||
EXAMPLES = """
|
EXAMPLES = """
|
||||||
|
@ -43,8 +48,8 @@ EXAMPLES = """
|
||||||
- item == 'Belgium'
|
- item == 'Belgium'
|
||||||
vars:
|
vars:
|
||||||
- lmdb_kv_db: jp.mdb
|
- lmdb_kv_db: jp.mdb
|
||||||
with_community.general.lmdb_kv:
|
with_community.general.lmdb_kv:
|
||||||
- be
|
- be
|
||||||
"""
|
"""
|
||||||
|
|
||||||
RETURN = """
|
RETURN = """
|
||||||
|
@ -58,6 +63,7 @@ _raw:
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.plugins.lookup import LookupBase
|
from ansible.plugins.lookup import LookupBase
|
||||||
from ansible.module_utils.common.text.converters import to_native, to_text
|
from ansible.module_utils.common.text.converters import to_native, to_text
|
||||||
|
|
||||||
HAVE_LMDB = True
|
HAVE_LMDB = True
|
||||||
try:
|
try:
|
||||||
import lmdb
|
import lmdb
|
||||||
|
@ -67,8 +73,7 @@ except ImportError:
|
||||||
|
|
||||||
class LookupModule(LookupBase):
|
class LookupModule(LookupBase):
|
||||||
|
|
||||||
def run(self, terms, variables, **kwargs):
|
def run(self, terms, variables=None, **kwargs):
|
||||||
|
|
||||||
'''
|
'''
|
||||||
terms contain any number of keys to be retrieved.
|
terms contain any number of keys to be retrieved.
|
||||||
If terms is None, all keys from the database are returned
|
If terms is None, all keys from the database are returned
|
||||||
|
@ -81,17 +86,15 @@ class LookupModule(LookupBase):
|
||||||
vars:
|
vars:
|
||||||
- lmdb_kv_db: "jp.mdb"
|
- lmdb_kv_db: "jp.mdb"
|
||||||
'''
|
'''
|
||||||
|
|
||||||
if HAVE_LMDB is False:
|
if HAVE_LMDB is False:
|
||||||
raise AnsibleError("Can't LOOKUP(lmdb_kv): this module requires lmdb to be installed")
|
raise AnsibleError("Can't LOOKUP(lmdb_kv): this module requires lmdb to be installed")
|
||||||
|
|
||||||
db = variables.get('lmdb_kv_db', None)
|
self.set_options(var_options=variables, direct=kwargs)
|
||||||
if db is None:
|
|
||||||
db = kwargs.get('db', 'ansible.mdb')
|
db = self.get_option('db')
|
||||||
db = str(db)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
env = lmdb.open(db, readonly=True)
|
env = lmdb.open(str(db), readonly=True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise AnsibleError("LMDB can't open database %s: %s" % (db, to_native(e)))
|
raise AnsibleError("LMDB can't open database %s: %s" % (db, to_native(e)))
|
||||||
|
|
||||||
|
|
|
@ -207,7 +207,7 @@ class ManifoldApiClient(object):
|
||||||
|
|
||||||
class LookupModule(LookupBase):
|
class LookupModule(LookupBase):
|
||||||
|
|
||||||
def run(self, terms, variables=None, api_token=None, project=None, team=None):
|
def run(self, terms, variables=None, **kwargs):
|
||||||
"""
|
"""
|
||||||
:param terms: a list of resources lookups to run.
|
:param terms: a list of resources lookups to run.
|
||||||
:param variables: ansible variables active at the time of the lookup
|
:param variables: ansible variables active at the time of the lookup
|
||||||
|
@ -217,10 +217,11 @@ class LookupModule(LookupBase):
|
||||||
:return: a dictionary of resources credentials
|
:return: a dictionary of resources credentials
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not api_token:
|
self.set_options(var_options=variables, direct=kwargs)
|
||||||
api_token = os.getenv('MANIFOLD_API_TOKEN')
|
|
||||||
if not api_token:
|
api_token = self.get_option('api_token')
|
||||||
raise AnsibleError('API token is required. Please set api_token parameter or MANIFOLD_API_TOKEN env var')
|
project = self.get_option('project')
|
||||||
|
team = self.get_option('team')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
labels = terms
|
labels = terms
|
||||||
|
|
|
@ -14,23 +14,24 @@ DOCUMENTATION = '''
|
||||||
- Read keys from Python shelve file.
|
- Read keys from Python shelve file.
|
||||||
options:
|
options:
|
||||||
_terms:
|
_terms:
|
||||||
description: sets of key value pairs of parameters
|
description: Sets of key value pairs of parameters.
|
||||||
key:
|
key:
|
||||||
description: key to query
|
description: Key to query.
|
||||||
required: true
|
required: true
|
||||||
file:
|
file:
|
||||||
description: path to shelve file
|
description: Path to shelve file.
|
||||||
required: true
|
required: true
|
||||||
'''
|
'''
|
||||||
|
|
||||||
EXAMPLES = """
|
EXAMPLES = """
|
||||||
- name: retrieve a string value corresponding to a key inside a Python shelve file
|
- name: Retrieve a string value corresponding to a key inside a Python shelve file
|
||||||
ansible.builtin.debug: msg="{{ lookup('community.general.shelvefile', 'file=path_to_some_shelve_file.db key=key_to_retrieve') }}
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ lookup('community.general.shelvefile', 'file=path_to_some_shelve_file.db key=key_to_retrieve') }}"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
RETURN = """
|
RETURN = """
|
||||||
_list:
|
_list:
|
||||||
description: value(s) of key(s) in shelve file(s)
|
description: Value(s) of key(s) in shelve file(s).
|
||||||
type: list
|
type: list
|
||||||
elements: str
|
elements: str
|
||||||
"""
|
"""
|
||||||
|
@ -53,7 +54,6 @@ class LookupModule(LookupBase):
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def run(self, terms, variables=None, **kwargs):
|
def run(self, terms, variables=None, **kwargs):
|
||||||
|
|
||||||
if not isinstance(terms, list):
|
if not isinstance(terms, list):
|
||||||
terms = [terms]
|
terms = [terms]
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
- hosts: localhost
|
- hosts: localhost
|
||||||
tasks:
|
tasks:
|
||||||
- debug:
|
- debug:
|
||||||
msg: '{{ query(''community.general.lmdb_kv'', ''nl'', ''be'', ''lu'', db=''jp.mdb'') }}'
|
msg: '{{ query("community.general.lmdb_kv", "nl", "be", "lu", db="jp.mdb") }}'
|
||||||
- debug:
|
- debug:
|
||||||
var: item.1
|
var: item.1
|
||||||
loop: '{{ query(''community.general.lmdb_kv'', db=''jp.mdb'') }}'
|
loop: '{{ query("community.general.lmdb_kv", db="jp.mdb") }}'
|
||||||
- assert:
|
- assert:
|
||||||
that:
|
that:
|
||||||
- query('community.general.lmdb_kv', 'nl', 'be', 'lu', db='jp.mdb') == ['Netherlands', 'Belgium', 'Luxembourg']
|
- query('community.general.lmdb_kv', 'nl', 'be', 'lu', db='jp.mdb') == ['Netherlands', 'Belgium', 'Luxembourg']
|
||||||
|
|
|
@ -11,8 +11,10 @@ from ansible.errors import AnsibleError
|
||||||
from ansible.module_utils.urls import ConnectionError, SSLValidationError
|
from ansible.module_utils.urls import ConnectionError, SSLValidationError
|
||||||
from ansible.module_utils.six.moves.urllib.error import HTTPError, URLError
|
from ansible.module_utils.six.moves.urllib.error import HTTPError, URLError
|
||||||
from ansible.module_utils import six
|
from ansible.module_utils import six
|
||||||
|
from ansible.plugins.loader import lookup_loader
|
||||||
from ansible_collections.community.general.plugins.lookup.manifold import ManifoldApiClient, LookupModule, ApiError
|
from ansible_collections.community.general.plugins.lookup.manifold import ManifoldApiClient, LookupModule, ApiError
|
||||||
import json
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
API_FIXTURES = {
|
API_FIXTURES = {
|
||||||
|
@ -375,8 +377,7 @@ class TestManifoldApiClient(unittest.TestCase):
|
||||||
|
|
||||||
class TestLookupModule(unittest.TestCase):
|
class TestLookupModule(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.lookup = LookupModule()
|
self.lookup = lookup_loader.get('community.general.manifold')
|
||||||
self.lookup._load_name = "manifold"
|
|
||||||
|
|
||||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.ManifoldApiClient')
|
@patch('ansible_collections.community.general.plugins.lookup.manifold.ManifoldApiClient')
|
||||||
def test_get_all(self, client_mock):
|
def test_get_all(self, client_mock):
|
||||||
|
@ -515,23 +516,22 @@ class TestLookupModule(unittest.TestCase):
|
||||||
self.lookup.run([], api_token='token-123')
|
self.lookup.run([], api_token='token-123')
|
||||||
self.assertTrue('Exception: Unknown error' in str(context.exception))
|
self.assertTrue('Exception: Unknown error' in str(context.exception))
|
||||||
|
|
||||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.os.getenv')
|
|
||||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.ManifoldApiClient')
|
@patch('ansible_collections.community.general.plugins.lookup.manifold.ManifoldApiClient')
|
||||||
def test_falls_back_to_env_var(self, client_mock, getenv_mock):
|
def test_falls_back_to_env_var(self, client_mock):
|
||||||
getenv_mock.return_value = 'token-321'
|
|
||||||
client_mock.return_value.get_resources.return_value = []
|
client_mock.return_value.get_resources.return_value = []
|
||||||
client_mock.return_value.get_credentials.return_value = []
|
client_mock.return_value.get_credentials.return_value = []
|
||||||
self.lookup.run([])
|
try:
|
||||||
getenv_mock.assert_called_with('MANIFOLD_API_TOKEN')
|
os.environ['MANIFOLD_API_TOKEN'] = 'token-321'
|
||||||
|
self.lookup.run([])
|
||||||
|
finally:
|
||||||
|
os.environ.pop('MANIFOLD_API_TOKEN', None)
|
||||||
client_mock.assert_called_with('token-321')
|
client_mock.assert_called_with('token-321')
|
||||||
|
|
||||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.os.getenv')
|
|
||||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.ManifoldApiClient')
|
@patch('ansible_collections.community.general.plugins.lookup.manifold.ManifoldApiClient')
|
||||||
def test_falls_raises_on_no_token(self, client_mock, getenv_mock):
|
def test_falls_raises_on_no_token(self, client_mock):
|
||||||
getenv_mock.return_value = None
|
|
||||||
client_mock.return_value.get_resources.return_value = []
|
client_mock.return_value.get_resources.return_value = []
|
||||||
client_mock.return_value.get_credentials.return_value = []
|
client_mock.return_value.get_credentials.return_value = []
|
||||||
|
os.environ.pop('MANIFOLD_API_TOKEN', None)
|
||||||
with self.assertRaises(AnsibleError) as context:
|
with self.assertRaises(AnsibleError) as context:
|
||||||
self.lookup.run([])
|
self.lookup.run([])
|
||||||
self.assertEqual('API token is required. Please set api_token parameter or MANIFOLD_API_TOKEN env var',
|
assert 'api_token' in str(context.exception)
|
||||||
str(context.exception))
|
|
||||||
|
|
Loading…
Reference in a new issue