Repository: ansible/ansible

Issue:
Add ability to create OpenStack users without password

##### ISSUE TYPE
 - Feature Idea

##### COMPONENT NAME
ansible/lib/ansible/modules/cloud/openstack/os_user.py

##### ANSIBLE VERSION
```
ansible 2.4.0 (devel 34c0abd106) last updated 2017/07/12 18:04:47 (GMT -400)
  config file = None
  configured module search path = [u'/home/*/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /home/*/ansible/lib/ansible
  executable location = /home/*/ansible/bin/ansible
  python version = 2.7.5 (default, Nov  6 2016, 00:28:07) [GCC 4.8.5 20150623 (Red Hat 4.8.5-11)]
```

##### CONFIGURATION

##### OS / ENVIRONMENT
RHOSP11/OpenStack Ocata


##### SUMMARY
I can create users without password from the OpenStack CLI but ansible os_user requires to type a password. I need to create users without password because they authenticate with SAML and the password comes from outside Keystone.

##### STEPS TO REPRODUCE
In OpenStack I can do:
openstack user create --domain mydomin myuser
```
---
- name: create_users
  hosts: localhost
  tasks:
  - os_user:
      state: present
      name: myuser
      domain: mydomain
      #update_password: on_create  # this can be there or not, result is similar
```
##### EXPECTED RESULTS
Users are created correctly, without password.

##### ACTUAL RESULTS
```
ansible-playbook 2.4.0 (devel 34c0abd106) last updated 2017/07/12 18:04:47 (GMT -400)
  config file = None
  configured module search path = [u'/home/ma/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /home/ma/ansible/lib/ansible
  executable location = /home/ma/ansible/bin/ansible-playbook
  python version = 2.7.5 (default, Nov  6 2016, 00:28:07) [GCC 4.8.5 20150623 (Red Hat 4.8.5-11)]
No config file found; using defaults
setting up inventory plugins
 [WARNING]: No inventory was parsed, only implicit localhost is available

 [WARNING]: Could not match supplied host pattern, ignoring: all

 [WARNING]: provided hosts list is empty, only localhost is available

Loading callback plugin default of type stdout, v2.0 from /home/ma/ansible/lib/ansible/plugins/callback/__init__.pyc

PLAYBOOK: create_users.yml ****************************************************************************************************************************
1 plays in create_users.yml

PLAY [create_users] ***********************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/basic.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/__init__.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/namespace.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/ansible_collector.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/default_collectors.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/_text.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/pycompat24.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/six/__init__.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/six/_six.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/timeout.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/collector.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/network/freebsd.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/virtual/openbsd.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/network/base.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/hardware/dragonfly.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/network/dragonfly.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/hardware/aix.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/network/aix.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/hardware/linux.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/system/platform.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/hardware/hpux.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/system/user.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/hardware/hurd.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/other/facter.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/virtual/sunos.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/network/hpux.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/system/distribution.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/virtual/freebsd.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/system/__init__.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/network/openbsd.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/network/darwin.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/network/linux.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/hardware/sunos.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/network/sunos.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/system/apparmor.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/hardware/openbsd.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/system/local.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/other/ohai.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/other/__init__.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/system/service_mgr.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/network/hurd.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/virtual/hpux.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/system/fips.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/system/selinux.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/virtual/__init__.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/system/pkg_mgr.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/system/dns.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/virtual/base.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/hardware/darwin.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/virtual/dragonfly.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/system/ssh_pub_keys.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/network/__init__.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/hardware/__init__.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/system/lsb.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/system/date_time.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/virtual/netbsd.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/hardware/base.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/system/cmdline.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/hardware/freebsd.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/network/netbsd.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/hardware/netbsd.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/system/caps.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/system/env.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/virtual/linux.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/system/python.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/network/generic_bsd.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/virtual/sysctl.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/utils.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/facts/sysctl.py
Using module file /home/ma/ansible/lib/ansible/modules/system/setup.py
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: ma
<127.0.0.1> EXEC /bin/sh -c 'echo ~ && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /home/ma/.ansible/tmp/ansible-tmp-1499898537.33-111495189577713 `" && echo ansible-tmp-1499898537.33-111495189577713="` echo /home/ma/.ansible/tmp/ansible-tmp-1499898537.33-111495189577713 `" ) && sleep 0'
<127.0.0.1> PUT /tmp/tmpCwIexF TO /home/ma/.ansible/tmp/ansible-tmp-1499898537.33-111495189577713/setup.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /home/ma/.ansible/tmp/ansible-tmp-1499898537.33-111495189577713/ /home/ma/.ansible/tmp/ansible-tmp-1499898537.33-111495189577713/setup.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '/home/ma/myenv/bin/python /home/ma/.ansible/tmp/ansible-tmp-1499898537.33-111495189577713/setup.py; rm -rf "/home/ma/.ansible/tmp/ansible-tmp-1499898537.33-111495189577713/" > /dev/null 2>&1 && sleep 0'
ok: [localhost]
META: ran handlers

