diff --git a/.zuul.yaml b/.zuul.yaml index 3a7b392d..be1752c0 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -70,6 +70,7 @@ dns_zone_info floating_ip_info group + identity_user_info identity_role image keypair diff --git a/ci/roles/identity_user_info/defaults/main.yml b/ci/roles/identity_user_info/defaults/main.yml new file mode 100644 index 00000000..5f2f1447 --- /dev/null +++ b/ci/roles/identity_user_info/defaults/main.yml @@ -0,0 +1,11 @@ +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 new file mode 100644 index 00000000..b03fc37c --- /dev/null +++ b/ci/roles/identity_user_info/tasks/main.yml @@ -0,0 +1,69 @@ +- 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 16cd5e41..4a80e3cf 100644 --- a/ci/run-collection.yml +++ b/ci/run-collection.yml @@ -16,6 +16,7 @@ tags: dns when: sdk_version is version(0.28, '>=') - { role: floating_ip_info, tags: floating_ip_info } + - { 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_info.py b/plugins/modules/identity_user_info.py index ee48a9c1..654c80cd 100644 --- a/plugins/modules/identity_user_info.py +++ b/plugins/modules/identity_user_info.py @@ -25,6 +25,7 @@ options: - A dictionary of meta data to use for further filtering. Elements of this dictionary may be additional dictionaries. type: dict + default: {} requirements: - "python >= 3.6" - "openstacksdk" @@ -39,7 +40,7 @@ EXAMPLES = ''' cloud: awesomecloud register: result - debug: - msg: "{{ result.openstack_users }}" + msg: "{{ result.users }}" # Gather information about a previously created user by name - openstack.cloud.identity_user_info: @@ -47,7 +48,7 @@ EXAMPLES = ''' name: demouser register: result - debug: - msg: "{{ result.openstack_users }}" + msg: "{{ result.users }}" # Gather information about a previously created user in a specific domain - openstack.cloud.identity_user_info: @@ -56,7 +57,7 @@ EXAMPLES = ''' domain: admindomain register: result - debug: - msg: "{{ result.openstack_users }}" + msg: "{{ result.users }}" # Gather information about a previously created user in a specific domain with filter - openstack.cloud.identity_user_info: @@ -67,15 +68,16 @@ EXAMPLES = ''' enabled: False register: result - debug: - msg: "{{ result.openstack_users }}" + msg: "{{ result.users }}" ''' RETURN = ''' -openstack_users: +users: description: has all the OpenStack information about users - returned: always, but can be null - type: complex + returned: always + type: list + elements: dict contains: id: description: Unique UUID. @@ -85,22 +87,39 @@ openstack_users: description: Username of the user. returned: success type: str - enabled: - description: Flag to indicate if the user is enabled - returned: success - type: bool - domain_id: - description: Domain ID containing the user - returned: success - type: str default_project_id: description: Default project ID of the 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 @@ -114,7 +133,7 @@ class IdentityUserInfoModule(OpenStackModule): argument_spec = dict( name=dict(required=False, default=None), domain=dict(required=False, default=None), - filters=dict(required=False, type='dict', default=None), + filters=dict(required=False, type='dict', default={}), ) module_kwargs = dict( supports_check_mode=True @@ -128,21 +147,16 @@ class IdentityUserInfoModule(OpenStackModule): filters = self.params['filters'] if domain: - try: - # We assume admin is passing domain id - dom = self.conn.get_domain(domain)['id'] - domain = dom - except Exception: - # If we fail, maybe admin is passing a domain name. - # Note that domains have unique names, just like id. - dom = self.conn.search_domains(filters={'name': domain}) - if dom: - domain = dom[0]['id'] - else: - self.fail_json(msg='Domain name or ID does not exist') + 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)) + filters['domain_id'] = dom_obj.id - users = self.conn.search_users(name, filters, domain_id=domain) - self.exit_json(changed=False, openstack_users=users) + users = self.conn.identity.users( + name=name, **filters) + users = [user.to_dict(computed=False) for user in users] + self.exit_json(changed=False, users=users) def main():