From 6fae1d2bbfa1086e4fc18e95acac96f98d838480 Mon Sep 17 00:00:00 2001
From: Michael Scherer <misc@zarb.org>
Date: Tue, 27 Sep 2016 23:31:21 +0200
Subject: [PATCH] Make password lookup treat /dev/null as a special case

I have from time to time a need of random password without
wanting to write them down (one example is mailman list creation,
that requires a password to be given to be sent to the list owner).

But using /dev/null do not return null, but the empty string, which
doesn't generate a password at all and so do not achieve my use case.
---
 docs/docsite/rst/playbooks_lookups.rst          |  3 +++
 lib/ansible/plugins/lookup/password.py          |  5 +++--
 test/integration/targets/lookups/tasks/main.yml | 12 ++++++++++++
 3 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/docs/docsite/rst/playbooks_lookups.rst b/docs/docsite/rst/playbooks_lookups.rst
index fa6c45db10a..d9b8c33994b 100644
--- a/docs/docsite/rst/playbooks_lookups.rst
+++ b/docs/docsite/rst/playbooks_lookups.rst
@@ -52,6 +52,9 @@ a file at a given filepath.
 If the file exists previously, it will retrieve its contents, behaving just like with_file. Usage of variables like "{{ inventory_hostname }}" in the filepath can be used to set
 up random passwords per host (which simplifies password management in 'host_vars' variables).
 
+A special case is using ``/dev/null`` as a path. The password lookup will generate a new random password each time, but will not write it to ``/dev/null``. This can be used when you need a password
+without storing it on the controller.
+
 Generated passwords contain a random mix of upper and lowercase ASCII letters, the
 numbers 0-9 and punctuation (". , : - _"). The default length of a generated password is 20 characters.
 This length can be changed by passing an extra parameter::
diff --git a/lib/ansible/plugins/lookup/password.py b/lib/ansible/plugins/lookup/password.py
index bbc75e1145f..d9c10e6c2d0 100644
--- a/lib/ansible/plugins/lookup/password.py
+++ b/lib/ansible/plugins/lookup/password.py
@@ -232,7 +232,8 @@ class LookupModule(LookupBase):
 
             changed = False
             content = _read_password_file(b_path)
-            if content is None:
+
+            if content is None or b_path == to_bytes('/dev/null'):
                 plaintext_password = _random_password(params['length'], chars)
                 salt = None
                 changed = True
@@ -243,7 +244,7 @@ class LookupModule(LookupBase):
                 changed = True
                 salt = _random_salt()
 
-            if changed:
+            if changed and b_path != to_bytes('/dev/null'):
                 content = _format_content(plaintext_password, salt, encrypt=params['encrypt'])
                 _write_password_file(b_path, content)
 
diff --git a/test/integration/targets/lookups/tasks/main.yml b/test/integration/targets/lookups/tasks/main.yml
index ddea035d1b2..9405770ddf3 100644
--- a/test/integration/targets/lookups/tasks/main.yml
+++ b/test/integration/targets/lookups/tasks/main.yml
@@ -134,6 +134,18 @@
     that:
         - "newpass == newpass2"
 
+- name: verify that we can generate a 1st password without writing it
+  set_fact:
+    newpass: "{{ lookup('password', '/dev/null') }}"
+
+- name: verify that we can generate a 2nd password without writing it
+  set_fact:
+    newpass2: "{{ lookup('password', '/dev/null') }}"
+
+- name: verify lookup password behavior with /dev/null
+  assert:
+    that:
+        - "newpass != newpass2"
 
 # ENV LOOKUP