From 85349908408afd155cfc66024920ba1b2c271665 Mon Sep 17 00:00:00 2001 From: Jakob Meng Date: Fri, 13 Jan 2023 10:11:27 +0100 Subject: [PATCH] Refactored identity_group{,_info} modules Change-Id: I72dce1278a7623d4f68cabcceafcdfefda900195 --- ci/roles/identity_group/defaults/main.yml | 2 - ci/roles/identity_group/tasks/main.yml | 252 +++++++++++++------- ci/roles/identity_group_info/tasks/main.yml | 74 ------ ci/run-collection.yml | 1 - plugins/modules/identity_group.py | 177 +++++++------- plugins/modules/identity_group_info.py | 165 +++++-------- 6 files changed, 312 insertions(+), 359 deletions(-) delete mode 100644 ci/roles/identity_group_info/tasks/main.yml diff --git a/ci/roles/identity_group/defaults/main.yml b/ci/roles/identity_group/defaults/main.yml index 9b6ad245..73ac0946 100644 --- a/ci/roles/identity_group/defaults/main.yml +++ b/ci/roles/identity_group/defaults/main.yml @@ -1,5 +1,3 @@ -group_name: ansible_group -domain_name: ansible_domain expected_fields: - description - domain_id diff --git a/ci/roles/identity_group/tasks/main.yml b/ci/roles/identity_group/tasks/main.yml index 0d2fd0c6..89c4ea4d 100644 --- a/ci/roles/identity_group/tasks/main.yml +++ b/ci/roles/identity_group/tasks/main.yml @@ -1,138 +1,220 @@ --- -- name: Create domain - openstack.cloud.identity_domain: - cloud: "{{ cloud }}" - state: present - name: "{{ domain_name }}" - register: domain - - name: Create group openstack.cloud.identity_group: - cloud: "{{ cloud }}" - state: present - name: "{{ group_name }}" - register: group_result + cloud: "{{ cloud }}" + state: present + description: "ansible group" + name: ansible_group + register: group -- name: Assert changed +- name: Assert return values of identity_group module assert: - that: group_result is changed - -- name: Assert returned fields - assert: - that: item in group_result.group - loop: "{{ expected_fields }}" + that: + - group.group.name == 'ansible_group' + - group.group.description == "ansible group" + # allow new fields to be introduced but prevent fields from being removed + - expected_fields|difference(group.group.keys())|length == 0 - name: Create group again openstack.cloud.identity_group: - cloud: "{{ cloud }}" - state: present - name: "{{ group_name }}" - register: group_result + cloud: "{{ cloud }}" + state: present + description: "ansible group" + name: ansible_group + register: group -- name: Assert not changed +- name: Assert group did not change assert: - that: group_result is not changed + that: + - group is not changed - name: Update group openstack.cloud.identity_group: - cloud: "{{ cloud }}" - state: present - name: "{{ group_name }}" - description: "updated description" - register: group_result + cloud: "{{ cloud }}" + state: present + name: ansible_group + description: "updated description" + register: group - name: Assert changed assert: that: - - group_result is changed - - group_result.group.description == "updated description" + - group is changed + - group.group.description == "updated description" + +- name: Fetch all groups + openstack.cloud.identity_group_info: + cloud: "{{ cloud }}" + register: _groups + +- name: Assert return values of identity_group_info module + assert: + that: + - _groups.groups | length > 0 + # allow new fields to be introduced but prevent fields from being removed + - expected_fields|difference(_groups.groups.0.keys())|length == 0 + +- name: List group with filters + openstack.cloud.identity_group_info: + cloud: "{{ cloud }}" + domain: default + filters: + name: ansible_group + register: _groups + +- name: Assert group with filters + assert: + that: + - _groups.groups | length == 1 + - _groups.groups.0.id == group.group.id + +- name: Create domain + openstack.cloud.identity_domain: + cloud: "{{ cloud }}" + state: present + name: ansible_domain + register: domain - name: Create group in specific domain openstack.cloud.identity_group: - cloud: "{{ cloud }}" - state: present - name: "{{ group_name }}" - domain_id: "{{ domain.domain.id }}" - register: group_result + cloud: "{{ cloud }}" + state: present + name: ansible_group + domain_id: "{{ domain.domain.id }}" + register: group - name: Assert results assert: that: - - group_result is changed - - group_result.group.domain_id == domain.domain.id + - group is changed + - group.group.domain_id == domain.domain.id + +- name: List group by group name + openstack.cloud.identity_group_info: + cloud: "{{ cloud }}" + name: ansible_group + register: _groups + +- name: Assert groups by group name + assert: + that: + - _groups.groups | length == 2 + +- name: List group by domain_id + openstack.cloud.identity_group_info: + cloud: "{{ cloud }}" + domain: ansible_domain + register: _groups + +- name: Assert groups by domain_id + assert: + that: + - _groups.groups | length == 1 + - _groups.groups.0.id == group.group.id + - _groups.groups.0.domain_id == domain.domain.id + +- name: List group by domain_id and group name + openstack.cloud.identity_group_info: + cloud: "{{ cloud }}" + domain: ansible_domain + name: ansible_group + register: _groups + +- name: Assert groups by domain_id and group name + assert: + that: + - _groups.groups | length == 1 + - _groups.groups.0.id == group.group.id - name: Create group in specific domain again openstack.cloud.identity_group: - cloud: "{{ cloud }}" - state: present - name: "{{ group_name }}" - domain_id: "{{ domain.domain.id }}" - register: group_result + cloud: "{{ cloud }}" + state: present + name: ansible_group + domain_id: "{{ domain.domain.id }}" + register: group - name: Assert not changed assert: - that: group_result is not changed + that: + - group is not changed -- name: Delete ambiguous domain +- name: Delete ambiguous group openstack.cloud.identity_group: - cloud: "{{ cloud }}" - state: absent - name: "{{ group_name }}" + cloud: "{{ cloud }}" + state: absent + name: ansible_group ignore_errors: true - register: group_result + register: group - name: Assert failed assert: - that: group_result is failed + that: + - group is failed - name: Delete group in specific domain openstack.cloud.identity_group: - cloud: "{{ cloud }}" - state: absent - name: "{{ group_name }}" - domain_id: "{{ domain.domain.id }}" - register: group_result + cloud: "{{ cloud }}" + state: absent + name: ansible_group + domain_id: "{{ domain.domain.id }}" + register: group - name: Assert changed assert: - that: group_result is changed + that: + - group is changed - name: Delete group in specific domain again openstack.cloud.identity_group: - cloud: "{{ cloud }}" - state: absent - name: "{{ group_name }}" - domain_id: "{{ domain.domain.id }}" - register: group_result + cloud: "{{ cloud }}" + state: absent + name: ansible_group + domain_id: "{{ domain.domain.id }}" + register: group - name: Assert not changed assert: - that: group_result is not changed - -- name: Delete group - openstack.cloud.identity_group: - cloud: "{{ cloud }}" - state: absent - name: "{{ group_name }}" - register: group_result - -- name: Assert changed - assert: - that: group_result is changed - -- name: Delete group again - openstack.cloud.identity_group: - cloud: "{{ cloud }}" - state: absent - name: "{{ group_name }}" - register: group_result - -- name: Assert not changed - assert: - that: group_result is not changed + that: + - group is not changed - name: Delete domain openstack.cloud.identity_domain: cloud: "{{ cloud }}" state: absent - name: "{{ domain_name }}" + name: ansible_domain + +- name: Delete group + openstack.cloud.identity_group: + cloud: "{{ cloud }}" + state: absent + name: ansible_group + register: group + +- name: Assert changed + assert: + that: + - group is changed + +- name: Delete group again + openstack.cloud.identity_group: + cloud: "{{ cloud }}" + state: absent + name: ansible_group + register: group + +- name: Assert not changed + assert: + that: + - group is not changed + +- name: List group + openstack.cloud.identity_group_info: + cloud: "{{ cloud }}" + name: ansible_group + register: _groups + +- name: Assert group does not exist + assert: + that: + - _groups.groups | length == 0 diff --git a/ci/roles/identity_group_info/tasks/main.yml b/ci/roles/identity_group_info/tasks/main.yml deleted file mode 100644 index 16a0afa2..00000000 --- a/ci/roles/identity_group_info/tasks/main.yml +++ /dev/null @@ -1,74 +0,0 @@ ---- -- name: List group by domain_id - openstack.cloud.identity_group_info: - cloud: "{{ cloud }}" - domain: default - register: group_domain - -- name: Assert groups were returned - assert: - that: - - group_domain.groups | length > 0 - - group_domain.groups[0].domain_id == 'default' - - group_domain.groups[0].id is defined - - group_domain.groups[0].description is defined - - group_domain.groups[0].name is defined - -- name: List group by domain_id and group - openstack.cloud.identity_group_info: - cloud: "{{ cloud }}" - domain: default - name: admins - register: groups_info - -- name: Assert groups by domain_id and grouph returned - assert: - that: - - groups_info.groups | length > 0 - - groups_info.groups[0].domain_id == 'default' - - groups_info.groups[0].id is defined - - groups_info.groups[0].description is defined - - groups_info.groups[0].name is defined - -- name: List group by filter - openstack.cloud.identity_group_info: - cloud: "{{ cloud }}" - domain: default - filters: - name: admins - register: groups_filter - -- name: Assert group by filter returned - assert: - that: - - groups_filter.groups | length > 0 - - groups_filter.groups[0].domain_id == 'default' - - groups_filter.groups[0].id is defined - - groups_filter.groups[0].description is defined - - groups_filter.groups[0].name is defined - -- name: Verify returned values of group info - assert: - that: - - item in groups_info.groups[0] - loop: - - description - - domain_id - - id - - name - -- name: List group by group name - openstack.cloud.identity_group_info: - cloud: "{{ cloud }}" - name: admins - register: groups_name - -- name: Assert group by name returned - assert: - that: - - groups_name.groups | length > 0 - - groups_name.groups[0].domain_id == 'default' - - groups_name.groups[0].id is defined - - groups_name.groups[0].description is defined - - groups_name.groups[0].name is defined - - groups_name.groups[0].name == 'admins' diff --git a/ci/run-collection.yml b/ci/run-collection.yml index 32976eaa..0a4fd7d2 100644 --- a/ci/run-collection.yml +++ b/ci/run-collection.yml @@ -20,7 +20,6 @@ - { role: host_aggregate, tags: host_aggregate } - { role: identity_domain, tags: identity_domain } - { role: identity_group, tags: identity_group } - - { role: identity_group_info, tags: identity_group_info } - { role: identity_user, tags: identity_user } - { role: identity_user_info, tags: identity_user_info } - { role: identity_role, tags: identity_role } diff --git a/plugins/modules/identity_group.py b/plugins/modules/identity_group.py index 50d410b2..e4de42cb 100644 --- a/plugins/modules/identity_group.py +++ b/plugins/modules/identity_group.py @@ -4,94 +4,94 @@ # Copyright (c) 2016 IBM # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -DOCUMENTATION = ''' +DOCUMENTATION = r''' --- module: identity_group -short_description: Manage OpenStack Identity Groups +short_description: Manage a OpenStack identity (Keystone) group author: OpenStack Ansible SIG description: - - Manage OpenStack Identity Groups. Groups can be created, deleted or - updated. Only the I(description) value can be updated. + - Create, update or delete an OpenStack identity (Keystone) group. options: - description: - description: - - Group description - type: str - domain_id: - description: - - Domain id to create the group in if the cloud supports domains. - type: str - name: - description: - - Group name - required: true - type: str - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - type: str + description: + description: + - Group description. + type: str + domain_id: + description: + - Domain id to create the group in. + type: str + name: + description: + - Group name + required: true + type: str + state: + description: + - Should the resource be present or absent. + choices: ['present', 'absent'] + default: present + type: str extends_documentation_fragment: -- openstack.cloud.openstack + - openstack.cloud.openstack ''' -EXAMPLES = ''' -# Create a group named "demo" -- openstack.cloud.identity_group: +EXAMPLES = r''' +- name: Create a group named "demo" + openstack.cloud.identity_group: cloud: mycloud state: present name: demo description: "Demo Group" domain_id: demoid -# Update the description on existing "demo" group -- openstack.cloud.identity_group: +- name: Update the description on existing demo group + openstack.cloud.identity_group: cloud: mycloud state: present name: demo description: "Something else" domain_id: demoid -# Delete group named "demo" -- openstack.cloud.identity_group: +- name: Delete group named demo + openstack.cloud.identity_group: cloud: mycloud state: absent name: demo ''' -RETURN = ''' +RETURN = r''' group: - description: Dictionary describing the group. - returned: On success when I(state) is 'present'. - type: dict - contains: - description: - description: Group description - type: str - sample: "Demo Group" - domain_id: - description: Domain for the group - type: str - sample: "default" - id: - description: Unique group ID - type: str - sample: "ee6156ff04c645f481a6738311aea0b0" - name: - description: Group name - type: str - sample: "demo" + description: Dictionary describing the identity group. + returned: On success when I(state) is C(present). + type: dict + contains: + description: + description: Group description + type: str + sample: "Demo Group" + domain_id: + description: Domain for the group + type: str + sample: "default" + id: + description: Unique group ID + type: str + sample: "ee6156ff04c645f481a6738311aea0b0" + name: + description: Group name + type: str + sample: "demo" ''' from ansible_collections.openstack.cloud.plugins.module_utils.openstack import OpenStackModule +from ansible_collections.openstack.cloud.plugins.module_utils.resource import StateMachine class IdentityGroupModule(OpenStackModule): argument_spec = dict( - name=dict(required=True), description=dict(), domain_id=dict(), + name=dict(required=True), state=dict(default='present', choices=['absent', 'present']), ) @@ -99,57 +99,40 @@ class IdentityGroupModule(OpenStackModule): supports_check_mode=True ) - def _system_state_change(self, state, group): - if state == 'present' and not group: - return True - if state == 'present' and self._build_update(group): - return True - if state == 'absent' and group: - return True - return False + class _StateMachine(StateMachine): + def _find(self, attributes, **kwargs): + kwargs = dict((k, attributes[k]) + for k in ['domain_id'] + if k in attributes and attributes[k] is not None) - def _build_update(self, group): - update = {} - desc = self.params['description'] - if desc is not None and desc != group.description: - update['description'] = desc - return update + return self.find_function(attributes['name'], **kwargs) def run(self): - name = self.params['name'] - description = self.params['description'] - state = self.params['state'] - domain_id = self.params['domain_id'] + sm = self._StateMachine(connection=self.conn, + service_name='identity', + type_name='group', + sdk=self.sdk) - group_filters = {} - if domain_id is not None: - group_filters['domain_id'] = domain_id + kwargs = dict((k, self.params[k]) + for k in ['state', 'timeout'] + if self.params[k] is not None) - group = self.conn.identity.find_group(name, **group_filters) + kwargs['attributes'] = \ + dict((k, self.params[k]) + for k in ['description', 'domain_id', 'name'] + if self.params[k] is not None) - if self.ansible.check_mode: - self.exit_json(changed=self._system_state_change(state, group)) + group, is_changed = sm(check_mode=self.ansible.check_mode, + updateable_attributes=None, + non_updateable_attributes=['domain_id'], + wait=False, + **kwargs) - changed = False - if state == 'present': - if group is None: - kwargs = dict(description=description, domain_id=domain_id) - kwargs = {k: v for k, v in kwargs.items() if v is not None} - group = self.conn.identity.create_group( - name=name, **kwargs) - changed = True - else: - update = self._build_update(group) - if update: - group = self.conn.identity.update_group(group, **update) - changed = True - group = group.to_dict(computed=False) - self.exit_json(changed=changed, group=group) - - elif state == 'absent' and group is not None: - self.conn.identity.delete_group(group) - changed = True - self.exit_json(changed=changed) + if group is None: + self.exit_json(changed=is_changed) + else: + self.exit_json(changed=is_changed, + group=group.to_dict(computed=False)) def main(): diff --git a/plugins/modules/identity_group_info.py b/plugins/modules/identity_group_info.py index 483f04fd..33240ddc 100644 --- a/plugins/modules/identity_group_info.py +++ b/plugins/modules/identity_group_info.py @@ -4,108 +4,74 @@ # Copyright (c) 2019, Phillipe Smith # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -DOCUMENTATION = ''' +DOCUMENTATION = r''' --- module: identity_group_info -short_description: Retrieve info about one or more OpenStack groups +short_description: Fetch OpenStack identity (Keystone) groups author: OpenStack Ansible SIG description: - - Retrieve info about a one or more OpenStack groups. + - Fetch OpenStack identity (Keystone) groups. options: - name: - description: - - Name or ID of the group. - type: str - domain: - description: - - Name or ID of the domain containing the group 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 + domain: + description: + - Name or ID of the domain containing the group. + 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 group. + type: str extends_documentation_fragment: -- openstack.cloud.openstack + - openstack.cloud.openstack ''' -EXAMPLES = ''' -# Gather info about previously created groups -- name: gather info - hosts: localhost - tasks: - - name: Gather info about previously created groups - openstack.cloud.identity_group_info: - cloud: awesomecloud - register: openstack_groups - - debug: - var: openstack_groups +EXAMPLES = r''' +- name: Gather previously created groups + openstack.cloud.identity_group_info: + cloud: awesomecloud -# Gather info about a previously created group by name -- name: gather info - hosts: localhost - tasks: - - name: Gather info about a previously created group by name - openstack.cloud.identity_group_info: - cloud: awesomecloud - name: demogroup - register: openstack_groups - - debug: - var: openstack_groups +- name: Gather previously created groups by name + openstack.cloud.identity_group_info: + cloud: awesomecloud + name: demogroup -# Gather info about a previously created group in a specific domain -- name: gather info - hosts: localhost - tasks: - - name: Gather info about a previously created group in a specific domain - openstack.cloud.identity_group_info: - cloud: awesomecloud - name: demogroup - domain: admindomain - register: openstack_groups - - debug: - var: openstack_groups +- name: Gather previously created groups in a specific domain + openstack.cloud.identity_group_info: + cloud: awesomecloud + domain: admindomain -# Gather info about a previously created group in a specific domain with filter -- name: gather info - hosts: localhost - tasks: - - name: Gather info about a previously created group in a specific domain with filter - openstack.cloud.identity_group_info: - cloud: awesomecloud - name: demogroup - domain: admindomain - filters: - enabled: False - register: openstack_groups - - debug: - var: openstack_groups +- name: Gather and filter previously created groups + openstack.cloud.identity_group_info: + cloud: awesomecloud + name: demogroup + domain: admindomain + filters: + is_enabled: False ''' - -RETURN = ''' +RETURN = r''' groups: - description: Dictionary describing all the matching groups. - returned: always, but can be an empty list - type: list - elements: dict - contains: - name: - description: Name given to the group. - returned: success - type: str - description: - description: Description of the group. - returned: success - type: str - id: - description: Unique UUID. - returned: success - type: str - domain_id: - description: Domain ID containing the group (keystone v3 clouds only) - returned: success - type: bool + description: Dictionary describing all matching identity groups. + returned: always + type: list + elements: dict + contains: + name: + description: Name given to the group. + type: str + description: + description: Description of the group. + type: str + id: + description: Unique UUID. + type: str + domain_id: + description: Domain ID containing the group (keystone v3 clouds only) + type: bool ''' from ansible_collections.openstack.cloud.plugins.module_utils.openstack import OpenStackModule @@ -113,9 +79,9 @@ from ansible_collections.openstack.cloud.plugins.module_utils.openstack import O class IdentityGroupInfoModule(OpenStackModule): argument_spec = dict( - name=dict(), domain=dict(), filters=dict(type='dict'), + name=dict(), ) module_kwargs = dict( supports_check_mode=True @@ -123,20 +89,19 @@ class IdentityGroupInfoModule(OpenStackModule): def run(self): name = self.params['name'] - domain = self.params['domain'] filters = self.params['filters'] or {} - args = {} - if domain: - dom = self.conn.identity.find_domain(domain) - if dom: - args['domain_id'] = dom['id'] - else: - self.fail_json(msg='Domain name or ID does not exist') + 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'] - groups = self.conn.search_groups(name, filters, **args) - groups = [g.to_dict(computed=False) for g in groups] - self.exit_json(changed=False, groups=groups) + groups = self.conn.search_groups(name, filters, **kwargs) + self.exit_json(changed=False, + groups=[g.to_dict(computed=False) for g in groups]) def main():