TASK [os_user] ****************************************************************************************************************************************
task path: /home/ma/ansible_manage/create_users.yml:6
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/basic.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/openstack.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/_text.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/pycompat24.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/six/__init__.py
Using module_utils file /home/ma/ansible/lib/ansible/module_utils/six/_six.py
Using module file /home/ma/ansible/lib/ansible/modules/cloud/openstack/os_user.py
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: ma
<127.0.0.1> EXEC /bin/sh -c 'echo ~ && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /home/ma/.ansible/tmp/ansible-tmp-1499898537.77-29861681347631 `" && echo ansible-tmp-1499898537.77-29861681347631="` echo /home/ma/.ansible/tmp/ansible-tmp-1499898537.77-29861681347631 `" ) && sleep 0'
<127.0.0.1> PUT /tmp/tmpg0RW_8 TO /home/ma/.ansible/tmp/ansible-tmp-1499898537.77-29861681347631/os_user.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /home/ma/.ansible/tmp/ansible-tmp-1499898537.77-29861681347631/ /home/ma/.ansible/tmp/ansible-tmp-1499898537.77-29861681347631/os_user.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '/home/ma/myenv/bin/python /home/ma/.ansible/tmp/ansible-tmp-1499898537.77-29861681347631/os_user.py; rm -rf "/home/ma/.ansible/tmp/ansible-tmp-1499898537.77-29861681347631/" > /dev/null 2>&1 && sleep 0'
fatal: [localhost]: FAILED! => {
    "changed": false, 
    "failed": true, 
    "invocation": {
        "module_args": {
            "api_timeout": null, 
            "auth": null, 
            "auth_type": null, 
            "availability_zone": null, 
            "cacert": null, 
            "cert": null, 
            "cloud": null, 
            "default_project": null, 
            "description": null, 
            "domain": "mydomain", 
            "email": null, 
            "enabled": true, 
            "endpoint_type": "public", 
            "key": null, 
            "name": "myuser", 
            "region_name": null, 
            "state": "present", 
            "timeout": 180, 
            "update_password": "on_create", 
            "verify": null, 
            "wait": true
        }
    }, 
    "msg": "update_password is on_create but a password value is missing"
}
	to retry, use: --limit @/home/ma/ansible_manage/create_users.retry

PLAY RECAP ********************************************************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=1   

```



Discussion:
cc @emonty @j2sol @juliakreger @rcarrillocruz @shrews @thingee
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
cc @dagnello
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->

Resolving patch:
diff --git a/lib/ansible/modules/cloud/openstack/os_user.py b/lib/ansible/modules/cloud/openstack/os_user.py
--- a/lib/ansible/modules/cloud/openstack/os_user.py
+++ b/lib/ansible/modules/cloud/openstack/os_user.py
@@ -33,7 +33,7 @@
      description:
         - Password for the user
    update_password:
-     default: always
+     required: false
      choices: ['always', 'on_create']
      version_added: "2.3"
      description:
@@ -97,6 +97,15 @@
     email: demo@example.com
     domain: default
     default_project: demo
+
+# Create a user without password
+- os_user:
+    cloud: mycloud
+    state: present
+    name: demouser
+    email: demo@example.com
+    domain: default
+    default_project: demo
 '''
 
 
@@ -181,7 +190,7 @@ def main():
         domain=dict(required=False, default=None),
         enabled=dict(default=True, type='bool'),
         state=dict(default='present', choices=['absent', 'present']),
-        update_password=dict(default='always', choices=['always', 'on_create']),
+        update_password=dict(default=None, choices=['always', 'on_create']),
     )
 
     module_kwargs = openstack_module_kwargs()


Test patch: