From feadf7576058f47f2bb1f0bc097d45101e8c1562 Mon Sep 17 00:00:00 2001 From: termie Date: Fri, 6 Jan 2012 21:00:41 -0800 Subject: [PATCH] config system overhaul we're now based on nova's config system which mainly means that you will have to call config.CONF with a config file at some point during tests or running an executable --- keystonelight/backends/kvs.py | 8 +- keystonelight/backends/policy.py | 6 -- keystonelight/backends/sql/core.py | 32 ++------ keystonelight/backends/sql/migration.py | 24 +++--- keystonelight/backends/templated.py | 25 +++--- keystonelight/catalog.py | 10 ++- keystonelight/config.py | 49 +++++++++++ keystonelight/identity.py | 11 +-- keystonelight/keystone_compat.py | 103 +++++++++++------------- keystonelight/middleware.py | 6 +- keystonelight/policy.py | 10 ++- keystonelight/service.py | 25 +++--- keystonelight/test.py | 58 +++---------- keystonelight/token.py | 10 ++- keystonelight/wsgi.py | 12 ++- tests/default.conf | 42 +++++----- tests/default_catalog.templates | 12 +++ tests/keystone_compat_diablo.conf | 17 +++- tests/keystoneclient_compat_master.conf | 34 ++++---- tests/test_backend_kvs.py | 9 +-- tests/test_backend_sql.py | 20 +++-- tests/test_identity_api.py | 12 ++- tests/test_keystoneclient_compat.py | 9 ++- tests/test_legacy_compat.py | 35 ++++---- tests/test_novaclient_compat.py | 6 +- 25 files changed, 304 insertions(+), 281 deletions(-) create mode 100644 keystonelight/config.py create mode 100644 tests/default_catalog.templates diff --git a/keystonelight/backends/kvs.py b/keystonelight/backends/kvs.py index 5bb8eddd27..4394f34776 100644 --- a/keystonelight/backends/kvs.py +++ b/keystonelight/backends/kvs.py @@ -10,7 +10,7 @@ INMEMDB = DictKvs() class KvsIdentity(object): - def __init__(self, options, db=None): + def __init__(self, db=None): if db is None: db = INMEMDB elif type(db) is type({}): @@ -189,7 +189,7 @@ class KvsIdentity(object): class KvsToken(object): - def __init__(self, options, db=None): + def __init__(self, db=None): if db is None: db = INMEMDB elif type(db) is type({}): @@ -209,7 +209,7 @@ class KvsToken(object): class KvsCatalog(object): - def __init__(self, options, db=None): + def __init__(self, db=None): if db is None: db = INMEMDB elif type(db) is type({}): @@ -251,7 +251,7 @@ class KvsCatalog(object): class KvsPolicy(object): - def __init__(self, options, db=None): + def __init__(self, db=None): if db is None: db = INMEMDB elif type(db) is type({}): diff --git a/keystonelight/backends/policy.py b/keystonelight/backends/policy.py index 6bdcacb80b..bb33548db1 100644 --- a/keystonelight/backends/policy.py +++ b/keystonelight/backends/policy.py @@ -2,17 +2,11 @@ import logging class TrivialTrue(object): - def __init__(self, options): - self.options = options - def can_haz(self, target, credentials): return True class SimpleMatch(object): - def __init__(self, options): - self.options = options - def can_haz(self, target, credentials): """Check whether key-values in target are present in credentials.""" # TODO(termie): handle ANDs, probably by providing a tuple instead of a diff --git a/keystonelight/backends/sql/core.py b/keystonelight/backends/sql/core.py index 060a98aebe..211d9ca261 100644 --- a/keystonelight/backends/sql/core.py +++ b/keystonelight/backends/sql/core.py @@ -10,9 +10,13 @@ import sqlalchemy.orm import sqlalchemy.pool import sqlalchemy.engine.url +from keystonelight import config from keystonelight import models +CONF = config.CONF + + Base = declarative.declarative_base() @@ -121,9 +125,6 @@ class SqlBase(object): _MAKER = None _ENGINE = None - def __init__(self, options): - self.options = options - def get_session(self, autocommit=True, expire_on_commit=False): """Return a SQLAlchemy session.""" if self._MAKER is None or self._ENGINE is None: @@ -138,36 +139,17 @@ class SqlBase(object): def get_engine(self): """Return a SQLAlchemy engine.""" - connection_dict = sqlalchemy.engine.url.make_url( - self.options.get('sql_connection')) + connection_dict = sqlalchemy.engine.url.make_url(CONF.sql.connection) engine_args = { - "pool_recycle": self.options.get('sql_idle_timeout'), + "pool_recycle": CONF.sql.idle_timeout, "echo": False, } if "sqlite" in connection_dict.drivername: engine_args["poolclass"] = sqlalchemy.pool.NullPool - #elif MySQLdb and "mysql" in connection_dict.drivername: - # LOG.info(_("Using mysql/eventlet db_pool.")) - # # MySQLdb won't accept 'None' in the password field - # password = connection_dict.password or '' - # pool_args = { - # "db": connection_dict.database, - # "passwd": password, - # "host": connection_dict.host, - # "user": connection_dict.username, - # "min_size": self.options.get('sql_min_pool_size'), - # "max_size": self.options.get('sql_max_pool_size'), - # "max_idle": self.options.get('sql_idle_timeout'), - # } - # creator = eventlet.db_pool.ConnectionPool(MySQLdb, **pool_args) - # engine_args["pool_size"] = self.options.get('sql_max_pool_size') - # engine_args["pool_timeout"] = self.options('sql_pool_timeout') - # engine_args["creator"] = creator.create - return sql.create_engine(self.options.get('sql_connection'), - **engine_args) + return sql.create_engine(CONF.sql.connection, **engine_args) def get_maker(self, engine, autocommit=True, expire_on_commit=False): """Return a SQLAlchemy sessionmaker using the given engine.""" diff --git a/keystonelight/backends/sql/migration.py b/keystonelight/backends/sql/migration.py index 1a4794b7e8..106bcea7ee 100644 --- a/keystonelight/backends/sql/migration.py +++ b/keystonelight/backends/sql/migration.py @@ -22,6 +22,12 @@ import sys import sqlalchemy from migrate.versioning import api as versioning_api +from keystonelight import config + + +CONF = config.CONF + + try: from migrate.versioning import exceptions as versioning_exceptions except ImportError: @@ -33,36 +39,36 @@ except ImportError: sys.exit("python-migrate is not installed. Exiting.") -def db_sync(options, version=None): +def db_sync(version=None): if version is not None: try: version = int(version) except ValueError: raise Exception("version should be an integer") - current_version = db_version(options) + current_version = db_version() repo_path = _find_migrate_repo() if version is None or version > current_version: return versioning_api.upgrade( - options.get('sql_connection'), repo_path, version) + CONF.sql.connection, repo_path, version) else: return versioning_api.downgrade( - options.get('sql_connection'), repo_path, version) + CONF.sql.connection, repo_path, version) -def db_version(options): +def db_version(): repo_path = _find_migrate_repo() try: return versioning_api.db_version( - options.get('sql_connection'), repo_path) + CONF.sql.connection, repo_path) except versioning_exceptions.DatabaseNotControlledError: - return db_version_control(options, 0) + return db_version_control(0) -def db_version_control(options, version=None): +def db_version_control(version=None): repo_path = _find_migrate_repo() versioning_api.version_control( - options.get('sql_connection'), repo_path, version) + CONF.sql.connection, repo_path, version) return version diff --git a/keystonelight/backends/templated.py b/keystonelight/backends/templated.py index 4ba5575851..155839b2be 100644 --- a/keystonelight/backends/templated.py +++ b/keystonelight/backends/templated.py @@ -1,7 +1,12 @@ +from keystonelight import config from keystonelight import logging from keystonelight.backends import kvs +CONF = config.CONF +config.register_str('template_file', group='catalog') + + class TemplatedCatalog(kvs.KvsCatalog): """A backend that generates endpoints for the Catalog based on templates. @@ -16,7 +21,7 @@ class TemplatedCatalog(kvs.KvsCatalog): http://localhost:$(public_port)s/ - When expanding the template it will pass in a dict made up of the options + When expanding the template it will pass in a dict made up of the conf 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 @@ -31,19 +36,21 @@ class TemplatedCatalog(kvs.KvsCatalog): """ - def __init__(self, options, templates=None): - self.options = options - + def __init__(self, templates=None): if templates: self.templates = templates else: - self._load_templates(options) + self._load_templates(CONF.catalog.template_file) - super(TemplatedCatalog, self).__init__(options) + super(TemplatedCatalog, self).__init__() - def _load_templates(self, options): + def _load_templates(self, template_file): o = {} - for k, v in options.iteritems(): + for line in open(template_file): + if ' = ' not in line: + continue + + k, v = line.split(' = ') if not k.startswith('catalog.'): continue @@ -64,7 +71,7 @@ class TemplatedCatalog(kvs.KvsCatalog): self.templates = o def get_catalog(self, user_id, tenant_id, extras=None): - d = self.options.copy() + d = dict(CONF.iteritems()) d.update({'tenant_id': tenant_id, 'user_id': user_id}) diff --git a/keystonelight/catalog.py b/keystonelight/catalog.py index 382b00ffaa..b4d472732e 100644 --- a/keystonelight/catalog.py +++ b/keystonelight/catalog.py @@ -2,14 +2,16 @@ # the catalog interfaces +from keystonelight import config from keystonelight import utils +CONF = config.CONF + + class Manager(object): - def __init__(self, options): - self.options = options - self.driver = utils.import_object(options['catalog_driver'], - options=options) + def __init__(self): + self.driver = utils.import_object(CONF.catalog.driver) def get_catalog(self, context, user_id, tenant_id, extras=None): """Return info for a catalog if it is valid.""" diff --git a/keystonelight/config.py b/keystonelight/config.py new file mode 100644 index 0000000000..03d6a24b81 --- /dev/null +++ b/keystonelight/config.py @@ -0,0 +1,49 @@ + + +from keystonelight import cfg + + +class Config(cfg.ConfigOpts): + def __call__(self, config_files=None, *args, **kw): + if config_files is None: + config_files = [] + self.config_file = config_files + super(Config, self).__call__(*args, **kw) + + def __getitem__(self, key, default=None): + return getattr(self, key, default) + + def __setitem__(self, key, value): + return setattr(self, key, value) + + def iteritems(self): + for k in self._opts: + yield (k, getattr(self, k)) + + +def register_str(*args, **kw): + group = kw.pop('group', None) + if group: + CONF.register_group(cfg.OptGroup(name=group)) + return CONF.register_opt(cfg.StrOpt(*args, **kw), group=group) + + +CONF = Config() + + +register_str('admin_token', default='ADMIN') +register_str('compute_port') +register_str('admin_port') +register_str('public_port') + +# sql options +register_str('connection', group='sql') +register_str('idle_timeout', group='sql') +register_str('min_pool_size', group='sql') +register_str('maz_pool_size', group='sql') +register_str('pool_timeout', group='sql') + +register_str('driver', group='catalog') +register_str('driver', group='identity') +register_str('driver', group='policy') +register_str('driver', group='token') diff --git a/keystonelight/identity.py b/keystonelight/identity.py index 52959ef979..93e8d309a5 100644 --- a/keystonelight/identity.py +++ b/keystonelight/identity.py @@ -2,15 +2,16 @@ # backends will make use of them to return something that conforms to their # apis - +from keystonelight import config from keystonelight import utils +CONF = config.CONF + + class Manager(object): - def __init__(self, options): - self.driver = utils.import_object(options['identity_driver'], - options=options) - self.options = options + def __init__(self): + self.driver = utils.import_object(CONF.identity.driver) def authenticate(self, context, **kwargs): """Passthru authentication to the identity driver. diff --git a/keystonelight/keystone_compat.py b/keystonelight/keystone_compat.py index 0fd998e196..b720477ca9 100644 --- a/keystonelight/keystone_compat.py +++ b/keystonelight/keystone_compat.py @@ -18,13 +18,11 @@ from keystonelight import wsgi class KeystoneAdminRouter(wsgi.Router): - def __init__(self, options): - self.options = options - + def __init__(self): mapper = routes.Mapper() # Token Operations - auth_controller = KeystoneTokenController(self.options) + auth_controller = KeystoneTokenController() mapper.connect('/tokens', controller=auth_controller, action='authenticate', @@ -39,7 +37,7 @@ class KeystoneAdminRouter(wsgi.Router): conditions=dict(method=['GET'])) # Tenant Operations - tenant_controller = KeystoneTenantController(self.options) + tenant_controller = KeystoneTenantController() mapper.connect('/tenants', controller=tenant_controller, action='get_tenants_for_token', @@ -50,14 +48,14 @@ class KeystoneAdminRouter(wsgi.Router): conditions=dict(method=['GET'])) # User Operations - user_controller = KeystoneUserController(self.options) + user_controller = KeystoneUserController() mapper.connect('/users/{user_id}', controller=user_controller, action='get_user', conditions=dict(method=['GET'])) # Role Operations - roles_controller = KeystoneRoleController(self.options) + roles_controller = KeystoneRoleController() mapper.connect('/tenants/{tenant_id}/users/{user_id}/roles', controller=roles_controller, action='get_user_roles', @@ -68,13 +66,13 @@ class KeystoneAdminRouter(wsgi.Router): conditions=dict(method=['GET'])) # Miscellaneous Operations - version_controller = KeystoneVersionController(self.options) + version_controller = KeystoneVersionController() mapper.connect('/', controller=version_controller, action='get_version_info', module='admin/version', conditions=dict(method=['GET'])) - extensions_controller = KeystoneExtensionsController(self.options) + extensions_controller = KeystoneExtensionsController() mapper.connect('/extensions', controller=extensions_controller, action='get_extensions_info', @@ -84,12 +82,11 @@ class KeystoneAdminRouter(wsgi.Router): class KeystoneServiceRouter(wsgi.Router): - def __init__(self, options): - self.options = options + def __init__(self): mapper = routes.Mapper() # Token Operations - auth_controller = KeystoneTokenController(self.options) + auth_controller = KeystoneTokenController() mapper.connect('/tokens', controller=auth_controller, action='authenticate', @@ -100,21 +97,21 @@ class KeystoneServiceRouter(wsgi.Router): conditions=dict(methods=['POST'])) # Tenant Operations - tenant_controller = KeystoneTenantController(self.options) + tenant_controller = KeystoneTenantController() mapper.connect('/tenants', controller=tenant_controller, action='get_tenants_for_token', conditions=dict(methods=['GET'])) # Miscellaneous - version_controller = KeystoneVersionController(self.options) + version_controller = KeystoneVersionController() mapper.connect('/', controller=version_controller, action='get_version_info', module='service/version', conditions=dict(method=['GET'])) - extensions_controller = KeystoneExtensionsController(self.options) + extensions_controller = KeystoneExtensionsController() mapper.connect('/extensions', controller=extensions_controller, action='get_extensions_info', @@ -130,13 +127,12 @@ class KeystoneAdminCrudExtension(wsgi.ExtensionRouter): """ - def __init__(self, application, options): - self.options = options + def __init__(self, application): mapper = routes.Mapper() - tenant_controller = KeystoneTenantController(self.options) - user_controller = KeystoneUserController(self.options) - role_controller = KeystoneRoleController(self.options) - service_controller = KeystoneServiceController(self.options) + tenant_controller = KeystoneTenantController() + user_controller = KeystoneUserController() + role_controller = KeystoneRoleController() + service_controller = KeystoneServiceController() # Tenant Operations mapper.connect("/tenants", controller=tenant_controller, @@ -270,16 +266,15 @@ class KeystoneAdminCrudExtension(wsgi.ExtensionRouter): conditions=dict(method=["DELETE"])) super(KeystoneAdminCrudExtension, self).__init__( - application, options, mapper) + application, mapper) class KeystoneTokenController(service.BaseApplication): - def __init__(self, options): - self.options = options - self.catalog_api = catalog.Manager(options) - self.identity_api = identity.Manager(options) - self.token_api = token.Manager(options) - self.policy_api = policy.Manager(options) + def __init__(self): + self.catalog_api = catalog.Manager() + self.identity_api = identity.Manager() + self.token_api = token.Manager() + self.policy_api = policy.Manager() super(KeystoneTokenController, self).__init__() def authenticate(self, context, auth=None): @@ -496,11 +491,10 @@ class KeystoneTokenController(service.BaseApplication): class KeystoneTenantController(service.BaseApplication): - def __init__(self, options): - self.options = options - self.identity_api = identity.Manager(options) - self.policy_api = policy.Manager(options) - self.token_api = token.Manager(options) + def __init__(self): + self.identity_api = identity.Manager() + self.policy_api = policy.Manager() + self.token_api = token.Manager() super(KeystoneTenantController, self).__init__() def get_tenants_for_token(self, context, **kw): @@ -578,12 +572,11 @@ class KeystoneTenantController(service.BaseApplication): class KeystoneUserController(service.BaseApplication): - def __init__(self, options): - self.options = options - self.catalog_api = catalog.Manager(options) - self.identity_api = identity.Manager(options) - self.token_api = token.Manager(options) - self.policy_api = policy.Manager(options) + def __init__(self): + self.catalog_api = catalog.Manager() + self.identity_api = identity.Manager() + self.policy_api = policy.Manager() + self.token_api = token.Manager() super(KeystoneUserController, self).__init__() def get_user(self, context, user_id): @@ -644,12 +637,11 @@ class KeystoneUserController(service.BaseApplication): class KeystoneRoleController(service.BaseApplication): - def __init__(self, options): - self.options = options - self.catalog_api = catalog.Manager(options) - self.identity_api = identity.Manager(options) - self.token_api = token.Manager(options) - self.policy_api = policy.Manager(options) + def __init__(self): + self.catalog_api = catalog.Manager() + self.identity_api = identity.Manager() + self.token_api = token.Manager() + self.policy_api = policy.Manager() super(KeystoneRoleController, self).__init__() def get_user_roles(self, context, user_id, tenant_id=None): @@ -748,12 +740,11 @@ class KeystoneRoleController(service.BaseApplication): class KeystoneServiceController(service.BaseApplication): - def __init__(self, options): - self.options = options - self.catalog_api = catalog.Manager(options) - self.identity_api = identity.Manager(options) - self.token_api = token.Manager(options) - self.policy_api = policy.Manager(options) + def __init__(self): + self.catalog_api = catalog.Manager() + self.identity_api = identity.Manager() + self.token_api = token.Manager() + self.policy_api = policy.Manager() super(KeystoneServiceController, self).__init__() # CRUD extensions @@ -783,8 +774,7 @@ class KeystoneServiceController(service.BaseApplication): class KeystoneVersionController(service.BaseApplication): - def __init__(self, options): - self.options = options + def __init__(self): super(KeystoneVersionController, self).__init__() def get_version_info(self, context, module='version'): @@ -792,8 +782,7 @@ class KeystoneVersionController(service.BaseApplication): class KeystoneExtensionsController(service.BaseApplication): - def __init__(self, options): - self.options = options + def __init__(self): super(KeystoneExtensionsController, self).__init__() def get_extensions_info(self, context): @@ -803,10 +792,10 @@ class KeystoneExtensionsController(service.BaseApplication): def service_app_factory(global_conf, **local_conf): conf = global_conf.copy() conf.update(local_conf) - return KeystoneServiceRouter(conf) + return KeystoneServiceRouter() def admin_app_factory(global_conf, **local_conf): conf = global_conf.copy() conf.update(local_conf) - return KeystoneAdminRouter(conf) + return KeystoneAdminRouter() diff --git a/keystonelight/middleware.py b/keystonelight/middleware.py index b8baabc98e..9ab528549d 100644 --- a/keystonelight/middleware.py +++ b/keystonelight/middleware.py @@ -1,8 +1,12 @@ import json +from keystonelight import config from keystonelight import wsgi +CONF = config.CONF + + # Header used to transmit the auth token AUTH_TOKEN_HEADER = 'X-Auth-Token' @@ -34,7 +38,7 @@ class AdminTokenAuthMiddleware(wsgi.Middleware): def process_request(self, request): token = request.headers.get(AUTH_TOKEN_HEADER) context = request.environ.get(CONTEXT_ENV, {}) - context['is_admin'] = (token == self.options['admin_token']) + context['is_admin'] = (token == CONF.admin_token) request.environ[CONTEXT_ENV] = context diff --git a/keystonelight/policy.py b/keystonelight/policy.py index 147c650196..0143878d31 100644 --- a/keystonelight/policy.py +++ b/keystonelight/policy.py @@ -4,14 +4,16 @@ import uuid +from keystonelight import config from keystonelight import utils +CONF = config.CONF + + class Manager(object): - def __init__(self, options): - self.options = options - self.driver = utils.import_object(options['policy_driver'], - options=options) + def __init__(self): + self.driver = utils.import_object(CONF.policy.driver) def can_haz(self, context, target, credentials): """Check whether the given creds can perform action on target.""" diff --git a/keystonelight/service.py b/keystonelight/service.py index 210250cb6d..50e8377c14 100644 --- a/keystonelight/service.py +++ b/keystonelight/service.py @@ -97,9 +97,8 @@ class BaseApplication(wsgi.Application): class TokenController(BaseApplication): """Validate and pass through calls to TokenManager.""" - def __init__(self, options): - self.token_api = token.Manager(options=options) - self.options = options + def __init__(self): + self.token_api = token.Manager() def validate_token(self, context, token_id): token_info = self.token_api.validate_token(context, token_id) @@ -115,10 +114,9 @@ class IdentityController(BaseApplication): a specific driver. """ - def __init__(self, options): - self.identity_api = identity.Manager(options=options) - self.token_api = token.Manager(options=options) - self.options = options + def __init__(self): + self.identity_api = identity.Manager() + self.token_api = token.Manager() def noop(self, context, *args, **kw): return '' @@ -207,10 +205,9 @@ class IdentityController(BaseApplication): class Router(wsgi.Router): - def __init__(self, options): - self.options = options - self.identity_controller = IdentityController(options) - self.token_controller = TokenController(options) + def __init__(self): + self.identity_controller = IdentityController() + self.token_controller = TokenController() mapper = self._build_map(URLMAP) mapper.connect('/', controller=self.identity_controller, action='noop') @@ -238,6 +235,6 @@ class Router(wsgi.Router): def app_factory(global_conf, **local_conf): - conf = global_conf.copy() - conf.update(local_conf) - return Router(conf) + #conf = global_conf.copy() + #conf.update(local_conf) + return Router() diff --git a/keystonelight/test.py b/keystonelight/test.py index 2045520a02..8af0888048 100644 --- a/keystonelight/test.py +++ b/keystonelight/test.py @@ -8,6 +8,7 @@ import time from paste import deploy +from keystonelight import config from keystonelight import logging from keystonelight import models from keystonelight import utils @@ -17,7 +18,7 @@ from keystonelight import wsgi ROOTDIR = os.path.dirname(os.path.dirname(__file__)) VENDOR = os.path.join(ROOTDIR, 'vendor') TESTSDIR = os.path.join(ROOTDIR, 'tests') - +CONF = config.CONF cd = os.chdir @@ -94,21 +95,14 @@ class TestCase(unittest.TestCase): for path in self._paths: if path in sys.path: sys.path.remove(path) + CONF.reset() super(TestCase, self).tearDown() - #TODO(termie): probably make this take an argument and use that for `options` def load_backends(self): - """Hacky shortcut to load the backends for data manipulation. - - Expects self.options to have already been set. - - """ - self.identity_api = utils.import_object( - self.options['identity_driver'], options=self.options) - self.token_api = utils.import_object( - self.options['token_driver'], options=self.options) - self.catalog_api = utils.import_object( - self.options['catalog_driver'], options=self.options) + """Hacky shortcut to load the backends for data manipulation.""" + self.identity_api = utils.import_object(CONF.identity.driver) + self.token_api = utils.import_object(CONF.token.driver) + self.catalog_api = utils.import_object(CONF.catalog.driver) def load_fixtures(self, fixtures): """Hacky basic and naive fixture loading based on a python module. @@ -164,44 +158,10 @@ class TestCase(unittest.TestCase): # Service catalog tests need to know the port we ran on. port = server.socket_info['socket'][1] - self._update_server_options(server, 'public_port', port) - self._update_server_options(server, 'admin_port', port) + CONF.public_port = port + CONF.admin_port = port return server - def _update_server_options(self, server, key, value): - """Hack to allow us to make changes to the options used by backends. - - A possible better solution would be to have a global config registry. - - """ - last = server - - applications = [] - - while (hasattr(last, 'applications') - or hasattr(last, 'application') - or hasattr(last, 'options')): - - #logging.debug('UPDATE %s: O %s A %s AS %s', - # last.__class__, - # getattr(last, 'options', None), - # getattr(last, 'application', None), - # getattr(last, 'applications', None)) - if hasattr(last, 'options'): - last.options[key] = value - - # NOTE(termie): paste.urlmap.URLMap stores applications in this format - if hasattr(last, 'applications'): - for app in last.applications: - applications.append(app[1]) - - if hasattr(last, 'application'): - last = last.application - elif len(applications): - last = applications.pop() - else: - break - def client(self, app, *args, **kw): return TestClient(app, *args, **kw) diff --git a/keystonelight/token.py b/keystonelight/token.py index a4c814e572..9e334f185e 100644 --- a/keystonelight/token.py +++ b/keystonelight/token.py @@ -4,15 +4,17 @@ import uuid +from keystonelight import config from keystonelight import logging from keystonelight import utils +CONF = config.CONF + + class Manager(object): - def __init__(self, options): - self.options = options - self.driver = utils.import_object(options['token_driver'], - options=options) + def __init__(self): + self.driver = utils.import_object(CONF.token.driver) def create_token(self, context, data): token = uuid.uuid4().hex diff --git a/keystonelight/wsgi.py b/keystonelight/wsgi.py index 0744fd32a8..401b0f0136 100644 --- a/keystonelight/wsgi.py +++ b/keystonelight/wsgi.py @@ -107,7 +107,7 @@ class Application(object): but using the kwarg passing it shouldn't be necessary. """ - return cls(**local_config) + return cls() def __call__(self, environ, start_response): r"""Subclasses will probably want to implement __call__ like this: @@ -182,12 +182,11 @@ class Middleware(Application): def _factory(app): conf = global_config.copy() conf.update(local_config) - return cls(app, conf) + return cls(app) return _factory - def __init__(self, application, options): + def __init__(self, application): self.application = application - self.options = options def process_request(self, req): """Called on each request. @@ -315,8 +314,7 @@ class ExtensionRouter(Router): Expects to be subclassed. """ - def __init__(self, application, options, mapper): - self.options = options + def __init__(self, application, mapper): self.application = application mapper.connect('{path_info:.*}', controller=self.application) @@ -348,5 +346,5 @@ class ExtensionRouter(Router): def _factory(app): conf = global_config.copy() conf.update(local_config) - return cls(app, conf) + return cls(app) return _factory diff --git a/tests/default.conf b/tests/default.conf index 295fe6ff53..8d54558c69 100644 --- a/tests/default.conf +++ b/tests/default.conf @@ -1,32 +1,28 @@ [DEFAULT] -catalog_driver = keystonelight.backends.templated.TemplatedCatalog -identity_driver = keystonelight.backends.kvs.KvsIdentity -token_driver = keystonelight.backends.kvs.KvsToken -policy_driver = keystonelight.backends.policy.SimpleMatch public_port = 5000 admin_port = 35357 admin_token = ADMIN - -# 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 -catalog.RegionOne.identity.adminURL = http://localhost:$(admin_port)s/v2.0 -catalog.RegionOne.identity.internalURL = http://localhost:$(admin_port)s/v2.0 -catalog.RegionOne.identity.name = 'Identity Service' - -# fake compute service for now to help novaclient tests work compute_port = 3000 -catalog.RegionOne.compute.publicURL = http://localhost:$(compute_port)s/v1.1/$(tenant_id)s -catalog.RegionOne.compute.adminURL = http://localhost:$(compute_port)s/v1.1/$(tenant_id)s -catalog.RegionOne.compute.internalURL = http://localhost:$(compute_port)s/v1.1/$(tenant_id)s -catalog.RegionOne.compute.name = 'Compute Service' -# for sql backends -sql_connection = sqlite:///bla.db -sql_idle_timeout = 200 -sql_min_pool_size = 5 -sql_max_pool_size = 10 -sql_pool_timeout = 200 +[sql] +connection = sqlite:///bla.db +idle_timeout = 200 +min_pool_size = 5 +max_pool_size = 10 +pool_timeout = 200 + +[identity] +driver = keystonelight.backends.kvs.KvsIdentity + +[catalog] +driver = keystonelight.backends.templated.TemplatedCatalog +template_file = default_catalog.templates + +[token] +driver = keystonelight.backends.kvs.KvsToken + +[policy] +driver = keystonelight.backends.policy.SimpleMatch [filter:debug] diff --git a/tests/default_catalog.templates b/tests/default_catalog.templates new file mode 100644 index 0000000000..c12b5c4ca7 --- /dev/null +++ b/tests/default_catalog.templates @@ -0,0 +1,12 @@ +# 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 +catalog.RegionOne.identity.adminURL = http://localhost:$(admin_port)s/v2.0 +catalog.RegionOne.identity.internalURL = http://localhost:$(admin_port)s/v2.0 +catalog.RegionOne.identity.name = 'Identity Service' + +# fake compute service for now to help novaclient tests work +catalog.RegionOne.compute.publicURL = http://localhost:$(compute_port)s/v1.1/$(tenant_id)s +catalog.RegionOne.compute.adminURL = http://localhost:$(compute_port)s/v1.1/$(tenant_id)s +catalog.RegionOne.compute.internalURL = http://localhost:$(compute_port)s/v1.1/$(tenant_id)s +catalog.RegionOne.compute.name = 'Compute Service' diff --git a/tests/keystone_compat_diablo.conf b/tests/keystone_compat_diablo.conf index f50c7706d6..b629a71098 100644 --- a/tests/keystone_compat_diablo.conf +++ b/tests/keystone_compat_diablo.conf @@ -1,12 +1,21 @@ [DEFAULT] -catalog_driver = keystonelight.backends.kvs.KvsCatalog -identity_driver = keystonelight.backends.kvs.KvsIdentity -token_driver = keystonelight.backends.kvs.KvsToken -policy_driver = keystonelight.backends.policy.SimpleMatch public_port = 5000 admin_port = 35357 admin_token = ADMIN +[identity] +driver = keystonelight.backends.kvs.KvsIdentity + +[catalog] +driver = keystonelight.backends.kvs.KvsCatalog + +[token] +driver = keystonelight.backends.kvs.KvsToken + +[policy] +driver = keystonelight.backends.policy.SimpleMatch + + [filter:debug] paste.filter_factory = keystonelight.wsgi:Debug.factory diff --git a/tests/keystoneclient_compat_master.conf b/tests/keystoneclient_compat_master.conf index 1930c50cae..1e531112e7 100644 --- a/tests/keystoneclient_compat_master.conf +++ b/tests/keystoneclient_compat_master.conf @@ -1,25 +1,27 @@ [DEFAULT] -catalog_driver = keystonelight.backends.templated.TemplatedCatalog -identity_driver = keystonelight.backends.kvs.KvsIdentity -token_driver = keystonelight.backends.kvs.KvsToken -policy_driver = keystonelight.backends.policy.SimpleMatch public_port = 5000 admin_port = 35357 admin_token = ADMIN -# 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 -catalog.RegionOne.identity.adminURL = http://localhost:$(admin_port)s/v2.0 -catalog.RegionOne.identity.internalURL = http://localhost:$(public_port)s/v2.0 -catalog.RegionOne.identity.name = 'Identity Service' +[sql] +connection = sqlite:///bla.db +idle_timeout = 200 +min_pool_size = 5 +max_pool_size = 10 +pool_timeout = 200 -# fake compute port for now to help novaclient tests work -compute_port = 3000 -catalog.RegionOne.compute.publicURL = http://localhost:$(compute_port)s/v2.0 -catalog.RegionOne.compute.adminURL = http://localhost:$(compute_port)s/v2.0 -catalog.RegionOne.compute.internalURL = http://localhost:$(compute_port)s/v2.0 -catalog.RegionOne.compute.name = 'Compute Service' +[identity] +driver = keystonelight.backends.kvs.KvsIdentity + +[catalog] +driver = keystonelight.backends.templated.TemplatedCatalog +template_file = default_catalog.templates + +[token] +driver = keystonelight.backends.kvs.KvsToken + +[policy] +driver = keystonelight.backends.policy.SimpleMatch [filter:debug] diff --git a/tests/test_backend_kvs.py b/tests/test_backend_kvs.py index ca367c476e..05987101a8 100644 --- a/tests/test_backend_kvs.py +++ b/tests/test_backend_kvs.py @@ -11,16 +11,14 @@ import default_fixtures class KvsIdentity(test.TestCase, test_backend.IdentityTests): def setUp(self): super(KvsIdentity, self).setUp() - self.options = self.appconfig('default') - self.identity_api = kvs.KvsIdentity(options=self.options, db={}) + self.identity_api = kvs.KvsIdentity(db={}) self.load_fixtures(default_fixtures) class KvsToken(test.TestCase): def setUp(self): super(KvsToken, self).setUp() - options = self.appconfig('default') - self.token_api = kvs.KvsToken(options=options, db={}) + self.token_api = kvs.KvsToken(db={}) def test_token_crud(self): token_id = uuid.uuid4().hex @@ -40,8 +38,7 @@ class KvsToken(test.TestCase): class KvsCatalog(test.TestCase): def setUp(self): super(KvsCatalog, self).setUp() - options = self.appconfig('default') - self.catalog_api = kvs.KvsCatalog(options=options, db={}) + self.catalog_api = kvs.KvsCatalog(db={}) self._load_fixtures() def _load_fixtures(self): diff --git a/tests/test_backend_sql.py b/tests/test_backend_sql.py index bee4ec33fc..2bdc224555 100644 --- a/tests/test_backend_sql.py +++ b/tests/test_backend_sql.py @@ -1,6 +1,7 @@ import os import uuid +from keystonelight import config from keystonelight import models from keystonelight import test from keystonelight.backends import sql @@ -10,20 +11,27 @@ import test_backend import default_fixtures +CONF = config.CONF + + + class SqlIdentity(test.TestCase, test_backend.IdentityTests): def setUp(self): super(SqlIdentity, self).setUp() - self.options = self.appconfig('default') - os.unlink('bla.db') - migration.db_sync(self.options, 1) - self.identity_api = sql.SqlIdentity(options=self.options) + try: + os.unlink('bla.db') + except Exception: + pass + CONF(config_files=['default.conf']) + migration.db_sync(1) + self.identity_api = sql.SqlIdentity() self.load_fixtures(default_fixtures) #class SqlToken(test_backend_kvs.KvsToken): # def setUp(self): # super(SqlToken, self).setUp() -# self.token_api = sql.SqlToken(options=options) +# self.token_api = sql.SqlToken() # self.load_fixtures(default_fixtures) # def test_token_crud(self): @@ -44,7 +52,7 @@ class SqlIdentity(test.TestCase, test_backend.IdentityTests): #class SqlCatalog(test_backend_kvs.KvsCatalog): # def setUp(self): # super(SqlCatalog, self).setUp() -# self.catalog_api = sql.SqlCatalog(options=options) +# self.catalog_api = sql.SqlCatalog() # self._load_fixtures() # def _load_fixtures(self): diff --git a/tests/test_identity_api.py b/tests/test_identity_api.py index c9d0ae28ac..b48c5078d3 100644 --- a/tests/test_identity_api.py +++ b/tests/test_identity_api.py @@ -1,16 +1,20 @@ import json from keystonelight import client +from keystonelight import config from keystonelight import models from keystonelight import test import default_fixtures +CONF = config.CONF + + class IdentityApi(test.TestCase): def setUp(self): super(IdentityApi, self).setUp() - self.options = self.appconfig('default') + CONF(config_files=['default.conf']) self.app = self.loadapp('default') self.load_backends() @@ -54,7 +58,7 @@ class IdentityApi(test.TestCase): self.assertDictEquals(self.tenant_bar, data[0]) def test_crud_user(self): - token_id = self.options['admin_token'] + token_id = CONF.admin_token c = client.TestClient(self.app, token=token_id) user_ref = models.User(name='FOO') resp = c.create_user(**user_ref) @@ -84,7 +88,7 @@ class IdentityApi(test.TestCase): #self.assertEquals(delget_resp.status, '404 Not Found') def test_crud_tenant(self): - token_id = self.options['admin_token'] + token_id = CONF.admin_token c = client.TestClient(self.app, token=token_id) tenant_ref = models.Tenant(name='BAZ') resp = c.create_tenant(**tenant_ref) @@ -128,7 +132,7 @@ class IdentityApi(test.TestCase): #self.assertEquals(delget_resp.status, '404 Not Found') def test_crud_extras(self): - token_id = self.options['admin_token'] + token_id = CONF.admin_token user_id = 'foo' tenant_id = 'bar' c = client.TestClient(self.app, token=token_id) diff --git a/tests/test_keystoneclient_compat.py b/tests/test_keystoneclient_compat.py index 04714a53ab..933f3c1440 100644 --- a/tests/test_keystoneclient_compat.py +++ b/tests/test_keystoneclient_compat.py @@ -1,8 +1,9 @@ +from keystonelight import config from keystonelight import test import default_fixtures - +CONF = config.CONF KEYSTONECLIENT_REPO = 'git://github.com/openstack/python-keystoneclient.git' @@ -12,12 +13,12 @@ class CompatTestCase(test.TestCase): def _public_url(self): public_port = self.public_server.socket_info['socket'][1] - self.options['public_port'] = public_port + CONF.public_port = public_port return "http://localhost:%s/v2.0" % public_port def _admin_url(self): admin_port = self.admin_server.socket_info['socket'][1] - self.options['admin_port'] = admin_port + CONF.admin_port = admin_port return "http://localhost:%s/v2.0" % admin_port def _client(self, **kwargs): @@ -41,7 +42,7 @@ class MasterCompatTestCase(CompatTestCase): from keystoneclient.v2_0 import client as ks_client reload(ks_client) - self.options = self.appconfig('keystoneclient_compat_master') + CONF(config_files=['keystoneclient_compat_master.conf']) self.public_app = self.loadapp('keystoneclient_compat_master', name='main') self.admin_app = self.loadapp('keystoneclient_compat_master', diff --git a/tests/test_legacy_compat.py b/tests/test_legacy_compat.py index 98c2ffdc5a..9fea88bf22 100644 --- a/tests/test_legacy_compat.py +++ b/tests/test_legacy_compat.py @@ -5,12 +5,16 @@ import sys from nose import exc +from keystonelight import config from keystonelight import logging from keystonelight import models from keystonelight import test from keystonelight import utils +CONF = config.CONF + + IDENTITY_API_REPO = 'git://github.com/openstack/identity-api.git' KEYSTONE_REPO = 'git://github.com/openstack/keystone.git' NOVACLIENT_REPO = 'git://github.com/rackspace/python-novaclient.git' @@ -46,16 +50,16 @@ class CompatTestCase(test.TestCase): os.path.join(self.sampledir, 'auth.json'))) # validate_token call - self.tenant_345 = self.identity_backend.create_tenant( + self.tenant_345 = self.identity_api.create_tenant( '345', models.Tenant(id='345', name='My Project')) - self.user_123 = self.identity_backend.create_user( + self.user_123 = self.identity_api.create_user( '123', models.User(id='123', name='jqsmith', tenants=[self.tenant_345['id']], password='password')) - self.extras_123 = self.identity_backend.create_extras( + self.extras_123 = self.identity_api.create_extras( self.user_123['id'], self.tenant_345['id'], dict(roles=[{'id': '234', 'name': 'compute:admin'}, @@ -63,7 +67,7 @@ class CompatTestCase(test.TestCase): 'name': 'object-store:admin', 'tenantId': '1'}], roles_links=[])) - self.token_123 = self.token_backend.create_token( + self.token_123 = self.token_api.create_token( 'ab48a9efdfedb23ty3494', models.Token(id='ab48a9efdfedb23ty3494', expires='2010-11-01T03:32:15-05:00', @@ -79,32 +83,32 @@ class CompatTestCase(test.TestCase): #catalog = json.load(open( # os.path.join(os.path.dirname(__file__), # 'keystone_compat_diablo_sample_catalog.json'))) - #self.catalog_backend.create_catalog(self.user_123['id'], + #self.catalog_api.create_catalog(self.user_123['id'], # self.tenant_345['id'], # catalog) # tenants_for_token call - self.user_foo = self.identity_backend.create_user( + self.user_foo = self.identity_api.create_user( 'foo', models.User(id='foo', name='FOO', tenants=['1234', '3456'])) - self.tenant_1234 = self.identity_backend.create_tenant( + self.tenant_1234 = self.identity_api.create_tenant( '1234', models.Tenant(id='1234', name='ACME Corp', description='A description ...', enabled=True)) - self.tenant_3456 = self.identity_backend.create_tenant( + self.tenant_3456 = self.identity_api.create_tenant( '3456', models.Tenant(id='3456', name='Iron Works', description='A description ...', enabled=True)) - self.token_foo_unscoped = self.token_backend.create_token( + self.token_foo_unscoped = self.token_api.create_token( 'foo_unscoped', models.Token(id='foo_unscoped', user=self.user_foo)) - self.token_foo_scoped = self.token_backend.create_token( + self.token_foo_scoped = self.token_api.create_token( 'foo_scoped', models.Token(id='foo_scoped', user=self.user_foo, @@ -113,18 +117,13 @@ class CompatTestCase(test.TestCase): class DiabloCompatTestCase(CompatTestCase): def setUp(self): + CONF(config_files=['keystone_compat_diablo.conf']) + revdir = test.checkout_vendor(KEYSTONE_REPO, 'stable/diablo') self.sampledir = os.path.join(revdir, KEYSTONE_SAMPLE_DIR) self.app = self.loadapp('keystone_compat_diablo') - self.options = self.appconfig('keystone_compat_diablo') - - self.identity_backend = utils.import_object( - self.options['identity_driver'], options=self.options) - self.token_backend = utils.import_object( - self.options['token_driver'], options=self.options) - self.catalog_backend = utils.import_object( - self.options['catalog_driver'], options=self.options) + self.load_backends() super(DiabloCompatTestCase, self).setUp() def test_authenticate_scoped(self): diff --git a/tests/test_novaclient_compat.py b/tests/test_novaclient_compat.py index 1a441a4c1d..1e097c5591 100644 --- a/tests/test_novaclient_compat.py +++ b/tests/test_novaclient_compat.py @@ -3,6 +3,7 @@ import json import os import sys +from keystonelight import config from keystonelight import logging from keystonelight import models from keystonelight import test @@ -11,6 +12,7 @@ from keystonelight import utils import default_fixtures +CONF = config.CONF NOVACLIENT_REPO = 'git://github.com/openstack/python-novaclient.git' @@ -30,8 +32,8 @@ class NovaClientCompatMasterTestCase(CompatTestCase): reload(ks_client) reload(base_client) + CONF(config_files=['keystoneclient_compat_master.conf']) self.app = self.loadapp('keystoneclient_compat_master') - self.options = self.appconfig('keystoneclient_compat_master') self.load_backends() self.load_fixtures(default_fixtures) self.server = self.serveapp('keystoneclient_compat_master') @@ -41,7 +43,7 @@ class NovaClientCompatMasterTestCase(CompatTestCase): from novaclient import client as base_client port = self.server.socket_info['socket'][1] - self.options['public_port'] = port + CONF.public_port = port # NOTE(termie): novaclient wants a "/" TypeErrorat the end, keystoneclient does not # NOTE(termie): projectid is apparently sent as tenantName, so... that's