We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add update_password option to os_user module
<!--- Verify first that your issue/request is not already reported in GitHub -->
##### ISSUE TYPE

<!--- Pick one below and delete the rest: -->
- Feature Idea
##### COMPONENT NAME

<!--- Name of the plugin/module/task -->

os_user
##### ANSIBLE VERSION

<!--- Paste verbatim output from “ansible --version” between quotes below -->

```
$ ansible --version
ansible 2.1.2.0
```
##### CONFIGURATION

<!---
Mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->
##### OS / ENVIRONMENT

<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say “N/A” for anything that is not platform-specific.
-->

N/A
##### SUMMARY

<!--- Explain the problem briefly -->

The `os_user` module with a password specified for a user will always report 'changed'.
The conclusion of the bug report in #5183 was that in order to "fix" this we need to add another parameter like the on in the `user` module.
I.e a parameter called `update_password` that has options `on_create` or `always`.
##### STEPS TO REPRODUCE

<!---
For bugs, show exactly how to reproduce the problem.
For new features, show how the feature would be used.
-->

```
  - name: "Create test user"
    os_user:
      name: test
      state: present
      password: very-secret
      default_project: a-existing-project
      update_password: on_create
```
##### EXPECTED RESULTS

<!--- What did you expect to happen when running the steps above? -->

