add templated catalog backend

Fix a few other issues, and adds passive aggressive comments and
documentation.
This commit is contained in:
termie 2011-11-02 13:35:27 -07:00
parent 2ac753edfd
commit 4ba33be08e
7 changed files with 142 additions and 9 deletions

View File

@ -0,0 +1,81 @@
class TemplatedCatalog(object):
"""A backend that generates endpoints for the Catalog based on templates.
It is usually configured via config entries that look like:
catalog.$REGION.$SERVICE.$key = $value
and is stored in a similar looking hierarchy. Where a value can contain
values to be interpolated by standard python string interpolation that look
like (the % is replaced by a $ due to paste attmepting to interpolate on its
own:
http://localhost:$(public_port)s/
When expanding the template it will pass in a dict made up of the options
instance plus a few additional key-values, notably tenant_id and user_id.
It does not care what the keys and values are but it is worth noting that
keystone_compat will expect certain keys to be there so that it can munge
them into the output format keystone expects. These keys are:
name - the name of the service, most likely repeated for all services of
the same type, across regions.
adminURL - the url of the admin endpoint
publicURL - the url of the public endpoint
internalURL - the url of the internal endpoint
"""
def __init__(self, options, templates=None):
self.options = options
if templates:
self.templates = templates
else:
self._load_templates(options)
def _load_templates(self, options):
o = {}
for k, v in options.iteritems():
if not k.startswith('catalog.'):
continue
parts = k.split('.')
region = parts[1]
service = parts[2]
key = parts[3]
region_ref = o.get(region, {})
service_ref = region_ref.get(service, {})
service_ref[key] = v
region_ref[service] = service_ref
o[region] = region_ref
self.templates = o
def get_catalog(self, user_id, tenant_id, extras=None):
d = self.options.copy()
d.update({'tenant_id': tenant_id,
'user_id': user_id})
o = {}
for region, region_ref in self.templates.iteritems():
o[region] = {}
for service, service_ref in region_ref.iteritems():
o[region][service] = {}
for k, v in service_ref.iteritems():
v = v.replace('$(', '%(')
o[region][service][k] = v % d
return o

View File

@ -71,7 +71,10 @@ class KeystoneController(service.BaseApplication):
# more compat
if tenant_name:
tenant_id = self.identity_api.get_tenant_by_name(tenant_name)
tenant_ref = self.identity_api.get_tenant_by_name(
context=context, tenant_name=tenant_name)
tenant_id = tenant_ref['id']
logging.debug('RENANT: %s', tenant_ref)
else:
tenant_id = auth.get('tenantId', None)

View File

@ -1,3 +1,4 @@
import ConfigParser
import os
import unittest
import sys
@ -67,6 +68,9 @@ class TestCase(unittest.TestCase):
super(TestCase, self).__init__(*args, **kw)
self._paths = []
def setUp(self):
super(TestCase, self).setUp()
def tearDown(self):
for path in self._paths:
if path in sys.path:
@ -87,6 +91,11 @@ class TestCase(unittest.TestCase):
app = self.loadapp(config)
server = wsgi.Server()
server.start(app, 0, key='socket')
# Service catalog tests need to know the port we ran on.
options = self.appconfig(config)
port = server.socket_info['socket'][1]
options['public_port'] = port
return server
def client(self, app, *args, **kw):

View File

@ -2,8 +2,7 @@
catalog_driver = keystonelight.backends.kvs.KvsCatalog
identity_driver = keystonelight.backends.kvs.KvsIdentity
token_driver = keystonelight.backends.kvs.KvsToken
public_port = 8080
public_port = 5000
[filter:debug]
paste.filter_factory = keystonelight.wsgi:Debug.factory

View File

@ -0,0 +1,31 @@
[DEFAULT]
catalog_driver = keystonelight.backends.templated.TemplatedCatalog
identity_driver = keystonelight.backends.kvs.KvsIdentity
token_driver = keystonelight.backends.kvs.KvsToken
public_port = 5000
# config for TemplatedCatalog, using camelCase because I don't want to do
# translations for keystone compat
catalog.RegionOne.identity.publicURL = http://localhost:$(public_port)s/v2.0/$(tenant_id)s
catalog.RegionOne.identity.adminURL = http://localhost:$(public_port)s/v2.0/$(tenant_id)s
catalog.RegionOne.identity.internalURL = http://localhost:$(public_port)s/v2.0/$(tenant_id)s
# in old config:
# first 1 == public
# second 1 == enabled
[filter:debug]
paste.filter_factory = keystonelight.wsgi:Debug.factory
[filter:token_auth]
paste.filter_factory = keystonelight.service:TokenAuthMiddleware.factory
[filter:json_body]
paste.filter_factory = keystonelight.service:JsonBodyMiddleware.factory
[app:keystone]
paste.app_factory = keystonelight.keystone_compat:app_factory
[pipeline:main]
pipeline = token_auth json_body debug keystone

View File

@ -19,6 +19,15 @@ KEYSTONE_SAMPLE_DIR = 'keystone/content/common/samples'
class CompatTestCase(test.TestCase):
"""Test compatibility against various versions of keystone's docs.
It should be noted that the docs for any given revision have rarely, if ever,
reflected the actual usage or reliable sample output of the system, so these
tests are largely a study of frustration and its effects on developer
productivity.
"""
def setUp(self):
super(CompatTestCase, self).setUp()
@ -120,7 +129,7 @@ class DiabloCompatTestCase(CompatTestCase):
{'auth': {'passwordCredentials': {'username': self.user_123['id'],
'password': self.user_123['password'],
},
'tenantName': self.tenant_345['id']}})
'tenantName': self.tenant_345['name']}})
resp = client.post('/v2.0/tokens', body=post_data)
data = json.loads(resp.body)

View File

@ -18,15 +18,17 @@ class CompatTestCase(test.TestCase):
super(CompatTestCase, self).setUp()
class DiabloCompatTestCase(CompatTestCase):
class MasterCompatTestCase(CompatTestCase):
def setUp(self):
super(MasterCompatTestCase, self).setUp()
revdir = test.checkout_vendor(KEYSTONECLIENT_REPO, 'master')
self.add_path(revdir)
from keystoneclient.v2_0 import client as ks_client
reload(ks_client)
self.app = self.loadapp('keystone_compat_diablo')
self.options = self.appconfig('keystone_compat_diablo')
self.app = self.loadapp('keystoneclient_compat_master')
self.options = self.appconfig('keystoneclient_compat_master')
self.identity_backend = utils.import_object(
self.options['identity_driver'], options=self.options)
@ -35,7 +37,7 @@ class DiabloCompatTestCase(CompatTestCase):
self.catalog_backend = utils.import_object(
self.options['catalog_driver'], options=self.options)
self.server = self.serveapp('keystone_compat_diablo')
self.server = self.serveapp('keystoneclient_compat_master')
self.tenant_bar = self.identity_backend._create_tenant(
'bar',
@ -53,7 +55,6 @@ class DiabloCompatTestCase(CompatTestCase):
dict(roles=[],
roles_links=[]))
super(DiabloCompatTestCase, self).setUp()
def test_pass(self):
from keystoneclient.v2_0 import client as ks_client