diff --git a/ci/roles/keystone_mapping/defaults/main.yml b/ci/roles/keystone_mapping/defaults/main.yml index 6cc843eb..760ae469 100644 --- a/ci/roles/keystone_mapping/defaults/main.yml +++ b/ci/roles/keystone_mapping/defaults/main.yml @@ -1,4 +1,5 @@ mapping_name: 'ansible-test-mapping' +mapping_name_2: 'ansible-test-mapping-2' mapping_rules_1: - local: - group: diff --git a/ci/roles/keystone_mapping/tasks/main.yml b/ci/roles/keystone_mapping/tasks/main.yml index 93cdea79..aae57882 100644 --- a/ci/roles/keystone_mapping/tasks/main.yml +++ b/ci/roles/keystone_mapping/tasks/main.yml @@ -5,6 +5,8 @@ # cloud: "{{ cloud }}" openstack.cloud.os_keystone_mapping: cloud: "{{ cloud }}" + openstack.cloud.os_keystone_mapping_info: + cloud: "{{ cloud }}" block: - name: "Ensure mapping doesn't exist to start" openstack.cloud.os_keystone_mapping: @@ -27,6 +29,15 @@ - create_mapping is successful - create_mapping is changed + - name: 'Fetch mapping info (mapping should be absent)' + openstack.cloud.os_keystone_mapping_info: + name: '{{ mapping_name }}' + register: mapping_info + ignore_errors: yes + - assert: + that: + - mapping_info is failed + - name: 'Create mapping' openstack.cloud.os_keystone_mapping: state: 'present' @@ -44,6 +55,42 @@ - create_mapping.mapping.name == mapping_name - create_mapping.mapping.rules | length == 1 + - name: 'Fetch mapping info - with name' + openstack.cloud.os_keystone_mapping_info: + name: '{{ mapping_name }}' + register: mapping_info + - assert: + that: + - mapping_info is successful + - '"mappings" in mapping_info' + - mapping_info.mappings | length == 1 + - '"id" in mapping_0' + - '"name" in mapping_0' + - '"rules" in mapping_0' + - mapping_0.id == mapping_name + - mapping_0.name == mapping_name + - mapping_0.rules | length == 1 + vars: + mapping_0: '{{ mapping_info.mappings[0] }}' + + - name: 'Fetch mapping info - without name' + openstack.cloud.os_keystone_mapping_info: {} + register: mapping_info + - assert: + that: + - mapping_info is successful + - '"mappings" in mapping_info' + # In CI we generally have a clean slate, but this might + # not be true for everyone... + - mapping_info.mappings | length >= 1 + - '"id" in mapping_0' + - '"name" in mapping_0' + - '"rules" in mapping_0' + - mapping_name in (mapping_info.mappings | map(attribute='id')) + - mapping_name in (mapping_info.mappings | map(attribute='name')) + vars: + mapping_0: '{{ mapping_info.mappings[0] }}' + - name: 'Create mapping (retry - no change) - CHECK_MODE' openstack.cloud.os_keystone_mapping: state: 'present' @@ -119,6 +166,65 @@ - update_mapping.mapping.name == mapping_name - update_mapping.mapping.rules | length == 1 + - name: 'Create second mapping' + openstack.cloud.os_keystone_mapping: + state: 'present' + name: '{{ mapping_name_2 }}' + rules: '{{ mapping_rules_1 }}' + register: create_mapping + - assert: + that: + - create_mapping is successful + - create_mapping is changed + - '"id" in create_mapping.mapping' + - '"name" in create_mapping.mapping' + - '"rules" in create_mapping.mapping' + - create_mapping.mapping.id == mapping_name_2 + - create_mapping.mapping.name == mapping_name_2 + - create_mapping.mapping.rules | length == 1 + + - name: 'Fetch mapping (2) info - with name' + openstack.cloud.os_keystone_mapping_info: + name: '{{ mapping_name_2 }}' + register: mapping_info + - assert: + that: + - mapping_info is successful + - '"mappings" in mapping_info' + - mapping_info.mappings | length == 1 + - '"id" in mapping_0' + - '"name" in mapping_0' + - '"rules" in mapping_0' + - mapping_0.id == mapping_name_2 + - mapping_0.name == mapping_name_2 + - mapping_0.rules | length == 1 + vars: + mapping_0: '{{ mapping_info.mappings[0] }}' + + - name: 'Fetch mapping info - without name' + openstack.cloud.os_keystone_mapping_info: {} + register: mapping_info + - assert: + that: + - mapping_info is successful + - '"mappings" in mapping_info' + # In CI we generally have a clean slate, but this might + # not be true for everyone... + - mapping_info.mappings | length >= 2 + - '"id" in mapping_0' + - '"name" in mapping_0' + - '"rules" in mapping_0' + - '"id" in mapping_1' + - '"name" in mapping_1' + - '"rules" in mapping_1' + - mapping_name in (mapping_info.mappings | map(attribute='id')) + - mapping_name in (mapping_info.mappings | map(attribute='name')) + - mapping_name_2 in (mapping_info.mappings | map(attribute='id')) + - mapping_name_2 in (mapping_info.mappings | map(attribute='name')) + vars: + mapping_0: '{{ mapping_info.mappings[0] }}' + mapping_1: '{{ mapping_info.mappings[1] }}' + - name: 'Delete mapping - CHECK_MODE' openstack.cloud.os_keystone_mapping: state: 'absent' @@ -161,9 +267,34 @@ - delete_mapping is successful - delete_mapping is not changed + - name: 'Fetch mapping info after deletion' + openstack.cloud.os_keystone_mapping_info: + name: '{{ mapping_name }}' + register: mapping_info + ignore_errors: True + - assert: + that: + - mapping_info is failed + + - name: 'Delete second mapping' + openstack.cloud.os_keystone_mapping: + state: 'absent' + name: '{{ mapping_name_2 }}' + register: delete_mapping + - assert: + that: + - delete_mapping is successful + - delete_mapping is changed + always: - name: 'Delete mapping' openstack.cloud.os_keystone_mapping: state: 'absent' name: '{{ mapping_name }}' ignore_errors: yes + + - name: 'Delete second mapping' + openstack.cloud.os_keystone_mapping: + state: 'absent' + name: '{{ mapping_name_2 }}' + ignore_errors: yes diff --git a/meta/action_groups.yml b/meta/action_groups.yml index a3e7d287..be296e86 100644 --- a/meta/action_groups.yml +++ b/meta/action_groups.yml @@ -17,6 +17,7 @@ os: - os_keystone_domain_info - os_keystone_endpoint - os_keystone_mapping +- os_keystone_mapping_info - os_keystone_role - os_keystone_service - os_listener diff --git a/plugins/modules/os_keystone_mapping_info.py b/plugins/modules/os_keystone_mapping_info.py new file mode 100644 index 00000000..41780e42 --- /dev/null +++ b/plugins/modules/os_keystone_mapping_info.py @@ -0,0 +1,104 @@ +#!/usr/bin/python +# Copyright: Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +ANSIBLE_METADATA = {'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'community'} + + +DOCUMENTATION = ''' +--- +module: os_keystone_mapping_info +short_description: Get the information about the available federation mappings +author: + - "Mark Chappell (@tremble) " +description: + - Fetch a federation mapping. +options: + name: + description: + - The name of the mapping to fetch. + - If I(name) is specified, the module will return failed if the mapping + doesn't exist. + type: str + aliases: ['id'] +requirements: + - "python >= 3.6" + - "openstacksdk >= 0.44" +extends_documentation_fragment: + - openstack.cloud.openstack +''' + +EXAMPLES = ''' +- name: Fetch a specific mapping + os_keystone_mapping_info: + cloud: example_cloud + name: example_mapping + +- name: Fetch all mappings + os_keystone_mapping_info: + cloud: example_cloud +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.openstack.cloud.plugins.module_utils.openstack import openstack_full_argument_spec +from ansible_collections.openstack.cloud.plugins.module_utils.openstack import openstack_module_kwargs +from ansible_collections.openstack.cloud.plugins.module_utils.openstack import openstack_cloud_from_module + + +def normalize_mapping(mapping): + """ + Normalizes the mapping definitions so that the outputs are consistent with the + parameters + + - "name" (parameter) == "id" (SDK) + """ + if mapping is None: + return None + + _mapping = mapping.to_dict() + _mapping['name'] = mapping['id'] + return _mapping + + +def main(): + """ Module entry point """ + + argument_spec = openstack_full_argument_spec( + name=dict(aliases=['id']), + ) + module_kwargs = openstack_module_kwargs( + ) + module = AnsibleModule( + argument_spec, + supports_check_mode=True, + **module_kwargs + ) + + name = module.params.get('name') + + sdk, cloud = openstack_cloud_from_module(module, min_version="0.44") + + if name: + try: + mapping = normalize_mapping(cloud.identity.get_mapping(name)) + except sdk.exceptions.ResourceNotFound: + module.fail_json(msg='Failed to find mapping') + except sdk.exceptions.OpenStackCloudException as ex: + module.fail_json(msg='Failed to get mapping: {0}'.format(str(ex))) + module.exit_json(changed=False, mappings=[mapping]) + + else: + try: + mappings = list(map(normalize_mapping, cloud.identity.mappings())) + except sdk.exceptions.OpenStackCloudException as ex: + module.fail_json(msg='Failed to list mappings: {0}'.format(str(ex))) + module.exit_json(changed=False, mappings=mappings) + + +if __name__ == '__main__': + main()