On first run, the user would be created and the password set.
On the second run, given that nothing changed, the task would say `ok`.
If the parameter would be `update_password: always` on the other hand, the module should always set the password and would always report `changed`


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `cloud/openstack/os_user.py`
Content:
```
1 #!/usr/bin/python
2 # Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
3 #
4 # This module is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
8 #
9 # This software is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this software.  If not, see <http://www.gnu.org/licenses/>.
16 
17 
18 try:
19     import shade
20     HAS_SHADE = True
21 except ImportError:
22     HAS_SHADE = False
23 
24 DOCUMENTATION = '''
25 ---
26 module: os_user
27 short_description: Manage OpenStack Identity Users
28 extends_documentation_fragment: openstack
29 version_added: "2.0"
30 description:
31     - Manage OpenStack Identity users. Users can be created,
32       updated or deleted using this module. A user will be updated
33       if I(name) matches an existing user and I(state) is present.
34       The value for I(name) cannot be updated without deleting and
35       re-creating the user.
36 options:
37    name:
38      description:
39         - Username for the user
40      required: true
41    password:
42      description:
43         - Password for the user
44      required: false
45      default: None
46    email:
47      description:
48         - Email address for the user
49      required: false
50      default: None
51    default_project:
52      description:
53         - Project name or ID that the user should be associated with by default
54      required: false
55      default: None
56    domain:
57      description:
58         - Domain to create the user in if the cloud supports domains
59      required: false
60      default: None
61    enabled:
62      description:
63         - Is the user enabled
64      required: false
65      default: True
66    state:
67      description:
68        - Should the resource be present or absent.
69      choices: [present, absent]
70      default: present
71 requirements:
72     - "python >= 2.6"
73     - "shade"
74 '''
75 
76 EXAMPLES = '''
77 # Create a user
78 - os_user:
79     cloud: mycloud
80     state: present
81     name: demouser
82     password: secret
83     email: demo@example.com
84     domain: default
85     default_project: demo
86 
87 # Delete a user
88 - os_user:
89     cloud: mycloud
90     state: absent
91     name: demouser
92 '''
93 
94 
95 RETURN = '''
96 user:
97     description: Dictionary describing the user.
98     returned: On success when I(state) is 'present'
99     type: dictionary
100     contains:
101         default_project_id:
102             description: User default project ID. Only present with Keystone >= v3.
103             type: string
104             sample: "4427115787be45f08f0ec22a03bfc735"
105         domain_id:
106             description: User domain ID. Only present with Keystone >= v3.
107             type: string
108             sample: "default"
109         email:
110             description: User email address
111             type: string
112             sample: "demo@example.com"
113         id:
114             description: User ID
115             type: string
116             sample: "f59382db809c43139982ca4189404650"
117         name:
118             description: User name
119             type: string
120             sample: "demouser"
121 '''
122 
123 def _needs_update(params_dict, user):
124     for k, v in params_dict.items():
125         if k != 'password' and user[k] != v:
126             return True
127 
128     # We don't get password back in the user object, so assume any supplied
129     # password is a change.
130     if params_dict['password'] is not None:
131         return True
132 
133     return False
134 
135 def _get_domain_id(cloud, domain):
136     try:
137         # We assume admin is passing domain id
138         domain_id = cloud.get_domain(domain)['id']
139     except:
140         # If we fail, maybe admin is passing a domain name.
141         # Note that domains have unique names, just like id.
142         try:
143             domain_id = cloud.search_domains(filters={'name': domain})[0]['id']
144         except:
145             # Ok, let's hope the user is non-admin and passing a sane id
146             domain_id = domain
147 
148     return domain_id
149 
150 def _get_default_project_id(cloud, default_project):
151     project = cloud.get_project(default_project)
152     if not project:
153         module.fail_json(msg='Default project %s is not valid' % default_project)
154 
155     return project['id']
156 
157 def main():
158 
159     argument_spec = openstack_full_argument_spec(
160         name=dict(required=True),
161         password=dict(required=False, default=None),
162         email=dict(required=False, default=None),
163         default_project=dict(required=False, default=None),
164         domain=dict(required=False, default=None),
165         enabled=dict(default=True, type='bool'),
166         state=dict(default='present', choices=['absent', 'present']),
167     )
168 
169     module_kwargs = openstack_module_kwargs()
170     module = AnsibleModule(
171         argument_spec,
172         **module_kwargs)
173 
174     if not HAS_SHADE:
175         module.fail_json(msg='shade is required for this module')
176 
177     name = module.params['name']
178     password = module.params['password']
179     email = module.params['email']
180     default_project = module.params['default_project']
181     domain = module.params['domain']
182     enabled = module.params['enabled']
183     state = module.params['state']
184 
185     try:
186         cloud = shade.openstack_cloud(**module.params)
187         user = cloud.get_user(name)
188 
189         domain_id = None
190         if domain:
191             opcloud = shade.operator_cloud(**module.params)
192             domain_id = _get_domain_id(opcloud, domain)
193 
194         if state == 'present':
195             default_project_id = None
196             if default_project:
197                 default_project_id = _get_default_project_id(cloud, default_project)
198 
199             if user is None:
200                 user = cloud.create_user(
201                     name=name, password=password, email=email,
202                     default_project=default_project_id, domain_id=domain_id,
203                     enabled=enabled)
204                 changed = True
205             else:
206                 params_dict = {'email': email, 'enabled': enabled, 'password': password}
207                 if domain_id is not None:
208                     params_dict['domain_id'] = domain_id
209                 if default_project_id is not None:
210                     params_dict['default_project_id'] = default_project_id
211 
212                 if _needs_update(params_dict, user):
213                     user = cloud.update_user(
214                         user['id'], password=password, email=email,
215                         default_project=default_project_id, domain_id=domain_id,
216                         enabled=enabled)
217                     changed = True
218                 else:
219                     changed = False
220             module.exit_json(changed=changed, user=user)
221 
222         elif state == 'absent':
223             if user is None:
224                 changed=False
225             else:
226                 cloud.delete_user(user['id'])
227                 changed=True
228             module.exit_json(changed=changed)
229 
230     except shade.OpenStackCloudException as e:
231         module.fail_json(msg=str(e), extra_data=e.extra_data)
232 
233 from ansible.module_utils.basic import *
234 from ansible.module_utils.openstack import *
235 
236 
237 if __name__ == '__main__':
238     main()
239
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/cloud/openstack/os_user.py b/cloud/openstack/os_user.py
--- a/cloud/openstack/os_user.py
+++ b/cloud/openstack/os_user.py
@@ -43,6 +43,14 @@
         - Password for the user
      required: false
      default: None
+   update_password:
+     required: false
+     default: always
+     choices: ['always', 'on_create']
+     version_added: "2.3"
+     description:
+        - C(always) will attempt to update password.  C(on_create) will only
+          set the password for newly created users.
    email:
      description:
         - Email address for the user
@@ -89,6 +97,17 @@
     cloud: mycloud
     state: absent
     name: demouser
+
+# Create a user but don't update password if user exists
+- os_user:
+    cloud: mycloud
+    state: present
+    name: demouser
+    password: secret
+    update_password: on_create
+    email: demo@example.com
+    domain: default
+    default_project: demo
 '''
 
 
@@ -122,12 +141,13 @@
 
 def _needs_update(params_dict, user):
     for k, v in params_dict.items():
-        if k != 'password' and user[k] != v:
+        if k not in ('password', 'update_password') and user[k] != v:
             return True
 
     # We don't get password back in the user object, so assume any supplied
     # password is a change.
-    if params_dict['password'] is not None:
+    if (params_dict['password'] is not None and
+            params_dict['update_password'] == 'always'):
         return True
 
     return False
@@ -164,11 +184,17 @@
         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']),
     )
 
     module_kwargs = openstack_module_kwargs()
     module = AnsibleModule(
         argument_spec,
+        required_if=[
+            ('update_password', 'always', ['password']),
+            ('update_password', 'on_create', ['password']),
+        ],
         **module_kwargs)
 
     if not HAS_SHADE:
@@ -181,6 +207,7 @@
     domain = module.params['domain']
     enabled = module.params['enabled']
     state = module.params['state']
+    update_password = module.params['update_password']
 
     try:
         cloud = shade.openstack_cloud(**module.params)
@@ -203,17 +230,25 @@
                     enabled=enabled)
                 changed = True
             else:
-                params_dict = {'email': email, 'enabled': enabled, 'password': password}
+                params_dict = {'email': email, 'enabled': enabled,
+                               'password': password,
+                               'update_password': update_password}
                 if domain_id is not None:
                     params_dict['domain_id'] = domain_id
                 if default_project_id is not None:
                     params_dict['default_project_id'] = default_project_id
 
                 if _needs_update(params_dict, user):
-                    user = cloud.update_user(
-                        user['id'], password=password, email=email,
-                        default_project=default_project_id, domain_id=domain_id,
-                        enabled=enabled)
+                    if update_password == 'always':
+                        user = cloud.update_user(
+                            user['id'], password=password, email=email,
+                            default_project=default_project_id,
+                            domain_id=domain_id, enabled=enabled)
+                    else:
+                        user = cloud.update_user(
+                            user['id'], email=email,
+                            default_project=default_project_id,
+                            domain_id=domain_id, enabled=enabled)
                     changed = True
                 else:
                     changed = False

{"golden_diff": "diff --git a/cloud/openstack/os_user.py b/cloud/openstack/os_user.py\n--- a/cloud/openstack/os_user.py\n+++ b/cloud/openstack/os_user.py\n@@ -43,6 +43,14 @@\n         - Password for the user\n      required: false\n      default: None\n+   update_password:\n+     required: false\n+     default: always\n+     choices: ['always', 'on_create']\n+     version_added: \"2.3\"\n+     description:\n+        - C(always) will attempt to update password.  C(on_create) will only\n+          set the password for newly created users.\n    email:\n      description:\n         - Email address for the user\n@@ -89,6 +97,17 @@\n     cloud: mycloud\n     state: absent\n     name: demouser\n+\n+# Create a user but don't update password if user exists\n+- os_user:\n+    cloud: mycloud\n+    state: present\n+    name: demouser\n+    password: secret\n+    update_password: on_create\n+    email: demo@example.com\n+    domain: default\n+    default_project: demo\n '''\n \n \n@@ -122,12 +141,13 @@\n \n def _needs_update(params_dict, user):\n     for k, v in params_dict.items():\n-        if k != 'password' and user[k] != v:\n+        if k not in ('password', 'update_password') and user[k] != v:\n             return True\n \n     # We don't get password back in the user object, so assume any supplied\n     # password is a change.\n-    if params_dict['password'] is not None:\n+    if (params_dict['password'] is not None and\n+            params_dict['update_password'] == 'always'):\n         return True\n \n     return False\n@@ -164,11 +184,17 @@\n         domain=dict(required=False, default=None),\n         enabled=dict(default=True, type='bool'),\n         state=dict(default='present', choices=['absent', 'present']),\n+        update_password=dict(default='always', choices=['always',\n+                                                        'on_create']),\n     )\n \n     module_kwargs = openstack_module_kwargs()\n     module = AnsibleModule(\n         argument_spec,\n+        required_if=[\n+            ('update_password', 'always', ['password']),\n+            ('update_password', 'on_create', ['password']),\n+        ],\n         **module_kwargs)\n \n     if not HAS_SHADE:\n@@ -181,6 +207,7 @@\n     domain = module.params['domain']\n     enabled = module.params['enabled']\n     state = module.params['state']\n+    update_password = module.params['update_password']\n \n     try:\n         cloud = shade.openstack_cloud(**module.params)\n@@ -203,17 +230,25 @@\n                     enabled=enabled)\n                 changed = True\n             else:\n-                params_dict = {'email': email, 'enabled': enabled, 'password': password}\n+                params_dict = {'email': email, 'enabled': enabled,\n+                               'password': password,\n+                               'update_password': update_password}\n                 if domain_id is not None:\n                     params_dict['domain_id'] = domain_id\n                 if default_project_id is not None:\n                     params_dict['default_project_id'] = default_project_id\n \n                 if _needs_update(params_dict, user):\n-                    user = cloud.update_user(\n-                        user['id'], password=password, email=email,\n-                        default_project=default_project_id, domain_id=domain_id,\n-                        enabled=enabled)\n+                    if update_password == 'always':\n+                        user = cloud.update_user(\n+                            user['id'], password=password, email=email,\n+                            default_project=default_project_id,\n+                            domain_id=domain_id, enabled=enabled)\n+                    else:\n+                        user = cloud.update_user(\n+                            user['id'], email=email,\n+                            default_project=default_project_id,\n+                            domain_id=domain_id, enabled=enabled)\n                     changed = True\n                 else:\n                     changed = False\n", "issue": "Add update_password option to os_user module\n<!--- Verify first that your issue/request is not already reported in GitHub -->\n##### ISSUE TYPE\n\n<!--- Pick one below and delete the rest: -->\n- Feature Idea\n##### COMPONENT NAME\n\n<!--- Name of the plugin/module/task -->\n\nos_user\n##### ANSIBLE VERSION\n\n<!--- Paste verbatim output from \u201cansible --version\u201d between quotes below -->\n\n```\n$ ansible --version\nansible 2.1.2.0\n```\n##### CONFIGURATION\n\n<!---\nMention any settings you have changed/added/removed in ansible.cfg\n(or using the ANSIBLE_* environment variables).\n-->\n##### OS / ENVIRONMENT\n\n<!---\nMention the OS you are running Ansible from, and the OS you are\nmanaging, or say \u201cN/A\u201d for anything that is not platform-specific.\n-->\n\nN/A\n##### SUMMARY\n\n<!--- Explain the problem briefly -->\n\nThe `os_user` module with a password specified for a user will always report 'changed'.\nThe conclusion of the bug report in #5183 was that in order to \"fix\" this we need to add another parameter like the on in the `user` module.\nI.e a parameter called `update_password` that has options `on_create` or `always`.\n##### STEPS TO REPRODUCE\n\n<!---\nFor bugs, show exactly how to reproduce the problem.\nFor new features, show how the feature would be used.\n-->\n\n```\n  - name: \"Create test user\"\n    os_user:\n      name: test\n      state: present\n      password: very-secret\n      default_project: a-existing-project\n      update_password: on_create\n```\n##### EXPECTED RESULTS\n\n<!--- What did you expect to happen when running the steps above? -->\n\nOn first run, the user would be created and the password set.\nOn the second run, given that nothing changed, the task would say `ok`.\nIf the parameter would be `update_password: always` on the other hand, the module should always set the password and would always report `changed`\n\n", "before_files": [{"content": "#!/usr/bin/python\n# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.\n#\n# This module is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# This software is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this software.  If not, see <http://www.gnu.org/licenses/>.\n\n\ntry:\n    import shade\n    HAS_SHADE = True\nexcept ImportError:\n    HAS_SHADE = False\n\nDOCUMENTATION = '''\n---\nmodule: os_user\nshort_description: Manage OpenStack Identity Users\nextends_documentation_fragment: openstack\nversion_added: \"2.0\"\ndescription:\n    - Manage OpenStack Identity users. Users can be created,\n      updated or deleted using this module. A user will be updated\n      if I(name) matches an existing user and I(state) is present.\n      The value for I(name) cannot be updated without deleting and\n      re-creating the user.\noptions:\n   name:\n     description:\n        - Username for the user\n     required: true\n   password:\n     description:\n        - Password for the user\n     required: false\n     default: None\n   email:\n     description:\n        - Email address for the user\n     required: false\n     default: None\n   default_project:\n     description:\n        - Project name or ID that the user should be associated with by default\n     required: false\n     default: None\n   domain:\n     description:\n        - Domain to create the user in if the cloud supports domains\n     required: false\n     default: None\n   enabled:\n     description:\n        - Is the user enabled\n     required: false\n     default: True\n   state:\n     description:\n       - Should the resource be present or absent.\n     choices: [present, absent]\n     default: present\nrequirements:\n    - \"python >= 2.6\"\n    - \"shade\"\n'''\n\nEXAMPLES = '''\n# Create a user\n- os_user:\n    cloud: mycloud\n    state: present\n    name: demouser\n    password: secret\n    email: demo@example.com\n    domain: default\n    default_project: demo\n\n# Delete a user\n- os_user:\n    cloud: mycloud\n    state: absent\n    name: demouser\n'''\n\n\nRETURN = '''\nuser:\n    description: Dictionary describing the user.\n    returned: On success when I(state) is 'present'\n    type: dictionary\n    contains:\n        default_project_id:\n            description: User default project ID. Only present with Keystone >= v3.\n            type: string\n            sample: \"4427115787be45f08f0ec22a03bfc735\"\n        domain_id:\n            description: User domain ID. Only present with Keystone >= v3.\n            type: string\n            sample: \"default\"\n        email:\n            description: User email address\n            type: string\n            sample: \"demo@example.com\"\n        id:\n            description: User ID\n            type: string\n            sample: \"f59382db809c43139982ca4189404650\"\n        name:\n            description: User name\n            type: string\n            sample: \"demouser\"\n'''\n\ndef _needs_update(params_dict, user):\n    for k, v in params_dict.items():\n        if k != 'password' and user[k] != v:\n            return True\n\n    # We don't get password back in the user object, so assume any supplied\n    # password is a change.\n    if params_dict['password'] is not None:\n        return True\n\n    return False\n\ndef _get_domain_id(cloud, domain):\n    try:\n        # We assume admin is passing domain id\n        domain_id = cloud.get_domain(domain)['id']\n    except:\n        # If we fail, maybe admin is passing a domain name.\n        # Note that domains have unique names, just like id.\n        try:\n            domain_id = cloud.search_domains(filters={'name': domain})[0]['id']\n        except:\n            # Ok, let's hope the user is non-admin and passing a sane id\n            domain_id = domain\n\n    return domain_id\n\ndef _get_default_project_id(cloud, default_project):\n    project = cloud.get_project(default_project)\n    if not project:\n        module.fail_json(msg='Default project %s is not valid' % default_project)\n\n    return project['id']\n\ndef main():\n\n    argument_spec = openstack_full_argument_spec(\n        name=dict(required=True),\n        password=dict(required=False, default=None),\n        email=dict(required=False, default=None),\n        default_project=dict(required=False, default=None),\n        domain=dict(required=False, default=None),\n        enabled=dict(default=True, type='bool'),\n        state=dict(default='present', choices=['absent', 'present']),\n    )\n\n    module_kwargs = openstack_module_kwargs()\n    module = AnsibleModule(\n        argument_spec,\n        **module_kwargs)\n\n    if not HAS_SHADE:\n        module.fail_json(msg='shade is required for this module')\n\n    name = module.params['name']\n    password = module.params['password']\n    email = module.params['email']\n    default_project = module.params['default_project']\n    domain = module.params['domain']\n    enabled = module.params['enabled']\n    state = module.params['state']\n\n    try:\n        cloud = shade.openstack_cloud(**module.params)\n        user = cloud.get_user(name)\n\n        domain_id = None\n        if domain:\n            opcloud = shade.operator_cloud(**module.params)\n            domain_id = _get_domain_id(opcloud, domain)\n\n        if state == 'present':\n            default_project_id = None\n            if default_project:\n                default_project_id = _get_default_project_id(cloud, default_project)\n\n            if user is None:\n                user = cloud.create_user(\n                    name=name, password=password, email=email,\n                    default_project=default_project_id, domain_id=domain_id,\n                    enabled=enabled)\n                changed = True\n            else:\n                params_dict = {'email': email, 'enabled': enabled, 'password': password}\n                if domain_id is not None:\n                    params_dict['domain_id'] = domain_id\n                if default_project_id is not None:\n                    params_dict['default_project_id'] = default_project_id\n\n                if _needs_update(params_dict, user):\n                    user = cloud.update_user(\n                        user['id'], password=password, email=email,\n                        default_project=default_project_id, domain_id=domain_id,\n                        enabled=enabled)\n                    changed = True\n                else:\n                    changed = False\n            module.exit_json(changed=changed, user=user)\n\n        elif state == 'absent':\n            if user is None:\n                changed=False\n            else:\n                cloud.delete_user(user['id'])\n                changed=True\n            module.exit_json(changed=changed)\n\n    except shade.OpenStackCloudException as e:\n        module.fail_json(msg=str(e), extra_data=e.extra_data)\n\nfrom ansible.module_utils.basic import *\nfrom ansible.module_utils.openstack import *\n\n\nif __name__ == '__main__':\n    main()\n", "path": "cloud/openstack/os_user.py"}], "after_files": [{"content": "#!/usr/bin/python\n# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.\n#\n# This module is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# This software is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this software.  If not, see <http://www.gnu.org/licenses/>.\n\n\ntry:\n    import shade\n    HAS_SHADE = True\nexcept ImportError:\n    HAS_SHADE = False\n\nDOCUMENTATION = '''\n---\nmodule: os_user\nshort_description: Manage OpenStack Identity Users\nextends_documentation_fragment: openstack\nversion_added: \"2.0\"\ndescription:\n    - Manage OpenStack Identity users. Users can be created,\n      updated or deleted using this module. A user will be updated\n      if I(name) matches an existing user and I(state) is present.\n      The value for I(name) cannot be updated without deleting and\n      re-creating the user.\noptions:\n   name:\n     description:\n        - Username for the user\n     required: true\n   password:\n     description:\n        - Password for the user\n     required: false\n     default: None\n   update_password:\n     required: false\n     default: always\n     choices: ['always', 'on_create']\n     version_added: \"2.3\"\n     description:\n        - C(always) will attempt to update password.  C(on_create) will only\n          set the password for newly created users.\n   email:\n     description:\n        - Email address for the user\n     required: false\n     default: None\n   default_project:\n     description:\n        - Project name or ID that the user should be associated with by default\n     required: false\n     default: None\n   domain:\n     description:\n        - Domain to create the user in if the cloud supports domains\n     required: false\n     default: None\n   enabled:\n     description:\n        - Is the user enabled\n     required: false\n     default: True\n   state:\n     description:\n       - Should the resource be present or absent.\n     choices: [present, absent]\n     default: present\nrequirements:\n    - \"python >= 2.6\"\n    - \"shade\"\n'''\n\nEXAMPLES = '''\n# Create a user\n- os_user:\n    cloud: mycloud\n    state: present\n    name: demouser\n    password: secret\n    email: demo@example.com\n    domain: default\n    default_project: demo\n\n# Delete a user\n- os_user:\n    cloud: mycloud\n    state: absent\n    name: demouser\n\n# Create a user but don't update password if user exists\n- os_user:\n    cloud: mycloud\n    state: present\n    name: demouser\n    password: secret\n    update_password: on_create\n    email: demo@example.com\n    domain: default\n    default_project: demo\n'''\n\n\nRETURN = '''\nuser:\n    description: Dictionary describing the user.\n    returned: On success when I(state) is 'present'\n    type: dictionary\n    contains:\n        default_project_id:\n            description: User default project ID. Only present with Keystone >= v3.\n            type: string\n            sample: \"4427115787be45f08f0ec22a03bfc735\"\n        domain_id:\n            description: User domain ID. Only present with Keystone >= v3.\n            type: string\n            sample: \"default\"\n        email:\n            description: User email address\n            type: string\n            sample: \"demo@example.com\"\n        id:\n            description: User ID\n            type: string\n            sample: \"f59382db809c43139982ca4189404650\"\n        name:\n            description: User name\n            type: string\n            sample: \"demouser\"\n'''\n\ndef _needs_update(params_dict, user):\n    for k, v in params_dict.items():\n        if k not in ('password', 'update_password') and user[k] != v:\n            return True\n\n    # We don't get password back in the user object, so assume any supplied\n    # password is a change.\n    if (params_dict['password'] is not None and\n            params_dict['update_password'] == 'always'):\n        return True\n\n    return False\n\ndef _get_domain_id(cloud, domain):\n    try:\n        # We assume admin is passing domain id\n        domain_id = cloud.get_domain(domain)['id']\n    except:\n        # If we fail, maybe admin is passing a domain name.\n        # Note that domains have unique names, just like id.\n        try:\n            domain_id = cloud.search_domains(filters={'name': domain})[0]['id']\n        except:\n            # Ok, let's hope the user is non-admin and passing a sane id\n            domain_id = domain\n\n    return domain_id\n\ndef _get_default_project_id(cloud, default_project):\n    project = cloud.get_project(default_project)\n    if not project:\n        module.fail_json(msg='Default project %s is not valid' % default_project)\n\n    return project['id']\n\ndef main():\n\n    argument_spec = openstack_full_argument_spec(\n        name=dict(required=True),\n        password=dict(required=False, default=None),\n        email=dict(required=False, default=None),\n        default_project=dict(required=False, default=None),\n        domain=dict(required=False, default=None),\n        enabled=dict(default=True, type='bool'),\n        state=dict(default='present', choices=['absent', 'present']),\n        update_password=dict(default='always', choices=['always',\n                                                        'on_create']),\n    )\n\n    module_kwargs = openstack_module_kwargs()\n    module = AnsibleModule(\n        argument_spec,\n        required_if=[\n            ('update_password', 'always', ['password']),\n            ('update_password', 'on_create', ['password']),\n        ],\n        **module_kwargs)\n\n    if not HAS_SHADE:\n        module.fail_json(msg='shade is required for this module')\n\n    name = module.params['name']\n    password = module.params['password']\n    email = module.params['email']\n    default_project = module.params['default_project']\n    domain = module.params['domain']\n    enabled = module.params['enabled']\n    state = module.params['state']\n    update_password = module.params['update_password']\n\n    try:\n        cloud = shade.openstack_cloud(**module.params)\n        user = cloud.get_user(name)\n\n        domain_id = None\n        if domain:\n            opcloud = shade.operator_cloud(**module.params)\n            domain_id = _get_domain_id(opcloud, domain)\n\n        if state == 'present':\n            default_project_id = None\n            if default_project:\n                default_project_id = _get_default_project_id(cloud, default_project)\n\n            if user is None:\n                user = cloud.create_user(\n                    name=name, password=password, email=email,\n                    default_project=default_project_id, domain_id=domain_id,\n                    enabled=enabled)\n                changed = True\n            else:\n                params_dict = {'email': email, 'enabled': enabled,\n                               'password': password,\n                               'update_password': update_password}\n                if domain_id is not None:\n                    params_dict['domain_id'] = domain_id\n                if default_project_id is not None:\n                    params_dict['default_project_id'] = default_project_id\n\n                if _needs_update(params_dict, user):\n                    if update_password == 'always':\n                        user = cloud.update_user(\n                            user['id'], password=password, email=email,\n                            default_project=default_project_id,\n                            domain_id=domain_id, enabled=enabled)\n                    else:\n                        user = cloud.update_user(\n                            user['id'], email=email,\n                            default_project=default_project_id,\n                            domain_id=domain_id, enabled=enabled)\n                    changed = True\n                else:\n                    changed = False\n            module.exit_json(changed=changed, user=user)\n\n        elif state == 'absent':\n            if user is None:\n                changed=False\n            else:\n                cloud.delete_user(user['id'])\n                changed=True\n            module.exit_json(changed=changed)\n\n    except shade.OpenStackCloudException as e:\n        module.fail_json(msg=str(e), extra_data=e.extra_data)\n\nfrom ansible.module_utils.basic import *\nfrom ansible.module_utils.openstack import *\n\n\nif __name__ == '__main__':\n    main()\n", "path": "cloud/openstack/os_user.py"}]}