summaryrefslogtreecommitdiffstats
path: root/keystone/catalog
diff options
context:
space:
mode:
authorDolph Mathews <dolph.mathews@gmail.com>2012-11-30 12:52:26 -0600
committerAdam Young <ayoung@redhat.com>2012-12-18 12:11:26 -0500
commit2f851340ee8969193b9dcc1913401aa9b33c5d97 (patch)
treec2706208dc3ce7ba30b202d98e2f2846b48c58ef /keystone/catalog
parent7db702cab1f2cad8160aeadc8c1ae27853b8a34c (diff)
downloadkeystone-2f851340ee8969193b9dcc1913401aa9b33c5d97.tar.gz
keystone-2f851340ee8969193b9dcc1913401aa9b33c5d97.tar.xz
keystone-2f851340ee8969193b9dcc1913401aa9b33c5d97.zip
Split endpoint records in SQL by interface
This migrates the SQL backend such that v2 endpoints containing up to 3 URL's (public, internal and admin) stored in 'extra' are split into unique endpoints. Because legacy "endpoints" (each having publicUrl, internalUrl and adminUrl) are no longer conceptually identical to v3's "endpoints" (each having an interface and a url), new ID's are assigned to each entity and each API continues to operate using with independent sets of endpoint ID's. Endpoints created on the v3 API are not exposed on the v2 API. Change-Id: I2ba59d55907313ae65e908585fc49be0c4ce899a
Diffstat (limited to 'keystone/catalog')
-rw-r--r--keystone/catalog/backends/sql.py54
-rw-r--r--keystone/catalog/controllers.py65
2 files changed, 87 insertions, 32 deletions
diff --git a/keystone/catalog/backends/sql.py b/keystone/catalog/backends/sql.py
index df128c7b..380d4660 100644
--- a/keystone/catalog/backends/sql.py
+++ b/keystone/catalog/backends/sql.py
@@ -36,12 +36,14 @@ class Service(sql.ModelBase, sql.DictBase):
class Endpoint(sql.ModelBase, sql.DictBase):
__tablename__ = 'endpoint'
- attributes = ['id', 'region', 'service_id']
+ attributes = ['id', 'interface', 'region', 'service_id', 'url']
id = sql.Column(sql.String(64), primary_key=True)
+ interface = sql.Column(sql.String(8), primary_key=True)
region = sql.Column('region', sql.String(255))
service_id = sql.Column(sql.String(64),
sql.ForeignKey('service.id'),
nullable=False)
+ url = sql.Column(sql.Text())
extra = sql.Column(sql.JsonBlob())
@@ -88,7 +90,9 @@ class Catalog(sql.Base, catalog.Driver):
old_dict = ref.to_dict()
old_dict.update(service_ref)
new_service = Service.from_dict(old_dict)
- ref.type = new_service.type
+ for attr in Service.attributes:
+ if attr != 'id':
+ setattr(ref, attr, getattr(new_service, attr))
ref.extra = new_service.extra
session.flush()
return ref.to_dict()
@@ -132,8 +136,9 @@ class Catalog(sql.Base, catalog.Driver):
old_dict = ref.to_dict()
old_dict.update(endpoint_ref)
new_endpoint = Endpoint.from_dict(old_dict)
- ref.service_id = new_endpoint.service_id
- ref.region = new_endpoint.region
+ for attr in Endpoint.attributes:
+ if attr != 'id':
+ setattr(ref, attr, getattr(new_endpoint, attr))
ref.extra = new_endpoint.extra
session.flush()
return ref.to_dict()
@@ -142,25 +147,28 @@ class Catalog(sql.Base, catalog.Driver):
d = dict(CONF.iteritems())
d.update({'tenant_id': tenant_id,
'user_id': user_id})
- catalog = {}
-
- endpoints = self.list_endpoints()
- for ep in endpoints:
- service = self.get_service(ep['service_id'])
- srv_type = service['type']
- srv_name = service['name']
- region = ep['region']
-
- if region not in catalog:
- catalog[region] = {}
- catalog[region][srv_type] = {}
-
- srv_type = catalog[region][srv_type]
- srv_type['id'] = ep['id']
- srv_type['name'] = srv_name
- srv_type['publicURL'] = core.format_url(ep.get('publicurl', ''), d)
- srv_type['internalURL'] = core.format_url(ep.get('internalurl'), d)
- srv_type['adminURL'] = core.format_url(ep.get('adminurl'), d)
+ catalog = {}
+ services = {}
+ for endpoint in self.list_endpoints():
+ # look up the service
+ services.setdefault(
+ endpoint['service_id'],
+ self.get_service(endpoint['service_id']))
+ service = services[endpoint['service_id']]
+
+ # add the endpoint to the catalog if it's not already there
+ catalog.setdefault(endpoint['region'], {})
+ catalog[endpoint['region']].setdefault(
+ service['type'], {
+ 'id': endpoint['id'],
+ 'name': service['name'],
+ 'publicURL': '', # this may be overridden, but must exist
+ })
+
+ # add the interface's url
+ url = core.format_url(endpoint.get('url'), d)
+ interface_url = '%sURL' % endpoint['interface']
+ catalog[endpoint['region']][service['type']][interface_url] = url
return catalog
diff --git a/keystone/catalog/controllers.py b/keystone/catalog/controllers.py
index b0460fc9..42ba4ed7 100644
--- a/keystone/catalog/controllers.py
+++ b/keystone/catalog/controllers.py
@@ -20,6 +20,13 @@ import uuid
from keystone.catalog import core
from keystone.common import controller
from keystone.common import wsgi
+from keystone import exception
+from keystone import identity
+from keystone import policy
+from keystone import token
+
+
+INTERFACES = ['public', 'internal', 'admin']
class Service(controller.V2Controller):
@@ -50,22 +57,62 @@ class Service(controller.V2Controller):
class Endpoint(controller.V2Controller):
def get_endpoints(self, context):
+ """Merge matching v3 endpoint refs into legacy refs."""
self.assert_admin(context)
- endpoint_list = self.catalog_api.list_endpoints(context)
- return {'endpoints': endpoint_list}
+ legacy_endpoints = {}
+ for endpoint in self.catalog_api.list_endpoints(context):
+ if not endpoint['legacy_endpoint_id']:
+ # endpoints created in v3 should not appear on the v2 API
+ continue
+
+ # is this is a legacy endpoint we haven't indexed yet?
+ if endpoint['legacy_endpoint_id'] not in legacy_endpoints:
+ legacy_ep = endpoint.copy()
+ legacy_ep['id'] = legacy_ep.pop('legacy_endpoint_id')
+ legacy_ep.pop('interface')
+ legacy_ep.pop('url')
+
+ legacy_endpoints[endpoint['legacy_endpoint_id']] = legacy_ep
+ else:
+ legacy_ep = legacy_endpoints[endpoint['legacy_endpoint_id']]
+
+ # add the legacy endpoint with an interface url
+ legacy_ep['%surl' % endpoint['interface']] = endpoint['url']
+ return {'endpoints': legacy_endpoints.values()}
def create_endpoint(self, context, endpoint):
+ """Create three v3 endpoint refs based on a legacy ref."""
self.assert_admin(context)
- endpoint_id = uuid.uuid4().hex
- endpoint_ref = endpoint.copy()
- endpoint_ref['id'] = endpoint_id
- new_endpoint_ref = self.catalog_api.create_endpoint(
- context, endpoint_id, endpoint_ref)
- return {'endpoint': new_endpoint_ref}
+
+ legacy_endpoint_ref = endpoint.copy()
+
+ urls = dict((i, endpoint.pop('%surl' % i)) for i in INTERFACES)
+ legacy_endpoint_id = uuid.uuid4().hex
+ for interface, url in urls.iteritems():
+ endpoint_ref = endpoint.copy()
+ endpoint_ref['id'] = uuid.uuid4().hex
+ endpoint_ref['legacy_endpoint_id'] = legacy_endpoint_id
+ endpoint_ref['interface'] = interface
+ endpoint_ref['url'] = url
+
+ self.catalog_api.create_endpoint(
+ context, endpoint_ref['id'], endpoint_ref)
+
+ legacy_endpoint_ref['id'] = legacy_endpoint_id
+ return {'endpoint': legacy_endpoint_ref}
def delete_endpoint(self, context, endpoint_id):
+ """Delete up to three v3 endpoint refs based on a legacy ref ID."""
self.assert_admin(context)
- self.catalog_api.delete_endpoint(context, endpoint_id)
+
+ deleted_at_least_one = False
+ for endpoint in self.catalog_api.list_endpoints(context):
+ if endpoint['legacy_endpoint_id'] == endpoint_id:
+ self.catalog_api.delete_endpoint(context, endpoint['id'])
+ deleted_at_least_one = True
+
+ if not deleted_at_least_one:
+ raise exception.EndpointNotFound(endpoint_id=endpoint_id)
class ServiceV3(controller.V3Controller):