316 lines
10 KiB
Python
316 lines
10 KiB
Python
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# Copied from: https://github.com/openstack-ansible/openstack-ansible-modules/blob/master/keystone_service
|
|
|
|
DOCUMENTATION = '''
|
|
---
|
|
module: keystone_service
|
|
short_description: Manage OpenStack Identity (keystone) service endpoints
|
|
options:
|
|
name:
|
|
description:
|
|
- name of service (e.g., keystone)
|
|
required: yes
|
|
type:
|
|
description:
|
|
- type of service (e.g., identity)
|
|
required: yes
|
|
description:
|
|
description:
|
|
- description of service (e.g., Identity Service)
|
|
required: yes
|
|
public_url:
|
|
description:
|
|
- public url of service.
|
|
- 'Alias: I(url)'
|
|
- 'Alias: I(publicurl)'
|
|
required: yes
|
|
internal_url:
|
|
description:
|
|
- internal url of service.
|
|
- 'Alias: I(internalurl)'
|
|
required: no
|
|
default: value of public_url
|
|
admin_url:
|
|
description:
|
|
- admin url of service.
|
|
- 'Alias: I(adminurl)'
|
|
required: no
|
|
default: value of public_url
|
|
insecure:
|
|
description:
|
|
- allow use of self-signed SSL certificates
|
|
required: no
|
|
choices: [ "yes", "no" ]
|
|
region:
|
|
description:
|
|
- region of service
|
|
required: yes
|
|
state:
|
|
description:
|
|
- Indicate desired state of the resource
|
|
choices: ['present', 'absent']
|
|
default: present
|
|
|
|
|
|
|
|
requirements: [ python-keystoneclient ]
|
|
author: Lorin Hochstein
|
|
'''
|
|
|
|
EXAMPLES = '''
|
|
examples:
|
|
keystone_service: >
|
|
name=keystone
|
|
type=identity
|
|
description="Keystone Identity Service"
|
|
publicurl=http://192.168.206.130:5000/v2.0
|
|
internalurl=http://192.168.206.130:5000/v2.0
|
|
adminurl=http://192.168.206.130:35357/v2.0
|
|
|
|
keystone_service: >
|
|
name=glance
|
|
type=image
|
|
description="Glance Identity Service"
|
|
url=http://192.168.206.130:9292
|
|
|
|
'''
|
|
|
|
try:
|
|
from keystoneclient.v2_0 import client
|
|
except ImportError:
|
|
keystoneclient_found = False
|
|
else:
|
|
keystoneclient_found = True
|
|
|
|
import traceback
|
|
|
|
|
|
def authenticate(endpoint, token, login_user, login_password, tenant_name,
|
|
insecure):
|
|
"""Return a keystone client object"""
|
|
|
|
if token:
|
|
return client.Client(endpoint=endpoint, token=token, insecure=insecure)
|
|
else:
|
|
return client.Client(auth_url=endpoint, username=login_user,
|
|
password=login_password, tenant_name=tenant_name,
|
|
insecure=insecure)
|
|
|
|
def get_service(keystone, name):
|
|
""" Retrieve a service by name """
|
|
services = [x for x in keystone.services.list() if x.name == name]
|
|
count = len(services)
|
|
if count == 0:
|
|
raise KeyError("No keystone services with name %s" % name)
|
|
elif count > 1:
|
|
raise ValueError("%d services with name %s" % (count, name))
|
|
else:
|
|
return services[0]
|
|
|
|
|
|
def get_endpoint(keystone, name):
|
|
""" Retrieve a service endpoint by name """
|
|
service = get_service(keystone, name)
|
|
endpoints = [x for x in keystone.endpoints.list()
|
|
if x.service_id == service.id]
|
|
count = len(endpoints)
|
|
if count == 0:
|
|
raise KeyError("No keystone endpoints with service name %s" % name)
|
|
elif count > 1:
|
|
raise ValueError("%d endpoints with service name %s" % (count, name))
|
|
else:
|
|
return endpoints[0]
|
|
|
|
|
|
def ensure_service_present(keystone, name, service_type, description,
|
|
check_mode):
|
|
""" Ensure the service is present and has the right values
|
|
|
|
Returns a pair, where the first element is a boolean that indicates
|
|
a state change, and the second element is the service uuid, or None
|
|
if running in check mode"""
|
|
service = None
|
|
try:
|
|
service = get_service(keystone, name)
|
|
except:
|
|
# Service doesn't exist yet, we'll need to create one
|
|
pass
|
|
else:
|
|
# See if it matches exactly
|
|
if service.name == name and \
|
|
service.type == service_type and \
|
|
service.description == description:
|
|
|
|
# Same, no changes needed
|
|
return (False, service.id)
|
|
|
|
# At this point, we know we will need to make a change
|
|
if check_mode:
|
|
return (True, None)
|
|
|
|
if service is None:
|
|
service = keystone.services.create(name=name,
|
|
service_type=service_type,
|
|
description=description)
|
|
return (True, service.id)
|
|
else:
|
|
msg = "keystone v2 API doesn't support updating services"
|
|
raise ValueError(msg)
|
|
|
|
|
|
def ensure_endpoint_present(keystone, name, public_url, internal_url,
|
|
admin_url, region, check_mode):
|
|
""" Ensure the service endpoint is present and have the right values
|
|
|
|
Assumes the service object has already been created at this point"""
|
|
|
|
service = get_service(keystone, name)
|
|
endpoint = None
|
|
try:
|
|
endpoint = get_endpoint(keystone, name)
|
|
except:
|
|
# Endpoint doesn't exist yet, we'll need to create one
|
|
pass
|
|
else:
|
|
# See if it matches
|
|
if endpoint.publicurl == public_url and \
|
|
endpoint.adminurl == admin_url and \
|
|
endpoint.internalurl == internal_url and \
|
|
endpoint.region == region:
|
|
|
|
# Same, no changes needed
|
|
return (False, endpoint.id)
|
|
|
|
# At this point, we know we will need to make a change
|
|
if check_mode:
|
|
return (True, None)
|
|
|
|
if endpoint is None:
|
|
endpoint = keystone.endpoints.create(region=region,
|
|
service_id=service.id,
|
|
publicurl=public_url,
|
|
adminurl=admin_url,
|
|
internalurl=internal_url)
|
|
return (True, endpoint.id)
|
|
else:
|
|
msg = "keystone v2 API doesn't support updating endpoints"
|
|
raise ValueError(msg)
|
|
|
|
|
|
def ensure_service_absent(keystone, name, check_mode):
|
|
""" Ensure the service is absent"""
|
|
|
|
service = get_service(keystone, name)
|
|
keystone.services.delete(service.id)
|
|
return True
|
|
|
|
def ensure_endpoint_absent(keystone, name, check_mode):
|
|
""" Ensure the service endpoint """
|
|
endpoint = get_endpoint(keystone, name)
|
|
keystone.endpoints.delete(endpoint.id)
|
|
return True
|
|
|
|
|
|
def dispatch(keystone, name, service_type, description, public_url,
|
|
internal_url, admin_url, region, state, check_mode):
|
|
|
|
if state == 'present':
|
|
(service_changed, service_id) = ensure_service_present(keystone,
|
|
name,
|
|
service_type,
|
|
description,
|
|
check_mode)
|
|
|
|
(endpoint_changed, endpoint_id) = ensure_endpoint_present(
|
|
keystone,
|
|
name,
|
|
public_url,
|
|
internal_url,
|
|
admin_url,
|
|
region,
|
|
check_mode)
|
|
return dict(changed=service_changed or endpoint_changed,
|
|
service_id=service_id,
|
|
endpoint_id=endpoint_id)
|
|
elif state == 'absent':
|
|
endpoint_changed = ensure_endpoint_absent(keystone, name, check_mode)
|
|
service_changed = ensure_service_absent(keystone, name, check_mode)
|
|
return dict(changed=service_changed or endpoint_changed)
|
|
else:
|
|
raise ValueError("Code should never reach here")
|
|
|
|
|
|
|
|
def main():
|
|
|
|
module = AnsibleModule(
|
|
argument_spec=dict(
|
|
name=dict(required=True),
|
|
type=dict(required=True),
|
|
description=dict(required=False),
|
|
public_url=dict(required=True, aliases=['url', 'publicurl']),
|
|
internal_url=dict(required=False, aliases=['internalurl']),
|
|
admin_url=dict(required=False, aliases=['adminurl']),
|
|
region=dict(required=True),
|
|
state=dict(default='present', choices=['present', 'absent']),
|
|
endpoint=dict(required=False,
|
|
default="http://127.0.0.1:35357/v2.0",
|
|
aliases=['auth_url']),
|
|
token=dict(required=False),
|
|
insecure=dict(required=False, default=False, choices=BOOLEANS),
|
|
|
|
login_user=dict(required=False),
|
|
login_password=dict(required=False),
|
|
tenant_name=dict(required=False, aliases=['tenant'])
|
|
),
|
|
supports_check_mode=True,
|
|
mutually_exclusive=[['token', 'login_user'],
|
|
['token', 'login_password'],
|
|
['token', 'tenant_name']]
|
|
)
|
|
|
|
endpoint = module.params['endpoint']
|
|
token = module.params['token']
|
|
login_user = module.params['login_user']
|
|
login_password = module.params['login_password']
|
|
tenant_name = module.params['tenant_name']
|
|
insecure = module.boolean(module.params['insecure'])
|
|
name = module.params['name']
|
|
service_type = module.params['type']
|
|
description = module.params['description']
|
|
public_url = module.params['public_url']
|
|
internal_url = module.params['internal_url']
|
|
if internal_url is None:
|
|
internal_url = public_url
|
|
admin_url = module.params['admin_url']
|
|
if admin_url is None:
|
|
admin_url = public_url
|
|
region = module.params['region']
|
|
state = module.params['state']
|
|
|
|
keystone = authenticate(endpoint, token, login_user, login_password,
|
|
tenant_name, insecure)
|
|
check_mode = module.check_mode
|
|
|
|
try:
|
|
d = dispatch(keystone, name, service_type, description,
|
|
public_url, internal_url, admin_url, region, state,
|
|
check_mode)
|
|
except Exception:
|
|
if check_mode:
|
|
# If we have a failure in check mode
|
|
module.exit_json(changed=True,
|
|
msg="exception: %s" % traceback.format_exc())
|
|
else:
|
|
module.fail_json(msg=traceback.format_exc())
|
|
else:
|
|
module.exit_json(**d)
|
|
|
|
|
|
# this is magic, see lib/ansible/module_common.py
|
|
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
|
if __name__ == '__main__':
|
|
main()
|