From c9afdbfd73d788450d0e9f28ffc6893e350c0460 Mon Sep 17 00:00:00 2001 From: Jakob Meng Date: Fri, 13 Jan 2023 12:21:04 +0100 Subject: [PATCH] Refactored identity_user{,_info} modules Change-Id: Iae52d1a86f8f78790290be3966681f2277b9701d --- ci/roles/identity_user/defaults/main.yml | 2 +- ci/roles/identity_user/tasks/main.yml | 371 +++++++++--------- ci/roles/identity_user_info/defaults/main.yml | 11 - ci/roles/identity_user_info/tasks/main.yml | 69 ---- ci/run-collection.yml | 1 - plugins/modules/identity_user.py | 352 ++++++++--------- plugins/modules/identity_user_info.py | 191 ++++----- 7 files changed, 444 insertions(+), 553 deletions(-) delete mode 100644 ci/roles/identity_user_info/defaults/main.yml delete mode 100644 ci/roles/identity_user_info/tasks/main.yml diff --git a/ci/roles/identity_user/defaults/main.yml b/ci/roles/identity_user/defaults/main.yml index 53954500..d7ae1079 100644 --- a/ci/roles/identity_user/defaults/main.yml +++ b/ci/roles/identity_user/defaults/main.yml @@ -1,4 +1,4 @@ -os_identity_user_fields: +expected_fields: - default_project_id - description - domain_id diff --git a/ci/roles/identity_user/tasks/main.yml b/ci/roles/identity_user/tasks/main.yml index 7696fdbd..37f123e0 100644 --- a/ci/roles/identity_user/tasks/main.yml +++ b/ci/roles/identity_user/tasks/main.yml @@ -1,197 +1,218 @@ --- -- name: setup - block: - - name: Delete user before running tests - openstack.cloud.identity_user: - cloud: "{{ cloud }}" - state: absent - name: "{{ item }}" - loop: - - ansible_user - - ansible_user2 - register: user +- name: Create a user without a password + openstack.cloud.identity_user: + cloud: "{{ cloud }}" + state: present + name: ansible_user + email: ansible.user@nowhere.net + domain: default + description: "ansible user" + default_project: demo + register: user -- block: - - name: Delete unexistent user - openstack.cloud.identity_user: - cloud: "{{ cloud }}" - state: absent - name: ansible_user - register: user +- name: Assert return values of identity_user module + assert: + that: + - user.user.name == 'ansible_user' + - user.user.description == 'ansible user' + # allow new fields to be introduced but prevent fields from being removed + - expected_fields|difference(user.user.keys())|length == 0 - - name: Ensure user was not changed - assert: - that: user is not changed +- name: Fail when update_password is always but no password specified + openstack.cloud.identity_user: + cloud: "{{ cloud }}" + state: present + name: ansible_user + update_password: always + email: ansible.user@nowhere.net + domain: default + default_project: demo + register: user + ignore_errors: yes -- block: - - name: Create a user without a password - openstack.cloud.identity_user: - cloud: "{{ cloud }}" - state: present - name: ansible_user - email: ansible.user@nowhere.net - domain: default - default_project: demo - register: user +- name: Assert that update failed + assert: + that: + - user is failed + - user.msg == "update_password is 'always' but password is missing" - - name: Ensure user was changed - assert: - that: user is changed +- name: Delete user + openstack.cloud.identity_user: + cloud: "{{ cloud }}" + state: absent + name: ansible_user - - name: Ensure user has fields - assert: - that: item in user['user'] - loop: "{{ os_identity_user_fields }}" - - name: Fail when update_password is always but no password specified - openstack.cloud.identity_user: - cloud: "{{ cloud }}" - state: present - name: ansible_user - update_password: always - email: ansible.user@nowhere.net - domain: default - default_project: demo - register: user - ignore_errors: yes +- name: Create user with a password + openstack.cloud.identity_user: + cloud: "{{ cloud }}" + state: present + name: ansible_user + password: secret + email: ansible.user@nowhere.net + update_password: on_create + domain: default + default_project: demo - - assert: - that: user.msg == "update_password is always but a password value is missing" +- name: Create user with a password again + openstack.cloud.identity_user: + cloud: "{{ cloud }}" + state: present + name: ansible_user + password: secret + email: ansible.user@nowhere.net + update_password: on_create + domain: default + default_project: demo + register: user - - name: Delete user - openstack.cloud.identity_user: - cloud: "{{ cloud }}" - state: absent - name: ansible_user +- name: Assert user was not changed + assert: + that: + - user is not changed -- block: - - name: Create user with a password - openstack.cloud.identity_user: - cloud: "{{ cloud }}" - state: present - name: ansible_user - password: secret - email: ansible.user@nowhere.net - update_password: on_create - domain: default - default_project: demo - register: user +- name: Update user with password + openstack.cloud.identity_user: + cloud: "{{ cloud }}" + state: present + name: ansible_user + password: secret2 + email: updated.ansible.user@nowhere.net + register: user - - name: Assert user has fields - assert: - that: item in user['user'] - loop: "{{ os_identity_user_fields }}" - -- block: - - name: Create identical user - openstack.cloud.identity_user: - cloud: "{{ cloud }}" - state: present - name: ansible_user - password: secret - email: ansible.user@nowhere.net - update_password: on_create - domain: default - default_project: demo - register: user - - - name: Assert user was not changed - assert: - that: user is not changed - - - name: Assert user has fields - assert: - that: item in user['user'] - loop: "{{ os_identity_user_fields }}" - -- block: - - name: Update user with password - openstack.cloud.identity_user: - cloud: "{{ cloud }}" - state: present - name: ansible_user - password: secret2 - email: updated.ansible.user@nowhere.net - register: user - - - name: Ensure user was changed - assert: - that: user is changed - - - name: Ensure user has fields - assert: - that: item in user['user'] - loop: "{{ os_identity_user_fields }}" +- name: Ensure user was changed + assert: + that: + - user is changed - name: Update user without password and update_password set to always - block: - - openstack.cloud.identity_user: - cloud: "{{ cloud }}" - state: present - name: ansible_user - update_password: always - email: updated.ansible.user@nowhere.net - register: user - ignore_errors: yes + openstack.cloud.identity_user: + cloud: "{{ cloud }}" + state: present + name: ansible_user + update_password: always + email: updated.ansible.user@nowhere.net + register: user + ignore_errors: yes - - assert: - that: user.msg == "update_password is always but a password value is missing" +- name: Assert user update failed + assert: + that: + - user is failed + - user.msg == "update_password is 'always' but password is missing" -- block: - - name: Ensure user with update_password set to on_create - openstack.cloud.identity_user: - cloud: "{{ cloud }}" - state: present - name: ansible_user - update_password: on_create - password: secret3 - email: updated.ansible.user@nowhere.net - register: user +- name: Ensure user with update_password set to on_create + openstack.cloud.identity_user: + cloud: "{{ cloud }}" + state: present + name: ansible_user + update_password: on_create + password: secret3 + email: updated.ansible.user@nowhere.net + register: user - - name: Ensure user was not changed - assert: - that: user is not changed +- name: Ensure user was not changed + assert: + that: + - user is not changed -- block: - - name: Ensure user with update_password set to always - openstack.cloud.identity_user: - cloud: "{{ cloud }}" - state: present - name: ansible_user - update_password: always - password: secret3 - email: updated.ansible.user@nowhere.net - register: user +- name: Ensure user with update_password set to always + openstack.cloud.identity_user: + cloud: "{{ cloud }}" + state: present + name: ansible_user + update_password: always + password: secret3 + email: updated.ansible.user@nowhere.net + register: user - - name: Ensure user was changed - assert: - that: user is changed +- name: Ensure user was changed + assert: + that: + - user is changed -- block: - - name: Create user without a password - openstack.cloud.identity_user: - cloud: "{{ cloud }}" - state: present - name: ansible_user2 - password: secret - email: ansible.user2@nowhere.net - update_password: on_create - domain: default - default_project: demo - register: user +- name: Create user without a password + openstack.cloud.identity_user: + cloud: "{{ cloud }}" + state: present + name: ansible_user2 + password: secret + email: ansible.user2@nowhere.net + update_password: on_create + domain: default + default_project: demo + register: user - - name: Assert user has fields - assert: - that: item in user['user'] - loop: "{{ os_identity_user_fields }}" +- name: Fetch users + openstack.cloud.identity_user_info: + cloud: "{{ cloud }}" + register: users -- block: - - name: Delete user - openstack.cloud.identity_user: - cloud: "{{ cloud }}" - state: absent - name: ansible_user +- name: Assert return values of identity_user_info module + assert: + that: + - users.users | length > 0 + # allow new fields to be introduced but prevent fields from being removed + - expected_fields|difference(users.users.0.keys())|length == 0 - - name: Ensure user was changed - assert: - that: user is changed +- name: Fetch user by name + openstack.cloud.identity_user_info: + cloud: "{{ cloud }}" + name: ansible_user + register: users + +- name: Assert named user + assert: + that: + - users.users | length == 1 + +- name: Delete user + openstack.cloud.identity_user: + cloud: "{{ cloud }}" + state: absent + name: ansible_user2 + +- name: Delete user + openstack.cloud.identity_user: + cloud: "{{ cloud }}" + state: absent + name: ansible_user + +- name: Ensure user was changed + assert: + that: + - user is changed + +- name: Delete user again + openstack.cloud.identity_user: + cloud: "{{ cloud }}" + state: absent + name: ansible_user + register: user + +- name: Ensure user was not changed + assert: + that: + - user is not changed + +- name: Fetch ansible_user + openstack.cloud.identity_user_info: + cloud: "{{ cloud }}" + name: ansible_user + register: users + +- name: Assert ansible_user does not exist + assert: + that: + - users.users | length == 0 + +- name: Fetch ansible_user2 + openstack.cloud.identity_user_info: + cloud: "{{ cloud }}" + name: ansible_user2 + register: users + +- name: Assert ansible_user2 does not exist + assert: + that: + - users.users | length == 0 diff --git a/ci/roles/identity_user_info/defaults/main.yml b/ci/roles/identity_user_info/defaults/main.yml deleted file mode 100644 index 5f2f1447..00000000 --- a/ci/roles/identity_user_info/defaults/main.yml +++ /dev/null @@ -1,11 +0,0 @@ -os_expected_user_info_fields: - - default_project_id - - description - - domain_id - - email - - id - - is_enabled - - links - - name - - password - - password_expires_at diff --git a/ci/roles/identity_user_info/tasks/main.yml b/ci/roles/identity_user_info/tasks/main.yml deleted file mode 100644 index b03fc37c..00000000 --- a/ci/roles/identity_user_info/tasks/main.yml +++ /dev/null @@ -1,69 +0,0 @@ -- name: Ensure user does not exist before tests - openstack.cloud.identity_user: - cloud: "{{ cloud }}" - state: absent - name: ansible_user - -- block: - - name: Get unexistent user - openstack.cloud.identity_user_info: - cloud: "{{ cloud }}" - name: ansible_user - register: userinfo - - name: Ensure nothing was returned - assert: - that: not userinfo.users - -- block: - - name: Create user - openstack.cloud.identity_user: - cloud: "{{ cloud }}" - state: present - name: ansible_user - password: secret - email: ansible.user@nowhere.net - domain: default - default_project: demo - register: user - - name: Create second user - openstack.cloud.identity_user: - cloud: "{{ cloud }}" - state: present - name: ansible_user2 - password: secret - email: ansible.user2@nowhere.net - domain: default - default_project: demo - register: user - - name: Get first user info - openstack.cloud.identity_user_info: - cloud: "{{ cloud }}" - name: ansible_user - register: userinfo - - name: Assert only one result exists - assert: - that: "{{ userinfo.users | length }} == 1" - - name: Assert userinfo has fields - assert: - that: item in userinfo.users[0] - loop: "{{ os_expected_user_info_fields }}" - -- block: - - name: Get all users - openstack.cloud.identity_user_info: - cloud: "{{ cloud }}" - register: userinfo - - name: Assert results were returned - assert: - that: "{{ userinfo.users | length }} > 0" - -- name: Post-test cleanup - block: - - name: Ensure users do not exist - openstack.cloud.identity_user: - cloud: "{{ cloud }}" - state: absent - name: "{{ item }}" - loop: - - ansible_user - - ansible_user2 diff --git a/ci/run-collection.yml b/ci/run-collection.yml index ad28879e..338f1182 100644 --- a/ci/run-collection.yml +++ b/ci/run-collection.yml @@ -21,7 +21,6 @@ - { role: identity_domain, tags: identity_domain } - { role: identity_group, tags: identity_group } - { role: identity_user, tags: identity_user } - - { role: identity_user_info, tags: identity_user_info } - { role: identity_role, tags: identity_role } - { role: image, tags: image } - { role: keypair, tags: keypair } diff --git a/plugins/modules/identity_user.py b/plugins/modules/identity_user.py index ca6feb2c..c4e7dff6 100644 --- a/plugins/modules/identity_user.py +++ b/plugins/modules/identity_user.py @@ -4,69 +4,68 @@ # Copyright (c) 2015 Hewlett-Packard Development Company, L.P. # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -DOCUMENTATION = ''' +DOCUMENTATION = r''' --- module: identity_user -short_description: Manage OpenStack Identity Users +short_description: Manage a OpenStack identity (Keystone) user author: OpenStack Ansible SIG description: - - Manage OpenStack Identity users. Users can be created, - updated or deleted using this module. A user will be updated - if I(name) matches an existing user and I(state) is present. - The value for I(name) cannot be updated without deleting and - re-creating the user. + - Create, update or delete a OpenStack identity (Keystone) user. options: - name: - description: - - Username for the user - required: true - type: str - password: - description: - - Password for the user - type: str - update_password: - required: false - choices: ['always', 'on_create'] - default: on_create - description: - - C(always) will attempt to update password. C(on_create) will only - set the password for newly created users. - type: str - email: - description: - - Email address for the user - type: str - description: - description: - - Description about the user - type: str - default_project: - description: - - Project name or ID that the user should be associated with by default - type: str - domain: - description: - - Domain to create the user in if the cloud supports domains - type: str - enabled: - description: - - Is the user enabled - type: bool - default: 'yes' - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - type: str + default_project: + description: + - Name or ID of the project, the user should be created in. + type: str + description: + description: + - Description about the user. + type: str + domain: + description: + - Domain to create the user in if the cloud supports domains. + type: str + email: + description: + - Email address for the user. + type: str + is_enabled: + description: + - Whether the user is enabled or not. + type: bool + default: 'yes' + aliases: ['enabled'] + name: + description: + - Name of the user. + - I(name) cannot be updated without deleting and re-creating the user. + required: true + type: str + password: + description: + - Password for the user. + type: str + state: + description: + - Should the resource be present or absent. + choices: [present, absent] + default: present + type: str + update_password: + choices: ['always', 'on_create'] + default: on_create + description: + - When I(update_password) is C(always), then the password will always be + updated. + - When I(update_password) is C(on_create), the the password is only set + when creating a user. + type: str extends_documentation_fragment: -- openstack.cloud.openstack + - openstack.cloud.openstack ''' -EXAMPLES = ''' -# Create a user -- openstack.cloud.identity_user: +EXAMPLES = r''' +- name: Create a user + openstack.cloud.identity_user: cloud: mycloud state: present name: demouser @@ -75,14 +74,14 @@ EXAMPLES = ''' domain: default default_project: demo -# Delete a user -- openstack.cloud.identity_user: +- name: Delete a user + openstack.cloud.identity_user: cloud: mycloud state: absent name: demouser -# Create a user but don't update password if user exists -- openstack.cloud.identity_user: +- name: Create a user but don't update password if user exists + openstack.cloud.identity_user: cloud: mycloud state: present name: demouser @@ -92,8 +91,8 @@ EXAMPLES = ''' domain: default default_project: demo -# Create a user without password -- openstack.cloud.identity_user: +- name: Create a user without password + openstack.cloud.identity_user: cloud: mycloud state: present name: demouser @@ -102,158 +101,137 @@ EXAMPLES = ''' default_project: demo ''' - -RETURN = ''' +RETURN = r''' user: - description: Dictionary describing the user. - returned: On success when I(state) is 'present' - type: dict - contains: - default_project_id: - description: User default project ID. Only present with Keystone >= v3. - returned: success - type: str - sample: "4427115787be45f08f0ec22a03bfc735" - description: - description: The description of this user - returned: success - type: str - sample: "a user" - domain_id: - description: User domain ID. Only present with Keystone >= v3. - returned: success - type: str - sample: "default" - email: - description: User email address - returned: success - type: str - sample: "demo@example.com" - id: - description: User ID - returned: success - type: str - sample: "f59382db809c43139982ca4189404650" - is_enabled: - description: Indicates whether the user is enabled - type: bool - links: - description: The links for the user resource - returned: success - type: dict - elements: str - name: - description: Unique user name, within the owning domain - returned: success - type: str - sample: "demouser" - password: - description: Credential used during authentication - returned: success - type: str - password_expires_at: - description: The date and time when the password expires. The time zone is UTC. A none value means the password never expires - returned: success - type: str - + description: Dictionary describing the identity user. + returned: On success when I(state) is C(present). + type: dict + contains: + default_project_id: + description: User default project ID. Only present with Keystone >= v3. + type: str + sample: "4427115787be45f08f0ec22a03bfc735" + description: + description: The description of this user + type: str + sample: "a user" + domain_id: + description: User domain ID. Only present with Keystone >= v3. + type: str + sample: "default" + email: + description: User email address + type: str + sample: "demo@example.com" + id: + description: User ID + type: str + sample: "f59382db809c43139982ca4189404650" + is_enabled: + description: Indicates whether the user is enabled + type: bool + links: + description: The links for the user resource + type: dict + elements: str + name: + description: Unique user name, within the owning domain + type: str + sample: "demouser" + password: + description: Credential used during authentication + type: str + password_expires_at: + description: The date and time when the password expires. The time zone + is UTC. A none value means the password never expires + type: str ''' from ansible_collections.openstack.cloud.plugins.module_utils.openstack import OpenStackModule +from ansible_collections.openstack.cloud.plugins.module_utils.resource import StateMachine class IdentityUserModule(OpenStackModule): argument_spec = dict( - name=dict(required=True), - password=dict(no_log=True), - email=dict(), default_project=dict(), description=dict(), domain=dict(), - enabled=dict(default=True, type='bool'), + email=dict(), + is_enabled=dict(default=True, type='bool', aliases=['enabled']), + name=dict(required=True), + password=dict(no_log=True), state=dict(default='present', choices=['absent', 'present']), - update_password=dict(default='on_create', choices=['always', 'on_create']), + update_password=dict(default='on_create', + choices=['always', 'on_create']), ) module_kwargs = dict() - def _needs_update(self, params_dict, user): - for k in params_dict: - # We don't get password back in the user object, so assume any supplied - # password is a change. - if k == 'password': - return True - if user[k] != params_dict[k]: - return True - return False + class _StateMachine(StateMachine): + def _build_update(self, resource, attributes, updateable_attributes, + non_updateable_attributes, + update_password='on_create', **kwargs): + if update_password == 'always' and 'password' not in attributes: + self.ansible.fail_json(msg="update_password is 'always'" + " but password is missing") + elif update_password == 'on_create' and 'password' in attributes: + attributes.pop('password') - def _get_domain_id(self, domain): - dom_obj = self.conn.identity.find_domain(domain) - if dom_obj is None: - # Ok, let's hope the user is non-admin and passing a sane id - return domain - return dom_obj.id + return super()._build_update(resource, attributes, + updateable_attributes, + non_updateable_attributes, **kwargs) - def _get_default_project_id(self, default_project, domain_id): - project = self.conn.identity.find_project(default_project, domain_id=domain_id) - if not project: - self.fail_json(msg='Default project %s is not valid' % default_project) - return project['id'] + def _find(self, attributes, **kwargs): + query_args = dict((k, attributes[k]) + for k in ['domain_id'] + if k in attributes and attributes[k] is not None) + + return self.find_function(attributes['name'], **query_args) def run(self): - name = self.params['name'] - password = self.params.get('password') - email = self.params['email'] - default_project = self.params['default_project'] - domain = self.params['domain'] - enabled = self.params['enabled'] - state = self.params['state'] - update_password = self.params['update_password'] - description = self.params['description'] + sm = self._StateMachine(connection=self.conn, + service_name='identity', + type_name='user', + sdk=self.sdk, + ansible=self.ansible) - domain_id = None - if domain: - domain_id = self._get_domain_id(domain) - user = self.conn.identity.find_user(name, domain_id=domain_id) + kwargs = dict((k, self.params[k]) + for k in ['state', 'timeout', 'update_password'] + if self.params[k] is not None) - changed = False - if state == 'present': - user_args = { - 'name': name, - 'email': email, - 'domain_id': domain_id, - 'description': description, - 'is_enabled': enabled, - } - if default_project: - default_project_id = self._get_default_project_id( - default_project, domain_id) - user_args['default_project_id'] = default_project_id - user_args = {k: v for k, v in user_args.items() if v is not None} + kwargs['attributes'] = \ + dict((k, self.params[k]) + for k in ['description', 'email', 'is_enabled', 'name', + 'password'] + if self.params[k] is not None) - changed = False - if user is None: - if password: - user_args['password'] = password + domain_name_or_id = self.params['domain'] + if domain_name_or_id is not None: + domain = self.conn.identity.find_domain(domain_name_or_id, + ignore_missing=False) + kwargs['attributes']['domain_id'] = domain.id - user = self.conn.identity.create_user(**user_args) - changed = True - else: - if update_password == 'always': - if not password: - self.fail_json(msg="update_password is always but a password value is missing") - user_args['password'] = password - # else we do not want to update the password + default_project_name_or_id = self.params['default_project'] + if default_project_name_or_id is not None: + query_args = dict((k, kwargs['attributes'][k]) + for k in ['domain_id'] + if k in kwargs['attributes'] + and kwargs['attributes'][k] is not None) + project = self.conn.identity.find_project( + default_project_name_or_id, ignore_missing=False, **query_args) + kwargs['attributes']['default_project_id'] = project.id - if self._needs_update(user_args, user): - user = self.conn.identity.update_user(user['id'], **user_args) - changed = True + user, is_changed = sm(check_mode=self.ansible.check_mode, + updateable_attributes=None, + non_updateable_attributes=['domain_id'], + wait=False, + **kwargs) - user = user.to_dict(computed=False) - self.exit_json(changed=changed, user=user) - elif state == 'absent' and user is not None: - self.conn.identity.delete_user(user) - changed = True - self.exit_json(changed=changed) + if user is None: + self.exit_json(changed=is_changed) + else: + self.exit_json(changed=is_changed, + user=user.to_dict(computed=False)) def main(): diff --git a/plugins/modules/identity_user_info.py b/plugins/modules/identity_user_info.py index 1a0f3b7a..b55b9fbd 100644 --- a/plugins/modules/identity_user_info.py +++ b/plugins/modules/identity_user_info.py @@ -4,126 +4,98 @@ # Copyright (c) 2016 Hewlett-Packard Enterprise Corporation # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -DOCUMENTATION = ''' +DOCUMENTATION = r''' --- module: identity_user_info -short_description: Retrieve information about one or more OpenStack users +short_description: Fetch OpenStack identity (Keystone) users author: OpenStack Ansible SIG description: - - Retrieve information about a one or more OpenStack users + - Fetch OpenStack identity (Keystone) users. options: - name: - description: - - Name or ID of the user - type: str - domain: - description: - - Name or ID of the domain containing the user if the cloud supports domains - type: str - filters: - description: - - A dictionary of meta data to use for further filtering. Elements of - this dictionary may be additional dictionaries. - type: dict - default: {} + domain: + description: + - Name or ID of the domain containing the user. + type: str + filters: + description: + - A dictionary of meta data to use for further filtering. Elements of + this dictionary may be additional dictionaries. + type: dict + name: + description: + - Name or ID of the user. + type: str extends_documentation_fragment: -- openstack.cloud.openstack + - openstack.cloud.openstack ''' -EXAMPLES = ''' -# Gather information about previously created users -- openstack.cloud.identity_user_info: +EXAMPLES = r''' +- name: Gather previously created users + openstack.cloud.identity_user_info: cloud: awesomecloud - register: result -- debug: - msg: "{{ result.users }}" -# Gather information about a previously created user by name -- openstack.cloud.identity_user_info: +- name: Gather previously created user by name + openstack.cloud.identity_user_info: cloud: awesomecloud name: demouser - register: result -- debug: - msg: "{{ result.users }}" -# Gather information about a previously created user in a specific domain -- openstack.cloud.identity_user_info: +- name: Gather previously created user in a specific domain + openstack.cloud.identity_user_info: cloud: awesomecloud name: demouser domain: admindomain - register: result -- debug: - msg: "{{ result.users }}" -# Gather information about a previously created user in a specific domain with filter -- openstack.cloud.identity_user_info: +- name: Gather previously created user with filters + openstack.cloud.identity_user_info: cloud: awesomecloud name: demouser domain: admindomain filters: - enabled: False - register: result -- debug: - msg: "{{ result.users }}" + is_enabled: False ''' - -RETURN = ''' +RETURN = r''' users: - description: has all the OpenStack information about users - returned: always - type: list - elements: dict - contains: - id: - description: Unique UUID. - returned: success - type: str - name: - description: Username of the user. - returned: success - type: str - default_project_id: - description: Default project ID of the user - returned: success - type: str - description: - description: The description of this user - returned: success - type: str - domain_id: - description: Domain ID containing the user - returned: success - type: str - email: - description: Email of the user - returned: success - type: str - is_enabled: - description: Flag to indicate if the user is enabled - returned: success - type: bool - links: - description: The links for the user resource - returned: success - type: complex - contains: - self: - description: Link to this user resource - returned: success - type: str - password: - description: The default form of credential used during authentication. - returned: success - type: str - password_expires_at: - description: The date and time when the password expires. The time zone is UTC. A Null value means the password never expires. - returned: success - type: str - username: - description: Username with Identity API v2 (OpenStack Pike or earlier) else Null - returned: success - type: str + description: Dictionary describing all matching identity users. + returned: always + type: list + elements: dict + contains: + id: + description: Unique UUID. + type: str + name: + description: Username of the user. + type: str + default_project_id: + description: Default project ID of the user + type: str + description: + description: The description of this user + type: str + domain_id: + description: Domain ID containing the user + type: str + email: + description: Email of the user + type: str + is_enabled: + description: Flag to indicate if the user is enabled + type: bool + links: + description: The links for the user resource + type: dict + password: + description: The default form of credential used during authentication. + type: str + password_expires_at: + description: The date and time when the password expires. The time zone + is UTC. A Null value means the password never expires. + type: str + username: + description: Username with Identity API v2 (OpenStack Pike or earlier) + else Null. + type: str ''' from ansible_collections.openstack.cloud.plugins.module_utils.openstack import OpenStackModule @@ -131,9 +103,9 @@ from ansible_collections.openstack.cloud.plugins.module_utils.openstack import O class IdentityUserInfoModule(OpenStackModule): argument_spec = dict( - name=dict(), domain=dict(), - filters=dict(type='dict', default={}), + filters=dict(type='dict'), + name=dict(), ) module_kwargs = dict( supports_check_mode=True @@ -141,19 +113,20 @@ class IdentityUserInfoModule(OpenStackModule): def run(self): name = self.params['name'] - domain = self.params['domain'] - filters = self.params['filters'] + filters = self.params['filters'] or {} - args = {} - if domain: - dom_obj = self.conn.identity.find_domain(domain) - if dom_obj is None: - self.fail_json( - msg="Domain name or ID '{0}' does not exist".format(domain)) - args['domain_id'] = dom_obj.id + kwargs = {} + domain_name_or_id = self.params['domain'] + if domain_name_or_id: + domain = self.conn.identity.find_domain(domain_name_or_id) + if domain is None: + self.exit_json(changed=False, groups=[]) + kwargs['domain_id'] = domain['id'] - users = [user.to_dict(computed=False) for user in self.conn.search_users(name, filters, **args)] - self.exit_json(changed=False, users=users) + self.exit_json(changed=False, + users=[u.to_dict(computed=False) + for u in self.conn.search_users(name, filters, + **kwargs)]) def main():