From 6817d66bd298b129bd84d1552e5ed02fa85c1fe2 Mon Sep 17 00:00:00 2001 From: Brant Knudson Date: Sat, 21 Mar 2015 13:33:34 -0500 Subject: [PATCH] Use stevedore for backend drivers The Stevedore library is used for loading backend drivers rather than using importutils. This provides a level of indirection for deployers/packagers. The importutils method of loading drivers is still supported, but it's deprecated. bp stevedore Change-Id: Id77ebf7056987ff1d3b9f62fab411845e63c86c3 --- keystone/assignment/core.py | 5 ++ keystone/catalog/core.py | 3 ++ keystone/common/manager.py | 29 ++++++++-- keystone/contrib/endpoint_filter/core.py | 2 + keystone/contrib/endpoint_policy/core.py | 2 + keystone/contrib/example/core.py | 2 + keystone/contrib/federation/core.py | 3 ++ keystone/contrib/oauth1/core.py | 3 ++ keystone/contrib/revoke/core.py | 2 + keystone/credential/core.py | 2 + keystone/identity/core.py | 8 ++- keystone/identity/generator.py | 2 + keystone/policy/core.py | 3 ++ keystone/resource/core.py | 5 ++ keystone/token/persistence/core.py | 2 + keystone/token/provider.py | 2 + keystone/trust/core.py | 3 ++ requirements.txt | 1 + setup.cfg | 69 ++++++++++++++++++++++++ 19 files changed, 144 insertions(+), 4 deletions(-) diff --git a/keystone/assignment/core.py b/keystone/assignment/core.py index 6845082221..4202254616 100644 --- a/keystone/assignment/core.py +++ b/keystone/assignment/core.py @@ -80,6 +80,9 @@ class Manager(manager.Manager): dynamically calls the backend. """ + + driver_namespace = 'keystone.assignment' + _PROJECT = 'project' _ROLE_REMOVED_FROM_USER = 'role_removed_from_user' _INVALIDATION_USER_PROJECT_TOKENS = 'invalidate_user_project_tokens' @@ -930,6 +933,8 @@ class Driver(object): class RoleManager(manager.Manager): """Default pivot point for the Role backend.""" + driver_namespace = 'keystone.role' + _ROLE = 'role' def __init__(self): diff --git a/keystone/catalog/core.py b/keystone/catalog/core.py index d31e924fef..e3cc51b6db 100644 --- a/keystone/catalog/core.py +++ b/keystone/catalog/core.py @@ -93,6 +93,9 @@ class Manager(manager.Manager): dynamically calls the backend. """ + + driver_namespace = 'keystone.catalog' + _ENDPOINT = 'endpoint' _SERVICE = 'service' _REGION = 'region' diff --git a/keystone/common/manager.py b/keystone/common/manager.py index 324183e8c3..15b460ec64 100644 --- a/keystone/common/manager.py +++ b/keystone/common/manager.py @@ -15,6 +15,9 @@ import functools from oslo_utils import importutils +import stevedore + +from keystone.openstack.common import versionutils def response_truncated(f): @@ -53,8 +56,26 @@ def response_truncated(f): return wrapper -def load_driver(driver_name, *args): - return importutils.import_object(driver_name, *args) +def load_driver(namespace, driver_name, *args): + try: + driver_manager = stevedore.DriverManager(namespace, + driver_name, + invoke_on_load=True, + invoke_args=args) + return driver_manager.driver + except RuntimeError: + # Ignore failure to load driver using stevedore and continue on. + pass + + @versionutils.deprecated(as_of=versionutils.deprecated.LIBERTY, + in_favor_of='entrypoints', + what='direct import of driver') + def _load_using_import(driver_name, *args): + return importutils.import_object(driver_name, *args) + + # For backwards-compatibility, an unregistered class reference can + # still be used. + return _load_using_import(driver_name, *args) class Manager(object): @@ -70,8 +91,10 @@ class Manager(object): """ + driver_namespace = None + def __init__(self, driver_name): - self.driver = load_driver(driver_name) + self.driver = load_driver(self.driver_namespace, driver_name) def __getattr__(self, name): """Forward calls to the underlying driver.""" diff --git a/keystone/contrib/endpoint_filter/core.py b/keystone/contrib/endpoint_filter/core.py index 972b65dd36..ffcc597402 100644 --- a/keystone/contrib/endpoint_filter/core.py +++ b/keystone/contrib/endpoint_filter/core.py @@ -56,6 +56,8 @@ class Manager(manager.Manager): """ + driver_namespace = 'keystone.endpoint_filter' + def __init__(self): super(Manager, self).__init__(CONF.endpoint_filter.driver) diff --git a/keystone/contrib/endpoint_policy/core.py b/keystone/contrib/endpoint_policy/core.py index 80c1056316..3e8026e613 100644 --- a/keystone/contrib/endpoint_policy/core.py +++ b/keystone/contrib/endpoint_policy/core.py @@ -38,6 +38,8 @@ class Manager(manager.Manager): """ + driver_namespace = 'keystone.endpoint_policy' + def __init__(self): super(Manager, self).__init__(CONF.endpoint_policy.driver) diff --git a/keystone/contrib/example/core.py b/keystone/contrib/example/core.py index 6e85c7f7e2..fc3c9fab1e 100644 --- a/keystone/contrib/example/core.py +++ b/keystone/contrib/example/core.py @@ -33,6 +33,8 @@ class ExampleManager(manager.Manager): """ + driver_namespace = 'keystone.example' + def __init__(self): # The following is an example of event callbacks. In this setup, # ExampleManager's data model is depended on project's data model. diff --git a/keystone/contrib/federation/core.py b/keystone/contrib/federation/core.py index b596cff7bf..68ed8c2bc8 100644 --- a/keystone/contrib/federation/core.py +++ b/keystone/contrib/federation/core.py @@ -55,6 +55,9 @@ class Manager(manager.Manager): dynamically calls the backend. """ + + driver_namespace = 'keystone.federation' + def __init__(self): super(Manager, self).__init__(CONF.federation.driver) diff --git a/keystone/contrib/oauth1/core.py b/keystone/contrib/oauth1/core.py index eeb3e114e2..2e333cd9f8 100644 --- a/keystone/contrib/oauth1/core.py +++ b/keystone/contrib/oauth1/core.py @@ -151,6 +151,9 @@ class Manager(manager.Manager): dynamically calls the backend. """ + + driver_namespace = 'keystone.oauth1' + _ACCESS_TOKEN = "OS-OAUTH1:access_token" _REQUEST_TOKEN = "OS-OAUTH1:request_token" _CONSUMER = "OS-OAUTH1:consumer" diff --git a/keystone/contrib/revoke/core.py b/keystone/contrib/revoke/core.py index c7335690b7..790dfb48d4 100644 --- a/keystone/contrib/revoke/core.py +++ b/keystone/contrib/revoke/core.py @@ -70,6 +70,8 @@ class Manager(manager.Manager): """ + driver_namespace = 'keystone.revoke' + def __init__(self): super(Manager, self).__init__(CONF.revoke.driver) self._register_listeners() diff --git a/keystone/credential/core.py b/keystone/credential/core.py index d3354ea3ef..6ad3a9a61e 100644 --- a/keystone/credential/core.py +++ b/keystone/credential/core.py @@ -40,6 +40,8 @@ class Manager(manager.Manager): """ + driver_namespace = 'keystone.credential' + def __init__(self): super(Manager, self).__init__(CONF.credential.driver) diff --git a/keystone/identity/core.py b/keystone/identity/core.py index 8c281439cc..afc8e99168 100644 --- a/keystone/identity/core.py +++ b/keystone/identity/core.py @@ -89,7 +89,8 @@ class DomainConfigs(dict): _any_sql = False def _load_driver(self, domain_config): - return manager.load_driver(domain_config['cfg'].identity.driver, + return manager.load_driver(Manager.driver_namespace, + domain_config['cfg'].identity.driver, domain_config['cfg']) def _assert_no_more_than_one_sql_driver(self, domain_id, new_config, @@ -404,6 +405,9 @@ class Manager(manager.Manager): mapping by default is a more prudent way to introduce this functionality. """ + + driver_namespace = 'keystone.identity' + _USER = 'user' _GROUP = 'group' @@ -1265,6 +1269,8 @@ class Driver(object): class MappingManager(manager.Manager): """Default pivot point for the ID Mapping backend.""" + driver_namespace = 'keystone.identity.id_mapping' + def __init__(self): super(MappingManager, self).__init__(CONF.identity_mapping.driver) diff --git a/keystone/identity/generator.py b/keystone/identity/generator.py index 0861bca09d..05ad2df5c7 100644 --- a/keystone/identity/generator.py +++ b/keystone/identity/generator.py @@ -31,6 +31,8 @@ CONF = cfg.CONF class Manager(manager.Manager): """Default pivot point for the identifier generator backend.""" + driver_namespace = 'keystone.identity.id_generator' + def __init__(self): super(Manager, self).__init__(CONF.identity_mapping.generator) diff --git a/keystone/policy/core.py b/keystone/policy/core.py index 1f02803fdc..7943b59eb1 100644 --- a/keystone/policy/core.py +++ b/keystone/policy/core.py @@ -36,6 +36,9 @@ class Manager(manager.Manager): dynamically calls the backend. """ + + driver_namespace = 'keystone.policy' + _POLICY = 'policy' def __init__(self): diff --git a/keystone/resource/core.py b/keystone/resource/core.py index 08e16c28b6..582b7ec2b0 100644 --- a/keystone/resource/core.py +++ b/keystone/resource/core.py @@ -53,6 +53,9 @@ class Manager(manager.Manager): dynamically calls the backend. """ + + driver_namespace = 'keystone.resource' + _DOMAIN = 'domain' _PROJECT = 'project' @@ -796,6 +799,8 @@ class DomainConfigManager(manager.Manager): # Only those options that affect the domain-specific driver support in # the identity manager are supported. + driver_namespace = 'keystone.resource.domain_config' + whitelisted_options = { 'identity': ['driver'], 'ldap': [ diff --git a/keystone/token/persistence/core.py b/keystone/token/persistence/core.py index 68a05440d9..44cd55faa5 100644 --- a/keystone/token/persistence/core.py +++ b/keystone/token/persistence/core.py @@ -47,6 +47,8 @@ class PersistenceManager(manager.Manager): """ + driver_namespace = 'keystone.token.persistence' + def __init__(self): super(PersistenceManager, self).__init__(CONF.token.driver) diff --git a/keystone/token/provider.py b/keystone/token/provider.py index 9225e655a3..f7bd7cfd11 100644 --- a/keystone/token/provider.py +++ b/keystone/token/provider.py @@ -110,6 +110,8 @@ class Manager(manager.Manager): """ + driver_namespace = 'keystone.token.provider' + V2 = V2 V3 = V3 VERSIONS = VERSIONS diff --git a/keystone/trust/core.py b/keystone/trust/core.py index 80e7fb36be..c50ac7a4db 100644 --- a/keystone/trust/core.py +++ b/keystone/trust/core.py @@ -41,6 +41,9 @@ class Manager(manager.Manager): dynamically calls the backend. """ + + driver_namespace = 'keystone.trust' + _TRUST = "OS-TRUST:trust" def __init__(self): diff --git a/requirements.txt b/requirements.txt index bdc4cd4cb6..01bb460898 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,6 +14,7 @@ cryptography>=0.8 # Apache-2.0 six>=1.9.0 SQLAlchemy>=0.9.7,<=0.9.99 sqlalchemy-migrate>=0.9.5 +stevedore>=1.3.0 # Apache-2.0 passlib iso8601>=0.1.9 python-keystoneclient>=1.1.0 diff --git a/setup.cfg b/setup.cfg index a8db4246ad..d5c26d7366 100644 --- a/setup.cfg +++ b/setup.cfg @@ -64,6 +64,75 @@ console_scripts = keystone-all = keystone.cmd.all:main keystone-manage = keystone.cmd.manage:main +keystone.assignment = + keystone.assignment.backends.ldap.Assignment = keystone.assignment.backends.ldap:Assignment + keystone.assignment.backends.sql.Assignment = keystone.assignment.backends.sql:Assignment + +keystone.catalog = + keystone.catalog.backends.kvs.Catalog = keystone.catalog.backends.kvs:Catalog + keystone.catalog.backends.sql.Catalog = keystone.catalog.backends.sql:Catalog + keystone.catalog.backends.templated.Catalog = keystone.catalog.backends.templated:Catalog + keystone.contrib.endpoint_filter.backends.catalog_sql.EndpointFilterCatalog = keystone.contrib.endpoint_filter.backends.catalog_sql:EndpointFilterCatalog + +keystone.credential = + keystone.credential.backends.sql.Credential = keystone.credential.backends.sql:Credential + +keystone.identity = + keystone.identity.backends.ldap.Identity = keystone.identity.backends.ldap:Identity + keystone.identity.backends.sql.Identity = keystone.identity.backends.sql:Identity + +keystone.identity.id_generator = + keystone.identity.id_generators.sha256.Generator = keystone.identity.id_generators.sha256:Generator + +keystone.identity.id_mapping = + keystone.identity.mapping_backends.sql.Mapping = keystone.identity.mapping_backends.sql:Mapping + +keystone.policy = + keystone.policy.backends.rules.Policy = keystone.policy.backends.rules:Policy + keystone.policy.backends.sql.Policy = keystone.policy.backends.sql:Policy + +keystone.resource = + keystone.resource.backends.ldap.Resource = keystone.resource.backends.ldap:Resource + keystone.resource.backends.sql.Resource = keystone.resource.backends.sql:Resource + +keystone.resource.domain_config = + keystone.resource.config_backends.sql.DomainConfig = keystone.resource.config_backends.sql:DomainConfig + +keystone.role = + keystone.assignment.role_backends.ldap.Role = keystone.assignment.role_backends.ldap:Role + keystone.assignment.role_backends.sql.Role = keystone.assignment.role_backends.sql:Role + +keystone.token.persistence = + keystone.token.persistence.backends.kvs.Token = keystone.token.persistence.backends.kvs:Token + keystone.token.persistence.backends.memcache.Token = keystone.token.persistence.backends.memcache:Token + keystone.token.persistence.backends.memcache_pool.Token = keystone.token.persistence.backends.memcache_pool:Token + keystone.token.persistence.backends.sql.Token = keystone.token.persistence.backends.sql:Token + +keystone.token.provider = + keystone.token.providers.fernet.Provider = keystone.token.providers.fernet:Provider + keystone.token.providers.uuid.Provider = keystone.token.providers.uuid:Provider + keystone.token.providers.pki.Provider = keystone.token.providers.pki:Provider + keystone.token.providers.pkiz.Provider = keystone.token.providers.pkiz:Provider + +keystone.trust = + keystone.trust.backends.sql.Trust = keystone.trust.backends.sql:Trust + +keystone.endpoint_filter = + keystone.contrib.endpoint_filter.backends.sql.EndpointFilter = keystone.contrib.endpoint_filter.backends.sql:EndpointFilter + +keystone.endpoint_policy = + keystone.contrib.endpoint_policy.backends.sql.EndpointPolicy = keystone.contrib.endpoint_policy.backends.sql:EndpointPolicy + +keystone.federation = + keystone.contrib.federation.backends.sql.Federation = keystone.contrib.federation.backends.sql:Federation + +keystone.oauth1 = + keystone.contrib.oauth1.backends.sql.OAuth1 = keystone.contrib.oauth1.backends.sql:OAuth1 + +keystone.revoke = + keystone.contrib.revoke.backends.kvs.Revoke = keystone.contrib.revoke.backends.kvs:Revoke + keystone.contrib.revoke.backends.sql.Revoke = keystone.contrib.revoke.backends.sql:Revoke + oslo.config.opts = keystone = keystone.common.config:list_opts keystone.notifications = keystone.notifications:list_opts