Driver registry
Uses automatic dependency injection to provide controllers with driver interfaces (identity_api, token_api, etc). See tests/test_injection.py for a self-contained example. Change-Id: I255087de534292fbf57a45b19f97488f831f607c
This commit is contained in:
parent
ac2d92ca2e
commit
03eb2801a3
@ -17,20 +17,16 @@
|
||||
|
||||
import uuid
|
||||
|
||||
from keystone.catalog import core
|
||||
from keystone.common import controller
|
||||
from keystone.common import wsgi
|
||||
from keystone.common import dependency
|
||||
from keystone import exception
|
||||
from keystone import identity
|
||||
from keystone import policy
|
||||
from keystone import token
|
||||
|
||||
|
||||
INTERFACES = ['public', 'internal', 'admin']
|
||||
|
||||
|
||||
@dependency.requires('catalog_api')
|
||||
class Service(controller.V2Controller):
|
||||
|
||||
def get_services(self, context):
|
||||
self.assert_admin(context)
|
||||
service_list = self.catalog_api.list_services(context)
|
||||
@ -55,6 +51,7 @@ class Service(controller.V2Controller):
|
||||
return {'OS-KSADM:service': new_service_ref}
|
||||
|
||||
|
||||
@dependency.requires('catalog_api')
|
||||
class Endpoint(controller.V2Controller):
|
||||
def get_endpoints(self, context):
|
||||
"""Merge matching v3 endpoint refs into legacy refs."""
|
||||
@ -115,6 +112,7 @@ class Endpoint(controller.V2Controller):
|
||||
raise exception.EndpointNotFound(endpoint_id=endpoint_id)
|
||||
|
||||
|
||||
@dependency.requires('catalog_api')
|
||||
class ServiceV3(controller.V3Controller):
|
||||
@controller.protected
|
||||
def create_service(self, context, service):
|
||||
@ -147,6 +145,7 @@ class ServiceV3(controller.V3Controller):
|
||||
return self.catalog_api.delete_service(context, service_id)
|
||||
|
||||
|
||||
@dependency.requires('catalog_api')
|
||||
class EndpointV3(controller.V3Controller):
|
||||
@controller.protected
|
||||
def create_endpoint(self, context, endpoint):
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
"""Main entry point into the Catalog service."""
|
||||
|
||||
from keystone.common import dependency
|
||||
from keystone.common import logging
|
||||
from keystone.common import manager
|
||||
from keystone import config
|
||||
@ -51,6 +52,7 @@ def format_url(url, data):
|
||||
return result
|
||||
|
||||
|
||||
@dependency.provider('catalog_api')
|
||||
class Manager(manager.Manager):
|
||||
"""Default pivot point for the Catalog backend.
|
||||
|
||||
|
@ -13,13 +13,13 @@
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from keystone.catalog import controllers
|
||||
from keystone.common import router
|
||||
from keystone.common import wsgi
|
||||
|
||||
|
||||
def append_v3_routers(mapper, routers, apis):
|
||||
routers.append(router.Router(controllers.ServiceV3(**apis),
|
||||
def append_v3_routers(mapper, routers):
|
||||
routers.append(router.Router(controllers.ServiceV3(),
|
||||
'services', 'service'))
|
||||
routers.append(router.Router(controllers.EndpointV3(**apis),
|
||||
routers.append(router.Router(controllers.EndpointV3(),
|
||||
'endpoints', 'endpoint'))
|
||||
|
@ -1,6 +1,7 @@
|
||||
import uuid
|
||||
import functools
|
||||
|
||||
from keystone.common import dependency
|
||||
from keystone.common import logging
|
||||
from keystone.common import wsgi
|
||||
from keystone import exception
|
||||
@ -55,15 +56,10 @@ def protected(f):
|
||||
return wrapper
|
||||
|
||||
|
||||
@dependency.requires('identity_api', 'policy_api', 'token_api')
|
||||
class V2Controller(wsgi.Application):
|
||||
"""Base controller class for Identity API v2."""
|
||||
|
||||
def __init__(self, catalog_api, identity_api, policy_api, token_api):
|
||||
self.catalog_api = catalog_api
|
||||
self.identity_api = identity_api
|
||||
self.policy_api = policy_api
|
||||
self.token_api = token_api
|
||||
super(V2Controller, self).__init__()
|
||||
pass
|
||||
|
||||
|
||||
class V3Controller(V2Controller):
|
||||
|
67
keystone/common/dependency.py
Normal file
67
keystone/common/dependency.py
Normal file
@ -0,0 +1,67 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2012 OpenStack LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
REGISTRY = {}
|
||||
|
||||
|
||||
class UnresolvableDependencyException(Exception):
|
||||
def __init__(self, name):
|
||||
msg = 'Unregistered dependency: %s' % name
|
||||
super(UnresolvableDependencyException, self).__init__(msg)
|
||||
|
||||
|
||||
def provider(name):
|
||||
"""Register the wrapped dependency provider under the specified name."""
|
||||
def wrapper(cls):
|
||||
def wrapped(init):
|
||||
def __wrapped_init__(self, *args, **kwargs):
|
||||
"""Initialize the wrapped object and add it to the registry."""
|
||||
init(self, *args, **kwargs)
|
||||
REGISTRY[name] = self
|
||||
|
||||
return __wrapped_init__
|
||||
|
||||
cls.__init__ = wrapped(cls.__init__)
|
||||
return cls
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def requires(*dependencies):
|
||||
"""Inject specified dependencies from the registry into the instance."""
|
||||
def wrapper(self, *args, **kwargs):
|
||||
"""Inject each dependency from the registry."""
|
||||
self.__wrapped_init__(*args, **kwargs)
|
||||
|
||||
for dependency in self._dependencies:
|
||||
if dependency not in REGISTRY:
|
||||
raise UnresolvableDependencyException(dependency)
|
||||
setattr(self, dependency, REGISTRY[dependency])
|
||||
|
||||
def wrapped(cls):
|
||||
"""Note the required dependencies on the object for later injection.
|
||||
|
||||
The dependencies of the parent class are combined with that of the
|
||||
child class to create a new set of dependencies.
|
||||
"""
|
||||
existing_dependencies = getattr(cls, '_dependencies', set())
|
||||
cls._dependencies = existing_dependencies.union(dependencies)
|
||||
if not hasattr(cls, '__wrapped_init__'):
|
||||
cls.__wrapped_init__ = cls.__init__
|
||||
cls.__init__ = wrapper
|
||||
return cls
|
||||
|
||||
return wrapped
|
@ -16,8 +16,6 @@
|
||||
from keystone import catalog
|
||||
from keystone.common import wsgi
|
||||
from keystone import identity
|
||||
from keystone import policy
|
||||
from keystone import token
|
||||
|
||||
|
||||
class CrudExtension(wsgi.ExtensionRouter):
|
||||
@ -28,16 +26,11 @@ class CrudExtension(wsgi.ExtensionRouter):
|
||||
"""
|
||||
|
||||
def add_routes(self, mapper):
|
||||
apis = dict(catalog_api=catalog.Manager(),
|
||||
identity_api=identity.Manager(),
|
||||
policy_api=policy.Manager(),
|
||||
token_api=token.Manager())
|
||||
|
||||
tenant_controller = identity.controllers.Tenant(**apis)
|
||||
user_controller = identity.controllers.User(**apis)
|
||||
role_controller = identity.controllers.Role(**apis)
|
||||
service_controller = catalog.controllers.Service(**apis)
|
||||
endpoint_controller = catalog.controllers.Endpoint(**apis)
|
||||
tenant_controller = identity.controllers.Tenant()
|
||||
user_controller = identity.controllers.User()
|
||||
role_controller = identity.controllers.Role()
|
||||
service_controller = catalog.controllers.Service()
|
||||
endpoint_controller = catalog.controllers.Endpoint()
|
||||
|
||||
# Tenant Operations
|
||||
mapper.connect(
|
||||
|
@ -36,20 +36,20 @@ glance to list images needed to perform the requested task.
|
||||
|
||||
import uuid
|
||||
|
||||
from keystone import catalog
|
||||
from keystone.common import controller
|
||||
from keystone.common import dependency
|
||||
from keystone.common import manager
|
||||
from keystone.common import utils
|
||||
from keystone.common import wsgi
|
||||
from keystone import config
|
||||
from keystone import exception
|
||||
from keystone import identity
|
||||
from keystone import policy
|
||||
from keystone import token
|
||||
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@dependency.provider('ec2_api')
|
||||
class Manager(manager.Manager):
|
||||
"""Default pivot point for the EC2 Credentials backend.
|
||||
|
||||
@ -95,15 +95,8 @@ class Ec2Extension(wsgi.ExtensionRouter):
|
||||
conditions=dict(method=['DELETE']))
|
||||
|
||||
|
||||
class Ec2Controller(wsgi.Application):
|
||||
def __init__(self):
|
||||
self.catalog_api = catalog.Manager()
|
||||
self.identity_api = identity.Manager()
|
||||
self.token_api = token.Manager()
|
||||
self.policy_api = policy.Manager()
|
||||
self.ec2_api = Manager()
|
||||
super(Ec2Controller, self).__init__()
|
||||
|
||||
@dependency.requires('catalog_api', 'ec2_api')
|
||||
class Ec2Controller(controller.V2Controller):
|
||||
def check_signature(self, creds_ref, credentials):
|
||||
signer = utils.Ec2Signer(creds_ref['secret'])
|
||||
signature = signer.generate(credentials)
|
||||
|
@ -18,13 +18,9 @@ import copy
|
||||
import uuid
|
||||
|
||||
from keystone import exception
|
||||
from keystone.common import controller
|
||||
from keystone.common import logging
|
||||
from keystone.common import wsgi
|
||||
from keystone import catalog
|
||||
from keystone import identity
|
||||
from keystone import policy
|
||||
from keystone import token
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -81,12 +77,7 @@ class CrudExtension(wsgi.ExtensionRouter):
|
||||
"""
|
||||
|
||||
def add_routes(self, mapper):
|
||||
apis = dict(catalog_api=catalog.Manager(),
|
||||
identity_api=identity.Manager(),
|
||||
policy_api=policy.Manager(),
|
||||
token_api=token.Manager())
|
||||
|
||||
user_controller = UserController(**apis)
|
||||
user_controller = UserController()
|
||||
|
||||
mapper.connect('/OS-KSCRUD/users/{user_id}',
|
||||
controller=user_controller,
|
||||
|
@ -22,11 +22,7 @@ import uuid
|
||||
|
||||
from keystone.common import controller
|
||||
from keystone.common import logging
|
||||
from keystone.common import wsgi
|
||||
from keystone import exception
|
||||
from keystone.identity import core
|
||||
from keystone import policy
|
||||
from keystone import token
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -16,14 +16,9 @@
|
||||
|
||||
"""Main entry point into the Identity service."""
|
||||
|
||||
import urllib
|
||||
import urlparse
|
||||
import uuid
|
||||
|
||||
from keystone.common import controller
|
||||
from keystone.common import dependency
|
||||
from keystone.common import logging
|
||||
from keystone.common import manager
|
||||
from keystone.common import wsgi
|
||||
from keystone import config
|
||||
from keystone import exception
|
||||
|
||||
@ -51,6 +46,7 @@ def filter_user(user_ref):
|
||||
return user_ref
|
||||
|
||||
|
||||
@dependency.provider('identity_api')
|
||||
class Manager(manager.Manager):
|
||||
"""Default pivot point for the Identity backend.
|
||||
|
||||
|
@ -20,12 +20,8 @@ from keystone.common import router
|
||||
|
||||
|
||||
class Public(wsgi.ComposableRouter):
|
||||
def __init__(self, apis):
|
||||
self.apis = apis
|
||||
super(Public, self).__init__()
|
||||
|
||||
def add_routes(self, mapper):
|
||||
tenant_controller = controllers.Tenant(**self.apis)
|
||||
tenant_controller = controllers.Tenant()
|
||||
mapper.connect('/tenants',
|
||||
controller=tenant_controller,
|
||||
action='get_tenants_for_token',
|
||||
@ -33,13 +29,9 @@ class Public(wsgi.ComposableRouter):
|
||||
|
||||
|
||||
class Admin(wsgi.ComposableRouter):
|
||||
def __init__(self, apis):
|
||||
self.apis = apis
|
||||
super(Admin, self).__init__()
|
||||
|
||||
def add_routes(self, mapper):
|
||||
# Tenant Operations
|
||||
tenant_controller = controllers.Tenant(**self.apis)
|
||||
tenant_controller = controllers.Tenant()
|
||||
mapper.connect('/tenants',
|
||||
controller=tenant_controller,
|
||||
action='get_all_tenants',
|
||||
@ -50,14 +42,14 @@ class Admin(wsgi.ComposableRouter):
|
||||
conditions=dict(method=['GET']))
|
||||
|
||||
# User Operations
|
||||
user_controller = controllers.User(**self.apis)
|
||||
user_controller = controllers.User()
|
||||
mapper.connect('/users/{user_id}',
|
||||
controller=user_controller,
|
||||
action='get_user',
|
||||
conditions=dict(method=['GET']))
|
||||
|
||||
# Role Operations
|
||||
roles_controller = controllers.Role(**self.apis)
|
||||
roles_controller = controllers.Role()
|
||||
mapper.connect('/tenants/{tenant_id}/users/{user_id}/roles',
|
||||
controller=roles_controller,
|
||||
action='get_user_roles',
|
||||
@ -68,11 +60,11 @@ class Admin(wsgi.ComposableRouter):
|
||||
conditions=dict(method=['GET']))
|
||||
|
||||
|
||||
def append_v3_routers(mapper, routers, apis):
|
||||
def append_v3_routers(mapper, routers):
|
||||
routers.append(
|
||||
router.Router(controllers.DomainV3(**apis),
|
||||
router.Router(controllers.DomainV3(),
|
||||
'domains', 'domain'))
|
||||
project_controller = controllers.ProjectV3(**apis)
|
||||
project_controller = controllers.ProjectV3()
|
||||
routers.append(
|
||||
router.Router(project_controller,
|
||||
'projects', 'project'))
|
||||
@ -81,12 +73,12 @@ def append_v3_routers(mapper, routers, apis):
|
||||
action='list_user_projects',
|
||||
conditions=dict(method=['GET']))
|
||||
routers.append(
|
||||
router.Router(controllers.UserV3(**apis),
|
||||
router.Router(controllers.UserV3(),
|
||||
'users', 'user'))
|
||||
routers.append(
|
||||
router.Router(controllers.CredentialV3(**apis),
|
||||
router.Router(controllers.CredentialV3(),
|
||||
'credentials', 'credential'))
|
||||
role_controller = controllers.RoleV3(**apis)
|
||||
role_controller = controllers.RoleV3()
|
||||
routers.append(router.Router(role_controller, 'roles', 'role'))
|
||||
mapper.connect('/projects/{project_id}/users/{user_id}/roles/{role_id}',
|
||||
controller=role_controller,
|
||||
|
@ -17,6 +17,7 @@
|
||||
"""Main entry point into the Policy service."""
|
||||
|
||||
|
||||
from keystone.common import dependency
|
||||
from keystone.common import manager
|
||||
from keystone import config
|
||||
from keystone import exception
|
||||
@ -25,6 +26,7 @@ from keystone import exception
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@dependency.provider('policy_api')
|
||||
class Manager(manager.Manager):
|
||||
"""Default pivot point for the Policy backend.
|
||||
|
||||
|
@ -17,6 +17,6 @@ from keystone.policy import controllers
|
||||
from keystone.common import router
|
||||
|
||||
|
||||
def append_v3_routers(mapper, routers, apis):
|
||||
policy_controller = controllers.PolicyV3(**apis)
|
||||
def append_v3_routers(mapper, routers):
|
||||
policy_controller = controllers.PolicyV3()
|
||||
routers.append(router.Router(policy_controller, 'policies', 'policy'))
|
||||
|
@ -14,17 +14,18 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
"""
|
||||
The only types of routers in this file should be ComposingRouters.
|
||||
The routers for the submodules should be in the module specific router files
|
||||
for example, the Composable Router for identity belongs in
|
||||
keystone/identity/routers.py
|
||||
The only types of routers in this file should be ``ComposingRouters``.
|
||||
|
||||
The routers for the backends should be in the backend-specific router modules.
|
||||
For example, the ``ComposableRouter`` for ``identity`` belongs in::
|
||||
|
||||
keystone.identity.routers
|
||||
|
||||
"""
|
||||
|
||||
|
||||
from keystone.common import wsgi
|
||||
from keystone import catalog
|
||||
from keystone import controllers
|
||||
from keystone import exception
|
||||
|
||||
|
||||
class Extension(wsgi.ComposableRouter):
|
||||
|
@ -17,22 +17,22 @@
|
||||
import routes
|
||||
|
||||
from keystone import catalog
|
||||
from keystone.contrib import ec2
|
||||
from keystone.common import logging
|
||||
from keystone.common import wsgi
|
||||
from keystone import exception
|
||||
from keystone import identity
|
||||
from keystone import policy
|
||||
from keystone import routers
|
||||
from keystone import token
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _apis():
|
||||
return dict(catalog_api=catalog.Manager(),
|
||||
identity_api=identity.Manager(),
|
||||
policy_api=policy.Manager(),
|
||||
token_api=token.Manager())
|
||||
DRIVERS = dict(
|
||||
catalog_api=catalog.Manager(),
|
||||
ec2_api=ec2.Manager(),
|
||||
identity_api=identity.Manager(),
|
||||
policy_api=policy.Manager(),
|
||||
token_api=token.Manager())
|
||||
|
||||
|
||||
@logging.fail_gracefully
|
||||
@ -40,10 +40,10 @@ def public_app_factory(global_conf, **local_conf):
|
||||
conf = global_conf.copy()
|
||||
conf.update(local_conf)
|
||||
return wsgi.ComposingRouter(routes.Mapper(),
|
||||
[identity.routers.Public(_apis()),
|
||||
token.routers.Router(_apis()),
|
||||
routers.Version('public'),
|
||||
routers.Extension(False)])
|
||||
[identity.routers.Public(),
|
||||
token.routers.Router(),
|
||||
routers.Version('public'),
|
||||
routers.Extension(False)])
|
||||
|
||||
|
||||
@logging.fail_gracefully
|
||||
@ -51,8 +51,8 @@ def admin_app_factory(global_conf, **local_conf):
|
||||
conf = global_conf.copy()
|
||||
conf.update(local_conf)
|
||||
return wsgi.ComposingRouter(routes.Mapper(),
|
||||
[identity.routers.Admin(_apis()),
|
||||
token.routers.Router(_apis()),
|
||||
[identity.routers.Admin(),
|
||||
token.routers.Router(),
|
||||
routers.Version('admin'),
|
||||
routers.Extension()])
|
||||
|
||||
@ -80,6 +80,6 @@ def v3_app_factory(global_conf, **local_conf):
|
||||
mapper = routes.Mapper()
|
||||
v3routers = []
|
||||
for module in [catalog, identity, policy]:
|
||||
module.routers.append_v3_routers(mapper, v3routers, _apis())
|
||||
#TODO put token routes here
|
||||
module.routers.append_v3_routers(mapper, v3routers)
|
||||
# TODO(ayoung): put token routes here
|
||||
return wsgi.ComposingRouter(mapper, v3routers)
|
||||
|
@ -31,7 +31,10 @@ from keystone.common import logging
|
||||
from keystone.common import utils
|
||||
from keystone.common import wsgi
|
||||
from keystone import config
|
||||
from keystone.openstack.common import importutils
|
||||
from keystone import catalog
|
||||
from keystone import identity
|
||||
from keystone import policy
|
||||
from keystone import token
|
||||
|
||||
|
||||
do_monkeypatch = not os.getenv('STANDARD_THREADS')
|
||||
@ -44,6 +47,7 @@ VENDOR = os.path.join(ROOTDIR, 'vendor')
|
||||
TESTSDIR = os.path.join(ROOTDIR, 'tests')
|
||||
ETCDIR = os.path.join(ROOTDIR, 'etc')
|
||||
CONF = config.CONF
|
||||
DRIVERS = {}
|
||||
|
||||
|
||||
cd = os.chdir
|
||||
@ -61,6 +65,14 @@ def testsdir(*p):
|
||||
return os.path.join(TESTSDIR, *p)
|
||||
|
||||
|
||||
def initialize_drivers():
|
||||
DRIVERS['catalog_api'] = catalog.Manager()
|
||||
DRIVERS['identity_api'] = identity.Manager()
|
||||
DRIVERS['policy_api'] = policy.Manager()
|
||||
DRIVERS['token_api'] = token.Manager()
|
||||
return DRIVERS
|
||||
|
||||
|
||||
def checkout_vendor(repo, rev):
|
||||
# TODO(termie): this function is a good target for some optimizations :PERF
|
||||
name = repo.split('/')[-1]
|
||||
@ -202,11 +214,9 @@ class TestCase(NoModule, unittest.TestCase):
|
||||
CONF.set_override(k, v)
|
||||
|
||||
def load_backends(self):
|
||||
"""Hacky shortcut to load the backends for data manipulation."""
|
||||
self.identity_api = importutils.import_object(CONF.identity.driver)
|
||||
self.token_api = importutils.import_object(CONF.token.driver)
|
||||
self.catalog_api = importutils.import_object(CONF.catalog.driver)
|
||||
self.policy_api = importutils.import_object(CONF.policy.driver)
|
||||
"""Create shortcut references to each driver for data manipulation."""
|
||||
for name, manager in initialize_drivers().iteritems():
|
||||
setattr(self, name, manager.driver)
|
||||
|
||||
def load_fixtures(self, fixtures):
|
||||
"""Hacky basic and naive fixture loading based on a python module.
|
||||
|
@ -4,6 +4,7 @@ import json
|
||||
from keystone import config
|
||||
from keystone.common import cms
|
||||
from keystone.common import controller
|
||||
from keystone.common import dependency
|
||||
from keystone.common import logging
|
||||
from keystone import exception
|
||||
from keystone.openstack.common import timeutils
|
||||
@ -18,6 +19,7 @@ class ExternalAuthNotApplicable(Exception):
|
||||
pass
|
||||
|
||||
|
||||
@dependency.requires('catalog_api')
|
||||
class Auth(controller.V2Controller):
|
||||
def ca_cert(self, context, auth=None):
|
||||
ca_file = open(config.CONF.signing.ca_certs, 'r')
|
||||
|
@ -18,8 +18,9 @@
|
||||
|
||||
import datetime
|
||||
|
||||
from keystone.common import manager
|
||||
from keystone.common import cms
|
||||
from keystone.common import dependency
|
||||
from keystone.common import manager
|
||||
from keystone import config
|
||||
from keystone import exception
|
||||
from keystone.openstack.common import timeutils
|
||||
@ -54,6 +55,7 @@ def default_expire_time():
|
||||
return timeutils.utcnow() + expire_delta
|
||||
|
||||
|
||||
@dependency.provider('token_api')
|
||||
class Manager(manager.Manager):
|
||||
"""Default pivot point for the Token backend.
|
||||
|
||||
|
@ -18,12 +18,8 @@ from keystone.token import controllers
|
||||
|
||||
|
||||
class Router(wsgi.ComposableRouter):
|
||||
def __init__(self, apis):
|
||||
self.apis = apis
|
||||
super(Router, self).__init__()
|
||||
|
||||
def add_routes(self, mapper):
|
||||
token_controller = controllers.Auth(**self.apis)
|
||||
token_controller = controllers.Auth()
|
||||
mapper.connect('/tokens',
|
||||
controller=token_controller,
|
||||
action='authenticate',
|
||||
|
@ -17,13 +17,9 @@ import uuid
|
||||
|
||||
import default_fixtures
|
||||
|
||||
from keystone import catalog
|
||||
from keystone import config
|
||||
from keystone import exception
|
||||
from keystone import identity
|
||||
from keystone.identity.backends import kvs as kvs_identity
|
||||
from keystone.openstack.common import timeutils
|
||||
from keystone import policy
|
||||
from keystone import test
|
||||
from keystone import token
|
||||
|
||||
@ -56,15 +52,11 @@ class AuthTest(test.TestCase):
|
||||
def setUp(self):
|
||||
super(AuthTest, self).setUp()
|
||||
|
||||
# load_fixtures checks for 'identity_api' to be defined
|
||||
self.identity_api = kvs_identity.Identity()
|
||||
CONF.identity.driver = 'keystone.identity.backends.kvs.Identity'
|
||||
self.load_backends()
|
||||
self.load_fixtures(default_fixtures)
|
||||
|
||||
self.api = token.controllers.Auth(
|
||||
catalog_api=catalog.Manager(),
|
||||
identity_api=identity.Manager(),
|
||||
policy_api=policy.Manager(),
|
||||
token_api=token.Manager())
|
||||
self.api = token.controllers.Auth()
|
||||
|
||||
def assertEqualTokens(self, a, b):
|
||||
"""Assert that two tokens are equal.
|
||||
|
141
tests/test_injection.py
Normal file
141
tests/test_injection.py
Normal file
@ -0,0 +1,141 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2012 OpenStack LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
import unittest2 as unittest
|
||||
import uuid
|
||||
|
||||
from keystone.common import dependency
|
||||
|
||||
|
||||
class TestDependencyInjection(unittest.TestCase):
|
||||
def test_dependency_injection(self):
|
||||
class Interface(object):
|
||||
def do_work(self):
|
||||
assert False
|
||||
|
||||
@dependency.provider('first_api')
|
||||
class FirstImplementation(Interface):
|
||||
def do_work(self):
|
||||
return True
|
||||
|
||||
@dependency.provider('second_api')
|
||||
class SecondImplementation(Interface):
|
||||
def do_work(self):
|
||||
return True
|
||||
|
||||
@dependency.requires('first_api', 'second_api')
|
||||
class Consumer(object):
|
||||
def do_work_with_dependencies(self):
|
||||
assert self.first_api.do_work()
|
||||
assert self.second_api.do_work()
|
||||
|
||||
# initialize dependency providers
|
||||
first_api = FirstImplementation()
|
||||
second_api = SecondImplementation()
|
||||
|
||||
# ... sometime later, initialize a dependency consumer
|
||||
consumer = Consumer()
|
||||
|
||||
# the expected dependencies should be available to the consumer
|
||||
self.assertIs(consumer.first_api, first_api)
|
||||
self.assertIs(consumer.second_api, second_api)
|
||||
self.assertIsInstance(consumer.first_api, Interface)
|
||||
self.assertIsInstance(consumer.second_api, Interface)
|
||||
consumer.do_work_with_dependencies()
|
||||
|
||||
def test_dependency_configuration(self):
|
||||
@dependency.provider('api')
|
||||
class Configurable(object):
|
||||
def __init__(self, value=None):
|
||||
self.value = value
|
||||
|
||||
def get_value(self):
|
||||
return self.value
|
||||
|
||||
@dependency.requires('api')
|
||||
class Consumer(object):
|
||||
def get_value(self):
|
||||
return self.api.get_value()
|
||||
|
||||
# initialize dependency providers
|
||||
api = Configurable(value=True)
|
||||
|
||||
# ... sometime later, initialize a dependency consumer
|
||||
consumer = Consumer()
|
||||
|
||||
# the expected dependencies should be available to the consumer
|
||||
self.assertIs(consumer.api, api)
|
||||
self.assertIsInstance(consumer.api, Configurable)
|
||||
self.assertTrue(consumer.get_value())
|
||||
|
||||
def test_inherited_dependency(self):
|
||||
class Interface(object):
|
||||
def do_work(self):
|
||||
assert False
|
||||
|
||||
@dependency.provider('first_api')
|
||||
class FirstImplementation(Interface):
|
||||
def do_work(self):
|
||||
return True
|
||||
|
||||
@dependency.provider('second_api')
|
||||
class SecondImplementation(Interface):
|
||||
def do_work(self):
|
||||
return True
|
||||
|
||||
@dependency.requires('first_api')
|
||||
class ParentConsumer(object):
|
||||
def do_work_with_dependencies(self):
|
||||
assert self.first_api.do_work()
|
||||
|
||||
@dependency.requires('second_api')
|
||||
class ChildConsumer(ParentConsumer):
|
||||
def do_work_with_dependencies(self):
|
||||
assert self.second_api.do_work()
|
||||
super(ChildConsumer, self).do_work_with_dependencies()
|
||||
|
||||
# initialize dependency providers
|
||||
first_api = FirstImplementation()
|
||||
second_api = SecondImplementation()
|
||||
|
||||
# ... sometime later, initialize a dependency consumer
|
||||
consumer = ChildConsumer()
|
||||
|
||||
# dependencies should be naturally inherited
|
||||
self.assertEqual(
|
||||
ParentConsumer._dependencies,
|
||||
set(['first_api']))
|
||||
self.assertEqual(
|
||||
ChildConsumer._dependencies,
|
||||
set(['first_api', 'second_api']))
|
||||
self.assertEqual(
|
||||
consumer._dependencies,
|
||||
set(['first_api', 'second_api']))
|
||||
|
||||
# the expected dependencies should be available to the consumer
|
||||
self.assertIs(consumer.first_api, first_api)
|
||||
self.assertIs(consumer.second_api, second_api)
|
||||
self.assertIsInstance(consumer.first_api, Interface)
|
||||
self.assertIsInstance(consumer.second_api, Interface)
|
||||
consumer.do_work_with_dependencies()
|
||||
|
||||
def test_unresolvable_dependency(self):
|
||||
@dependency.requires(uuid.uuid4().hex)
|
||||
class Consumer(object):
|
||||
pass
|
||||
|
||||
with self.assertRaises(dependency.UnresolvableDependencyException):
|
||||
Consumer()
|
Loading…
x
Reference in New Issue
Block a user