Add endpoint CRD

This introduces a CRD to manage endpoints and moves DevStack to use it
instead of using OpenStack CLI.

Change-Id: I90a8d8ba4b73c782f9669a3e7ab5ae1e2b6a9719
This commit is contained in:
Mohammed Naser 2020-04-26 17:04:34 -04:00 committed by okozachenko
parent 97501c4460
commit 84071196c6
9 changed files with 151 additions and 3 deletions

View File

@ -0,0 +1,24 @@
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: endpoints.identity.openstack.org
spec:
group: identity.openstack.org
names:
kind: Endpoint
listKind: EndpointList
plural: endpoints
singular: endpoint
scope: Cluster
version: v1alpha1
versions:
- name: v1alpha1
served: true
storage: true
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

View File

@ -114,6 +114,7 @@ rules:
resources:
- services
- keystones
- endpoints
verbs:
- create
- delete
@ -127,6 +128,7 @@ rules:
resources:
- services/status
- keystones/status
- endpoints/status
verbs:
- get
- patch

View File

@ -37,6 +37,8 @@ spec:
- -m
- openstack_operator.memcached
- -m
- openstack_operator.openstack.identity.endpoints
- -m
- openstack_operator.openstack.identity.services
- -m
- openstack_operator.rabbitmq

View File

@ -0,0 +1,9 @@
---
apiVersion: identity.openstack.org/v1alpha1
kind: Endpoint
metadata:
name: heat-public
spec:
service: orchestration
interface: public
url: https://orchestration.sjc1.vexxhost.net

View File

@ -135,3 +135,19 @@ function bootstrap_keystone {
--bootstrap-public-url "$KEYSTONE_SERVICE_URI"
}
export -f bootstrap_keystone
# Create an endpoint with a specific interface
# Usage: _get_or_create_endpoint_with_interface <service> <interface> <url> <region>
function _get_or_create_endpoint_with_interface {
cat <<EOF | kubectl apply -f-
---
apiVersion: identity.openstack.org/v1alpha1
kind: Endpoint
metadata:
name: ${1//_/-}-$2
spec:
service: $1
interface: $2
url: $3
EOF
}
export -f _get_or_create_endpoint_with_interface

View File

@ -0,0 +1,94 @@
# 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)

View File

@ -51,7 +51,6 @@ def create_or_resume(name, spec, **_):
conn = utils.get_openstack_connection()
service = _get_service(conn, name, spec["type"])
if service:
service = conn.update_service(service.id, name=name,
type=spec["type"],

View File

@ -16,5 +16,6 @@
- hosts: all
roles:
- collect-container-logs
- collect-kubernetes-logs
- collect-container-logs
- collect-kubernetes-logs

View File

@ -32,6 +32,7 @@
OS_USER_DOMAIN_ID: default
OS_USERNAME: admin
OS_PASSWORD: secretadmin
OS_REGION_NAME: RegionOne
EOF
roles:
- role: helm-template