ansible-collections-openstack/plugins/modules/endpoint.py
Jakob Meng 1b38b7c500 Properly documented openstacksdk version requirements
With "extends_documentation_fragment: ['openstack.cloud.openstack']"
it is not necessary to list required Python libraries in section
'requirements' of DOCUMENTATION docstring in modules. Ansible will
merge requirements from doc fragments and DOCUMENTATION docstring
which previously resulted in duplicates such as in server module [0]:

* openstacksdk
* openstacksdk >= 0.36, < 0.99.0
* python >= 3.6

When removing the 'requirements' section from server module, then
Ansible will list openstacksdk once only:

* openstacksdk >= 0.36, < 0.99.0
* python >= 3.6

To see what documentation Ansible will produce for server module run:

  ansible-doc --type module openstack.cloud.server

[0] https://docs.ansible.com/ansible/latest/collections/openstack/\
    cloud/server_module.html

Change-Id: I727ed95ee480bb644b5a533f6a9526973677064c
2023-01-16 13:51:01 +01:00

218 lines
6.2 KiB
Python

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, VEXXHOST, Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
DOCUMENTATION = '''
---
module: endpoint
short_description: Manage OpenStack Identity service endpoints
author: OpenStack Ansible SIG
description:
- Create, update, or delete OpenStack Identity service endpoints. If a
service with the same combination of I(service), I(interface) and
I(region) exist, the I(url), I(enabled) and I(state) (C(present) or
C(absent)) will be updated.
options:
service:
description:
- Name or id of the service.
required: true
type: str
endpoint_interface:
description:
- Interface of the service.
choices: [admin, public, internal]
required: true
type: str
url:
description:
- URL of the service.
required: true
type: str
region:
description:
- ID of the region that the service belongs to.
Note that I(region) is used for authentication.
type: str
enabled:
description:
- Is the service enabled.
default: True
type: bool
state:
description:
- Should the resource be C(present) or C(absent).
choices: [present, absent]
default: present
type: str
extends_documentation_fragment:
- openstack.cloud.openstack
'''
EXAMPLES = '''
- name: Create a service for glance
openstack.cloud.endpoint:
cloud: mycloud
service: glance
endpoint_interface: public
url: http://controller:9292
region: RegionOne
state: present
- name: Delete a service for nova
openstack.cloud.endpoint:
cloud: mycloud
service: nova
endpoint_interface: public
region: RegionOne
state: absent
'''
RETURN = '''
endpoint:
description: Dictionary describing the endpoint.
returned: On success when I(state) is C(present)
type: dict
contains:
id:
description: Endpoint ID.
type: str
sample: 3292f020780b4d5baf27ff7e1d224c44
interface:
description: Endpoint Interface.
type: str
sample: public
is_enabled:
description: Service status.
type: bool
sample: True
links:
description: Links for the endpoint
type: str
sample: http://controller/identity/v3/endpoints/123
name:
description: Name of the endpoint
type: str
sample: cinder
region_id:
description: Region ID.
type: str
sample: RegionOne
service_id:
description: Service ID.
type: str
sample: b91f1318f735494a825a55388ee118f3
url:
description: Service URL.
type: str
sample: http://controller:9292
'''
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import OpenStackModule
class IdentityEndpointModule(OpenStackModule):
argument_spec = dict(
service=dict(required=True),
endpoint_interface=dict(required=True, choices=['admin', 'public', 'internal']),
url=dict(required=True),
region=dict(),
enabled=dict(type='bool', default=True),
state=dict(default='present', choices=['absent', 'present']),
)
module_kwargs = dict(
supports_check_mode=True
)
def _needs_update(self, endpoint):
if endpoint.is_enabled != self.params['enabled']:
return True
if endpoint.url != self.params['url']:
return True
return False
def _system_state_change(self, endpoint):
state = self.params['state']
if state == 'absent' and endpoint:
return True
if state == 'present':
if endpoint is None:
return True
return self._needs_update(endpoint)
return False
def run(self):
service_name_or_id = self.params['service']
interface = self.params['endpoint_interface']
url = self.params['url']
# Regions have IDs but do not have names
# Ref.: https://docs.openstack.org/api-ref/identity/v3/#regions
region_id = self.params['region']
enabled = self.params['enabled']
state = self.params['state']
service = self.conn.identity.find_service(service_name_or_id)
if service is None and state == 'absent':
self.exit_json(changed=False)
if service is None and state == 'present':
self.fail_json(msg='Service %s does not exist' % service_name_or_id)
filters = dict(service_id=service.id, interface=interface)
if region_id:
filters['region_id'] = region_id
endpoints = list(self.conn.identity.endpoints(**filters))
endpoint = None
if len(endpoints) > 1:
self.fail_json(msg='Service %s, interface %s and region %s are '
'not unique' %
(service_name_or_id, interface, region_id))
elif len(endpoints) == 1:
endpoint = endpoints[0]
if self.ansible.check_mode:
self.exit_json(changed=self._system_state_change(endpoint))
changed = False
if state == 'present':
if not endpoint:
args = {
'url': url,
'interface': interface,
'service_id': service.id,
'enabled': enabled,
'region_id': region_id
}
endpoint = self.conn.identity.create_endpoint(**args)
changed = True
elif self._needs_update(endpoint):
endpoint = self.conn.identity.update_endpoint(
endpoint.id, url=url, enabled=enabled)
changed = True
self.exit_json(changed=changed,
endpoint=endpoint.to_dict(computed=False))
elif state == 'absent' and endpoint:
self.conn.identity.delete_endpoint(endpoint.id)
changed = True
self.exit_json(changed=changed)
def main():
module = IdentityEndpointModule()
module()
if __name__ == '__main__':
main()