1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

Add option missing to passwordstore lookup (#2500) (#2541)

Add ability to ignore error on missing pass file to allow processing the
output further via another filters (mainly the default filter) without
updating the pass file itself.

It also contains the option to create the pass file, like the option
create=true does.

Finally, it also allows to issue a warning only, if the pass file is not
found.

(cherry picked from commit 350380ba8c)

Co-authored-by: Jan Baier <7996094+baierjan@users.noreply.github.com>
This commit is contained in:
patchback[bot] 2021-05-17 14:14:44 +02:00 committed by GitHub
parent 42f28048a8
commit 38aa0ec8ad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 85 additions and 5 deletions

View file

@ -0,0 +1,3 @@
minor_changes:
- passwordstore lookup - add option ``missing`` to choose what to do if the password file is missing
(https://github.com/ansible-collections/community.general/pull/2500).

View file

@ -25,9 +25,9 @@ DOCUMENTATION = '''
env: env:
- name: PASSWORD_STORE_DIR - name: PASSWORD_STORE_DIR
create: create:
description: Create the password if it does not already exist. description: Create the password if it does not already exist. Takes precedence over C(missing).
type: bool type: bool
default: 'no' default: false
overwrite: overwrite:
description: Overwrite the password if it does already exist. description: Overwrite the password if it does already exist.
type: bool type: bool
@ -60,6 +60,22 @@ DOCUMENTATION = '''
description: use alphanumeric characters. description: use alphanumeric characters.
type: bool type: bool
default: 'no' default: 'no'
missing:
description:
- List of preference about what to do if the password file is missing.
- If I(create=true), the value for this option is ignored and assumed to be C(create).
- If set to C(error), the lookup will error out if the passname does not exist.
- If set to C(create), the passname will be created with the provided length I(length) if it does not exist.
- If set to C(empty) or C(warn), will return a C(none) in case the passname does not exist.
When using C(lookup) and not C(query), this will be translated to an empty string.
version_added: 3.1.0
type: str
default: error
choices:
- error
- warn
- empty
- create
''' '''
EXAMPLES = """ EXAMPLES = """
# Debug is used for examples, BAD IDEA to show passwords on screen # Debug is used for examples, BAD IDEA to show passwords on screen
@ -67,12 +83,28 @@ EXAMPLES = """
ansible.builtin.debug: ansible.builtin.debug:
msg: "{{ lookup('community.general.passwordstore', 'example/test')}}" msg: "{{ lookup('community.general.passwordstore', 'example/test')}}"
- name: Basic lookup. Warns if example/test does not exist and returns empty string
ansible.builtin.debug:
msg: "{{ lookup('community.general.passwordstore', 'example/test missing=warn')}}"
- name: Create pass with random 16 character password. If password exists just give the password - name: Create pass with random 16 character password. If password exists just give the password
ansible.builtin.debug: ansible.builtin.debug:
var: mypassword var: mypassword
vars: vars:
mypassword: "{{ lookup('community.general.passwordstore', 'example/test create=true')}}" mypassword: "{{ lookup('community.general.passwordstore', 'example/test create=true')}}"
- name: Create pass with random 16 character password. If password exists just give the password
ansible.builtin.debug:
var: mypassword
vars:
mypassword: "{{ lookup('community.general.passwordstore', 'example/test missing=create')}}"
- name: Prints 'abc' if example/test does not exist, just give the password otherwise
ansible.builtin.debug:
var: mypassword
vars:
mypassword: "{{ lookup('community.general.passwordstore', 'example/test missing=empty') | default('abc', true) }}"
- name: Different size password - name: Different size password
ansible.builtin.debug: ansible.builtin.debug:
msg: "{{ lookup('community.general.passwordstore', 'example/test create=true length=42')}}" msg: "{{ lookup('community.general.passwordstore', 'example/test create=true length=42')}}"
@ -111,10 +143,13 @@ import yaml
from distutils import util from distutils import util
from ansible.errors import AnsibleError, AnsibleAssertionError from ansible.errors import AnsibleError, AnsibleAssertionError
from ansible.module_utils._text import to_bytes, to_native, to_text from ansible.module_utils._text import to_bytes, to_native, to_text
from ansible.utils.display import Display
from ansible.utils.encrypt import random_password from ansible.utils.encrypt import random_password
from ansible.plugins.lookup import LookupBase from ansible.plugins.lookup import LookupBase
from ansible import constants as C from ansible import constants as C
display = Display()
# backhacked check_output with input for python 2.7 # backhacked check_output with input for python 2.7
# http://stackoverflow.com/questions/10103551/passing-data-to-subprocess-check-output # http://stackoverflow.com/questions/10103551/passing-data-to-subprocess-check-output
@ -178,12 +213,17 @@ class LookupModule(LookupBase):
self.paramvals[key] = util.strtobool(self.paramvals[key]) self.paramvals[key] = util.strtobool(self.paramvals[key])
except (ValueError, AssertionError) as e: except (ValueError, AssertionError) as e:
raise AnsibleError(e) raise AnsibleError(e)
if self.paramvals['missing'] not in ['error', 'warn', 'create', 'empty']:
raise AnsibleError("{0} is not a valid option for missing".format(self.paramvals['missing']))
if not isinstance(self.paramvals['length'], int): if not isinstance(self.paramvals['length'], int):
if self.paramvals['length'].isdigit(): if self.paramvals['length'].isdigit():
self.paramvals['length'] = int(self.paramvals['length']) self.paramvals['length'] = int(self.paramvals['length'])
else: else:
raise AnsibleError("{0} is not a correct value for length".format(self.paramvals['length'])) raise AnsibleError("{0} is not a correct value for length".format(self.paramvals['length']))
if self.paramvals['create']:
self.paramvals['missing'] = 'create'
# Collect pass environment variables from the plugin's parameters. # Collect pass environment variables from the plugin's parameters.
self.env = os.environ.copy() self.env = os.environ.copy()
@ -224,9 +264,11 @@ class LookupModule(LookupBase):
if e.returncode != 0 and 'not in the password store' in e.output: if e.returncode != 0 and 'not in the password store' in e.output:
# if pass returns 1 and return string contains 'is not in the password store.' # if pass returns 1 and return string contains 'is not in the password store.'
# We need to determine if this is valid or Error. # We need to determine if this is valid or Error.
if not self.paramvals['create']: if self.paramvals['missing'] == 'error':
raise AnsibleError('passname: {0} not found, use create=True'.format(self.passname)) raise AnsibleError('passwordstore: passname {0} not found and missing=error is set'.format(self.passname))
else: else:
if self.paramvals['missing'] == 'warn':
display.warning('passwordstore: passname {0} not found'.format(self.passname))
return False return False
else: else:
raise AnsibleError(e) raise AnsibleError(e)
@ -294,6 +336,7 @@ class LookupModule(LookupBase):
'userpass': '', 'userpass': '',
'length': 16, 'length': 16,
'backup': False, 'backup': False,
'missing': 'error',
} }
for term in terms: for term in terms:
@ -304,6 +347,9 @@ class LookupModule(LookupBase):
else: else:
result.append(self.get_passresult()) result.append(self.get_passresult())
else: # password does not exist else: # password does not exist
if self.paramvals['create']: if self.paramvals['missing'] == 'create':
result.append(self.generate_password()) result.append(self.generate_password())
else:
result.append(None)
return result return result

View file

@ -61,6 +61,37 @@
that: that:
- readpass == newpass - readpass == newpass
- name: Create a password using missing=create
set_fact:
newpass: "{{ lookup('community.general.passwordstore', 'test-missing-create missing=create length=8') }}"
- name: Fetch password from an existing file
set_fact:
readpass: "{{ lookup('community.general.passwordstore', 'test-missing-create') }}"
- name: Verify password
assert:
that:
- readpass == newpass
- name: Fetch password from existing file using missing=empty
set_fact:
readpass: "{{ lookup('community.general.passwordstore', 'test-missing-create missing=empty') }}"
- name: Verify password
assert:
that:
- readpass == newpass
- name: Fetch password from non-existing file using missing=empty
set_fact:
readpass: "{{ query('community.general.passwordstore', 'test-missing-pass missing=empty') }}"
- name: Verify password
assert:
that:
- readpass == [ none ]
# As inserting multiline passwords on the commandline would require something # As inserting multiline passwords on the commandline would require something
# like expect, simply create it by using default gpg on a file with the correct # like expect, simply create it by using default gpg on a file with the correct
# structure. # structure.