diff options
author | Dolph Mathews <dolph.mathews@gmail.com> | 2012-11-30 12:52:26 -0600 |
---|---|---|
committer | Adam Young <ayoung@redhat.com> | 2012-12-18 12:11:26 -0500 |
commit | 2f851340ee8969193b9dcc1913401aa9b33c5d97 (patch) | |
tree | c2706208dc3ce7ba30b202d98e2f2846b48c58ef /keystone/catalog | |
parent | 7db702cab1f2cad8160aeadc8c1ae27853b8a34c (diff) | |
download | keystone-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.py | 54 | ||||
-rw-r--r-- | keystone/catalog/controllers.py | 65 |
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): |