
This introduces a CRD to manage endpoints and moves DevStack to use it instead of using OpenStack CLI. Change-Id: I90a8d8ba4b73c782f9669a3e7ab5ae1e2b6a9719
95 lines
3.0 KiB
Python
95 lines
3.0 KiB
Python
# Copyright 2020 VEXXHOST, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""Endpoints Operator
|
|
|
|
This operator helps manage the creation and removal of endpoints inside
|
|
Keystone using custom resources.
|
|
"""
|
|
|
|
import kopf
|
|
from openstack_operator import utils
|
|
|
|
|
|
def _get_service_by_type(conn, service_type):
|
|
"""Get a service from Keystone based on service type."""
|
|
|
|
services = conn.search_services(filters={"type": service_type})
|
|
|
|
if len(services) > 1:
|
|
raise RuntimeError("Multiple services with type: %s" % service_type)
|
|
if len(services) == 0:
|
|
raise RuntimeError("Unable to find service: %s" % service_type)
|
|
return services[0]
|
|
|
|
|
|
def _get_endpoint(conn, service_type, interface):
|
|
"""Get an endpoint from Keystone
|
|
|
|
This method will retrieve the endpoint from Keystone, raise an error if it
|
|
found more than one or return None if it couldn't find it
|
|
"""
|
|
|
|
service = _get_service_by_type(conn, service_type)
|
|
|
|
filters = {
|
|
"service_id": service.id,
|
|
"interface": interface,
|
|
"region": conn.config.get_region_name(),
|
|
}
|
|
endpoints = conn.search_endpoints(filters=filters)
|
|
|
|
if len(endpoints) > 1:
|
|
raise RuntimeError("Found multiple endpoints with interface & region")
|
|
if len(endpoints) == 0:
|
|
return service, None
|
|
return service, endpoints[0]
|
|
|
|
|
|
@kopf.on.resume('identity.openstack.org', 'v1alpha1', 'endpoints')
|
|
@kopf.on.create('identity.openstack.org', 'v1alpha1', 'endpoints')
|
|
def create_or_resume(spec, **_):
|
|
"""Create or resume controller
|
|
|
|
This function runs when a new resource is created or when the controller
|
|
is first started. It creates or updates the appropriate endpoint.
|
|
"""
|
|
|
|
conn = utils.get_openstack_connection()
|
|
service, endpoint = _get_endpoint(conn, spec["service"], spec["interface"])
|
|
if endpoint:
|
|
conn.update_endpoint(endpoint.id, url=spec["url"])
|
|
return
|
|
|
|
conn.create_endpoint(service_name_or_id=service.id, url=spec["url"],
|
|
interface=spec["interface"],
|
|
region=conn.config.get_region_name())
|
|
|
|
|
|
@kopf.on.delete('identity.openstack.org', 'v1alpha1', 'endpoints')
|
|
def delete(spec, **_):
|
|
"""Delete an endpoint
|
|
|
|
This function runs when the endpoint CR is deleted and removes the record
|
|
from Keystone.
|
|
"""
|
|
|
|
conn = utils.get_openstack_connection()
|
|
endpoint = _get_endpoint(conn, spec["service"], spec["interface"])
|
|
|
|
if not endpoint:
|
|
return
|
|
|
|
conn.delete_endpoint(endpoint)
|