diff --git a/keystoneauth1/__init__.py b/keystoneauth1/__init__.py index cfa7169..e69de29 100644 --- a/keystoneauth1/__init__.py +++ b/keystoneauth1/__init__.py @@ -1,38 +0,0 @@ -# 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. - - -from keystoneauth1.base import * # noqa -from keystoneauth1.cli import * # noqa -from keystoneauth1.conf import * # noqa - - -__all__ = [ - # auth.base - 'AUTH_INTERFACE', - 'BaseAuthPlugin', - 'get_available_plugin_names', - 'get_available_plugin_classes', - 'get_plugin_class', - 'IDENTITY_AUTH_HEADER_NAME', - 'PLUGIN_NAMESPACE', - - # auth.cli - 'load_from_argparse_arguments', - 'register_argparse_arguments', - - # auth.conf - 'get_common_conf_options', - 'get_plugin_options', - 'load_from_conf_options', - 'register_conf_options', -] diff --git a/keystoneauth1/identity/base.py b/keystoneauth1/identity/base.py index 8fee3ec..a5bb167 100644 --- a/keystoneauth1/identity/base.py +++ b/keystoneauth1/identity/base.py @@ -13,25 +13,18 @@ import abc import logging -from oslo_config import cfg import six from keystoneauth1 import _utils as utils -from keystoneauth1 import base from keystoneauth1 import discover from keystoneauth1 import exceptions +from keystoneauth1 import plugin LOG = logging.getLogger(__name__) -def get_options(): - return [ - cfg.StrOpt('auth-url', help='Authentication URL'), - ] - - @six.add_metaclass(abc.ABCMeta) -class BaseIdentityPlugin(base.BaseAuthPlugin): +class BaseIdentityPlugin(plugin.BaseAuthPlugin): # we count a token as valid (not needing refreshing) if it is valid for at # least this many seconds before the token expiry time @@ -201,7 +194,7 @@ class BaseIdentityPlugin(base.BaseAuthPlugin): # are asking for the auth endpoint it means that there is no catalog to # query however we still need to support asking for a specific version # of the auth_url for generic plugins. - if interface is base.AUTH_INTERFACE: + if interface is plugin.AUTH_INTERFACE: url = self.auth_url service_type = service_type or 'identity' @@ -318,9 +311,3 @@ class BaseIdentityPlugin(base.BaseAuthPlugin): session_endpoint_cache[url] = disc return disc - - @classmethod - def get_options(cls): - options = super(BaseIdentityPlugin, cls).get_options() - options.extend(get_options()) - return options diff --git a/keystoneauth1/identity/generic/base.py b/keystoneauth1/identity/generic/base.py index e4e8c6d..a71491a 100644 --- a/keystoneauth1/identity/generic/base.py +++ b/keystoneauth1/identity/generic/base.py @@ -13,7 +13,6 @@ import abc import logging -from oslo_config import cfg import six import six.moves.urllib.parse as urlparse @@ -25,22 +24,6 @@ from keystoneauth1.identity import base LOG = logging.getLogger(__name__) -def get_options(): - return [ - cfg.StrOpt('domain-id', help='Domain ID to scope to'), - cfg.StrOpt('domain-name', help='Domain name to scope to'), - cfg.StrOpt('tenant-id', help='Tenant ID to scope to'), - cfg.StrOpt('tenant-name', help='Tenant name to scope to'), - cfg.StrOpt('project-id', help='Project ID to scope to'), - cfg.StrOpt('project-name', help='Project name to scope to'), - cfg.StrOpt('project-domain-id', - help='Domain ID containing project'), - cfg.StrOpt('project-domain-name', - help='Domain name containing project'), - cfg.StrOpt('trust-id', help='Trust ID'), - ] - - @six.add_metaclass(abc.ABCMeta) class BaseGenericPlugin(base.BaseIdentityPlugin): """An identity plugin that is not version dependant. @@ -173,9 +156,3 @@ class BaseGenericPlugin(base.BaseIdentityPlugin): self._plugin = self._do_create_plugin(session) return self._plugin.get_auth_ref(session, **kwargs) - - @classmethod - def get_options(cls): - options = super(BaseGenericPlugin, cls).get_options() - options.extend(get_options()) - return options diff --git a/keystoneauth1/identity/generic/password.py b/keystoneauth1/identity/generic/password.py index c509429..daf2e63 100644 --- a/keystoneauth1/identity/generic/password.py +++ b/keystoneauth1/identity/generic/password.py @@ -12,8 +12,6 @@ import logging -from oslo_config import cfg - from keystoneauth1 import _utils as utils from keystoneauth1 import discover from keystoneauth1.identity.generic import base @@ -23,17 +21,6 @@ from keystoneauth1.identity import v3 LOG = logging.getLogger(__name__) -def get_options(): - return [ - cfg.StrOpt('user-id', help='User id'), - cfg.StrOpt('user-name', dest='username', help='Username', - deprecated_name='username'), - cfg.StrOpt('user-domain-id', help="User's domain id"), - cfg.StrOpt('user-domain-name', help="User's domain name"), - cfg.StrOpt('password', help="User's password"), - ] - - class Password(base.BaseGenericPlugin): """A common user/password authentication plugin. @@ -76,9 +63,3 @@ class Password(base.BaseGenericPlugin): user_domain_name=self._user_domain_name, password=self._password, **self._v3_params) - - @classmethod - def get_options(cls): - options = super(Password, cls).get_options() - options.extend(get_options()) - return options diff --git a/keystoneauth1/identity/generic/token.py b/keystoneauth1/identity/generic/token.py index 635563f..7bca2e6 100644 --- a/keystoneauth1/identity/generic/token.py +++ b/keystoneauth1/identity/generic/token.py @@ -12,8 +12,6 @@ import logging -from oslo_config import cfg - from keystoneauth1 import discover from keystoneauth1.identity.generic import base from keystoneauth1.identity import v2 @@ -22,12 +20,6 @@ from keystoneauth1.identity import v3 LOG = logging.getLogger(__name__) -def get_options(): - return [ - cfg.StrOpt('token', help='Token to authenticate with'), - ] - - class Token(base.BaseGenericPlugin): """Generic token auth plugin. @@ -44,9 +36,3 @@ class Token(base.BaseGenericPlugin): elif discover.version_match((3,), version): return v3.Token(url, self._token, **self._v3_params) - - @classmethod - def get_options(cls): - options = super(Token, cls).get_options() - options.extend(get_options()) - return options diff --git a/keystoneauth1/identity/v2.py b/keystoneauth1/identity/v2.py index 3f6e896..e3d77cc 100644 --- a/keystoneauth1/identity/v2.py +++ b/keystoneauth1/identity/v2.py @@ -13,7 +13,6 @@ import abc import logging -from oslo_config import cfg import six from keystoneauth1 import _utils as utils @@ -36,18 +35,6 @@ class Auth(base.BaseIdentityPlugin): is going to expire. (optional) default True """ - @classmethod - def get_options(cls): - options = super(Auth, cls).get_options() - - options.extend([ - cfg.StrOpt('tenant-id', help='Tenant ID'), - cfg.StrOpt('tenant-name', help='Tenant Name'), - cfg.StrOpt('trust-id', help='Trust ID'), - ]) - - return options - @utils.positional() def __init__(self, auth_url, trust_id=None, @@ -147,21 +134,6 @@ class Password(Auth): return {'passwordCredentials': auth} - @classmethod - def get_options(cls): - options = super(Password, cls).get_options() - - options.extend([ - cfg.StrOpt('user-name', - dest='username', - deprecated_name='username', - help='Username to login with'), - cfg.StrOpt('user-id', help='User ID to login with'), - cfg.StrOpt('password', secret=True, help='Password to use'), - ]) - - return options - class Token(Auth): """A plugin for authenticating with an existing token. @@ -183,13 +155,3 @@ class Token(Auth): if headers is not None: headers['X-Auth-Token'] = self.token return {'token': {'id': self.token}} - - @classmethod - def get_options(cls): - options = super(Token, cls).get_options() - - options.extend([ - cfg.StrOpt('token', secret=True, help='Token'), - ]) - - return options diff --git a/keystoneauth1/identity/v3/base.py b/keystoneauth1/identity/v3/base.py index c4849f7..94967f0 100644 --- a/keystoneauth1/identity/v3/base.py +++ b/keystoneauth1/identity/v3/base.py @@ -13,7 +13,6 @@ import abc import logging -from oslo_config import cfg import six from keystoneauth1 import _utils as utils @@ -76,24 +75,6 @@ class BaseAuth(base.BaseIdentityPlugin): def get_auth_ref(self, session, **kwargs): return None - @classmethod - def get_options(cls): - options = super(BaseAuth, cls).get_options() - - options.extend([ - cfg.StrOpt('domain-id', help='Domain ID to scope to'), - cfg.StrOpt('domain-name', help='Domain name to scope to'), - cfg.StrOpt('project-id', help='Project ID to scope to'), - cfg.StrOpt('project-name', help='Project name to scope to'), - cfg.StrOpt('project-domain-id', - help='Domain ID containing project'), - cfg.StrOpt('project-domain-name', - help='Domain name containing project'), - cfg.StrOpt('trust-id', help='Trust ID'), - ]) - - return options - class Auth(BaseAuth): """Identity V3 Authentication Plugin. diff --git a/keystoneauth1/identity/v3/federation.py b/keystoneauth1/identity/v3/federation.py index 4c6e150..ad97ba3 100644 --- a/keystoneauth1/identity/v3/federation.py +++ b/keystoneauth1/identity/v3/federation.py @@ -12,7 +12,6 @@ import abc -from oslo_config import cfg import six from keystoneauth1.identity.v3 import base @@ -45,19 +44,6 @@ class FederationBaseAuth(base.BaseAuth): self.identity_provider = identity_provider self.protocol = protocol - @classmethod - def get_options(cls): - options = super(FederationBaseAuth, cls).get_options() - - options.extend([ - cfg.StrOpt('identity-provider', - help="Identity Provider's name"), - cfg.StrOpt('protocol', - help='Protocol for federated plugin'), - ]) - - return options - @property def federated_token_url(self): """Full URL where authorization data is sent.""" diff --git a/keystoneauth1/identity/v3/k2k.py b/keystoneauth1/identity/v3/k2k.py index 0acd2f2..e2cae75 100644 --- a/keystoneauth1/identity/v3/k2k.py +++ b/keystoneauth1/identity/v3/k2k.py @@ -10,13 +10,11 @@ # License for the specific language governing permissions and limitations # under the License. -from oslo_config import cfg - from keystoneauth1 import access -from keystoneauth1 import base as auth_base from keystoneauth1 import exceptions from keystoneauth1.identity.v3 import base from keystoneauth1.identity.v3 import token +from keystoneauth1 import plugin __all__ = ['Keystone2Keystone'] @@ -83,16 +81,6 @@ class Keystone2Keystone(base.BaseAuth): 'project_domain_id': self.project_domain_id, 'project_domain_name': self.project_domain_name} - @classmethod - def get_options(cls): - options = super(Keystone2Keystone, cls).get_options() - - options.extend([ - cfg.StrOpt("service-provider", help="Service Provider's ID") - ]) - - return options - def _ecp_assertion_request(self, session): token_id = self._local_cloud_plugin.get_access(session).auth_token body = { @@ -115,7 +103,7 @@ class Keystone2Keystone(base.BaseAuth): def _get_ecp_assertion(self, session): url = self._local_cloud_plugin.get_endpoint( - session, interface=auth_base.AUTH_INTERFACE) + session, interface=plugin.AUTH_INTERFACE) body = self._ecp_assertion_request(session) resp = session.post(url=url + self.REQUEST_ECP_URL, json=body, diff --git a/keystoneauth1/identity/v3/password.py b/keystoneauth1/identity/v3/password.py index 100ce76..b89ce84 100644 --- a/keystoneauth1/identity/v3/password.py +++ b/keystoneauth1/identity/v3/password.py @@ -10,8 +10,6 @@ # License for the specific language governing permissions and limitations # under the License. -from oslo_config import cfg - from keystoneauth1.identity.v3 import base @@ -71,18 +69,3 @@ class Password(base.AuthConstructor): """ _auth_method_class = PasswordMethod - - @classmethod - def get_options(cls): - options = super(Password, cls).get_options() - - options.extend([ - cfg.StrOpt('user-id', help='User ID'), - cfg.StrOpt('user-name', dest='username', help='Username', - deprecated_name='username'), - cfg.StrOpt('user-domain-id', help="User's domain id"), - cfg.StrOpt('user-domain-name', help="User's domain name"), - cfg.StrOpt('password', secret=True, help="User's password"), - ]) - - return options diff --git a/keystoneauth1/identity/v3/token.py b/keystoneauth1/identity/v3/token.py index 89e7f89..e9e0841 100644 --- a/keystoneauth1/identity/v3/token.py +++ b/keystoneauth1/identity/v3/token.py @@ -10,8 +10,6 @@ # License for the specific language governing permissions and limitations # under the License. -from oslo_config import cfg - from keystoneauth1.identity.v3 import base @@ -51,15 +49,3 @@ class Token(base.AuthConstructor): def __init__(self, auth_url, token, **kwargs): super(Token, self).__init__(auth_url, token=token, **kwargs) - - @classmethod - def get_options(cls): - options = super(Token, cls).get_options() - - options.extend([ - cfg.StrOpt('token', - secret=True, - help='Token to authenticate with'), - ]) - - return options diff --git a/keystoneauth1/loading/__init__.py b/keystoneauth1/loading/__init__.py new file mode 100644 index 0000000..8ae2568 --- /dev/null +++ b/keystoneauth1/loading/__init__.py @@ -0,0 +1,35 @@ +# 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. + +from keystoneauth1.loading.base import * # noqa +from keystoneauth1.loading.cli import * # noqa +from keystoneauth1.loading.conf import * # noqa + + +__all__ = [ + # loading.base + 'BaseLoader', + 'get_available_plugin_names', + 'get_available_plugin_loaders', + 'get_plugin_loader', + 'PLUGIN_NAMESPACE', + + # loading.cli + 'load_from_argparse_arguments', + 'register_argparse_arguments', + + # loading.conf + 'get_common_conf_options', + 'get_plugin_options', + 'load_from_conf_options', + 'register_conf_options', +] diff --git a/keystoneauth1/loading/_plugins/__init__.py b/keystoneauth1/loading/_plugins/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/keystoneauth1/loading/_plugins/identity/__init__.py b/keystoneauth1/loading/_plugins/identity/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/keystoneauth1/loading/_plugins/identity/base.py b/keystoneauth1/loading/_plugins/identity/base.py new file mode 100644 index 0000000..9b9e531 --- /dev/null +++ b/keystoneauth1/loading/_plugins/identity/base.py @@ -0,0 +1,27 @@ +# 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. + +from oslo_config import cfg + +from keystoneauth1 import loading + + +class BaseIdentityLoader(loading.BaseLoader): + + def get_options(self): + options = super(BaseIdentityLoader, self).get_options() + + options.extend([ + cfg.StrOpt('auth-url', help='Authentication URL'), + ]) + + return options diff --git a/keystoneauth1/loading/_plugins/identity/generic.py b/keystoneauth1/loading/_plugins/identity/generic.py new file mode 100644 index 0000000..049248f --- /dev/null +++ b/keystoneauth1/loading/_plugins/identity/generic.py @@ -0,0 +1,75 @@ +# 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. + +from oslo_config import cfg + +from keystoneauth1 import identity +from keystoneauth1.loading._plugins.identity import base + + +class GenericBaseLoader(base.BaseIdentityLoader): + + def get_options(self): + options = super(GenericBaseLoader, self).get_options() + + options.extend([ + cfg.StrOpt('domain-id', help='Domain ID to scope to'), + cfg.StrOpt('domain-name', help='Domain name to scope to'), + cfg.StrOpt('tenant-id', help='Tenant ID to scope to'), + cfg.StrOpt('tenant-name', help='Tenant name to scope to'), + cfg.StrOpt('project-id', help='Project ID to scope to'), + cfg.StrOpt('project-name', help='Project name to scope to'), + cfg.StrOpt('project-domain-id', + help='Domain ID containing project'), + cfg.StrOpt('project-domain-name', + help='Domain name containing project'), + cfg.StrOpt('trust-id', help='Trust ID'), + ]) + + return options + + +class Token(GenericBaseLoader): + + @property + def plugin_class(self): + return identity.Token + + def get_options(self): + options = super(Token, self).get_options() + + options.extend([ + cfg.StrOpt('token', help='Token to authenticate with'), + ]) + + return options + + +class Password(GenericBaseLoader): + + @property + def plugin_class(self): + return identity.Password + + def get_options(cls): + options = super(Password, cls).get_options() + options.extend([ + cfg.StrOpt('user-id', help='User id'), + cfg.StrOpt('user-name', + dest='username', + help='Username', + deprecated_name='username'), + cfg.StrOpt('user-domain-id', help="User's domain id"), + cfg.StrOpt('user-domain-name', help="User's domain name"), + cfg.StrOpt('password', help="User's password"), + ]) + return options diff --git a/keystoneauth1/loading/_plugins/identity/v2.py b/keystoneauth1/loading/_plugins/identity/v2.py new file mode 100644 index 0000000..da7f77b --- /dev/null +++ b/keystoneauth1/loading/_plugins/identity/v2.py @@ -0,0 +1,67 @@ +# 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. + +from oslo_config import cfg + +from keystoneauth1 import identity +from keystoneauth1.loading._plugins.identity import base + + +class BaseV2Loader(base.BaseIdentityLoader): + + def get_options(self): + options = super(BaseV2Loader, self).get_options() + + options.extend([ + cfg.StrOpt('tenant-id', help='Tenant ID'), + cfg.StrOpt('tenant-name', help='Tenant Name'), + cfg.StrOpt('trust-id', help='Trust ID'), + ]) + + return options + + +class V2Token(BaseV2Loader): + + @property + def plugin_class(self): + return identity.V2Token + + def get_options(self): + options = super(V2Token, self).get_options() + + options.extend([ + cfg.StrOpt('token', secret=True, help='Token'), + ]) + + return options + + +class V2Password(BaseV2Loader): + + @property + def plugin_class(self): + return identity.V2Password + + def get_options(self): + options = super(V2Password, self).get_options() + + options.extend([ + cfg.StrOpt('user-name', + dest='username', + deprecated_name='username', + help='Username to login with'), + cfg.StrOpt('user-id', help='User ID to longin with'), + cfg.StrOpt('password', secret=True, help='Password to use'), + ]) + + return options diff --git a/keystoneauth1/loading/_plugins/identity/v3.py b/keystoneauth1/loading/_plugins/identity/v3.py new file mode 100644 index 0000000..a311665 --- /dev/null +++ b/keystoneauth1/loading/_plugins/identity/v3.py @@ -0,0 +1,92 @@ +# 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. + +from oslo_config import cfg + +from keystoneauth1 import identity +from keystoneauth1.loading._plugins.identity import base + + +class BaseV3Loader(base.BaseIdentityLoader): + + def get_options(self): + options = super(BaseV3Loader, self).get_options() + + options.extend([ + cfg.StrOpt('domain-id', help='Domain ID to scope to'), + cfg.StrOpt('domain-name', help='Domain name to scope to'), + cfg.StrOpt('project-id', help='Project ID to scope to'), + cfg.StrOpt('project-name', help='Project name to scope to'), + cfg.StrOpt('project-domain-id', + help='Domain ID containing project'), + cfg.StrOpt('project-domain-name', + help='Domain name containing project'), + cfg.StrOpt('trust-id', help='Trust ID'), + ]) + + return options + + +class Password(BaseV3Loader): + + @property + def plugin_class(self): + return identity.V3Password + + def get_options(self): + options = super(Password, self).get_options() + + options.extend([ + cfg.StrOpt('user-id', help='User ID'), + cfg.StrOpt('user-name', + dest='username', + help='Username', + deprecated_name='username'), + cfg.StrOpt('user-domain-id', help="User's domain id"), + cfg.StrOpt('user-domain-name', help="User's domain name"), + cfg.StrOpt('password', secret=True, help="User's password"), + ]) + + return options + + +class Token(BaseV3Loader): + + @property + def plugin_class(self): + return identity.Token + + def get_options(self): + options = super(Token, self).get_options() + + options.extend([ + cfg.StrOpt('token', + secret=True, + help='Token to authenticate with'), + ]) + + return options + + +class FederatedBase(BaseV3Loader): + + def get_options(self): + options = super(FederatedBase, self).get_options() + + options.extend([ + cfg.StrOpt('identity-provider', + help="Identity Provider's name"), + cfg.StrOpt('protocol', + help='Protocol for federated plugin'), + ]) + + return options diff --git a/keystoneauth1/loading/_plugins/token_endpoint.py b/keystoneauth1/loading/_plugins/token_endpoint.py new file mode 100644 index 0000000..361408c --- /dev/null +++ b/keystoneauth1/loading/_plugins/token_endpoint.py @@ -0,0 +1,36 @@ +# 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. + +from oslo_config import cfg + +from keystoneauth1 import loading +from keystoneauth1 import token_endpoint + + +class TokenEndpoint(loading.BaseLoader): + + @property + def plugin_class(self): + return token_endpoint.TokenEndpoint + + def get_options(self): + options = super(TokenEndpoint, self).get_options() + + options.extend([ + cfg.StrOpt('endpoint', + help='The endpoint that will always be used'), + cfg.StrOpt('token', + secret=True, + help='The token that will always be used'), + ]) + + return options diff --git a/keystoneauth1/loading/base.py b/keystoneauth1/loading/base.py new file mode 100644 index 0000000..588fa5c --- /dev/null +++ b/keystoneauth1/loading/base.py @@ -0,0 +1,202 @@ +# 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 abc +import os + +import six +import stevedore + +from keystoneauth1 import exceptions + +PLUGIN_NAMESPACE = 'keystoneauth1.plugin' + + +def get_available_plugin_names(): + """Get the names of all the plugins that are available on the system. + + This is particularly useful for help and error text to prompt a user for + example what plugins they may specify. + + :returns: A list of names. + :rtype: frozenset + """ + mgr = stevedore.ExtensionManager(namespace=PLUGIN_NAMESPACE) + return frozenset(mgr.names()) + + +def get_available_plugin_loaders(): + """Retrieve all the plugin classes available on the system. + + :returns: A dict with plugin entrypoint name as the key and the plugin + class as the value. + :rtype: dict + """ + mgr = stevedore.ExtensionManager(namespace=PLUGIN_NAMESPACE, + propagate_map_exceptions=True) + + return dict(mgr.map(lambda ext: (ext.entry_point.name, ext.plugin))) + + +def get_plugin_loader(name): + """Retrieve a plugin class by its entrypoint name. + + :param str name: The name of the object to get. + + :returns: An auth plugin class. + :rtype: :py:class:`keystoneauth1.loading.BaseLoader` + + :raises keystonauth.exceptions.NoMatchingPlugin: if a plugin cannot be + created. + """ + try: + mgr = stevedore.DriverManager(namespace=PLUGIN_NAMESPACE, + name=name) + except RuntimeError: + raise exceptions.NoMatchingPlugin(name) + + return mgr.driver + + +@six.add_metaclass(abc.ABCMeta) +class BaseLoader(object): + + @abc.abstractproperty + def plugin_class(self): + raise NotImplemented() + + @abc.abstractmethod + def get_options(self): + """Return the list of parameters associated with the auth plugin. + + This list may be used to generate CLI or config arguments. + + :returns: A list of Param objects describing available plugin + parameters. + :rtype: list + """ + return [] + + def load_from_options(self, **kwargs): + """Create a plugin from the arguments retrieved from get_options. + + A client can override this function to do argument validation or to + handle differences between the registered options and what is required + to create the plugin. + """ + return self.plugin_class(**kwargs) + + def register_argparse_arguments(self, parser): + """Register the CLI options provided by a specific plugin. + + Given a plugin class convert it's options into argparse arguments and + add them to a parser. + + :param parser: the parser to attach argparse options. + :type parser: argparse.ArgumentParser + """ + + # NOTE(jamielennox): ideally oslo_config would be smart enough to + # handle all the Opt manipulation that goes on in this file. However it + # is currently not. Options are handled in as similar a way as + # possible to oslo_config such that when available we should be able to + # transition. + + for opt in self.get_options(): + args = [] + envs = [] + + for o in [opt] + opt.deprecated_opts: + args.append('--os-%s' % o.name) + envs.append('OS_%s' % o.name.replace('-', '_').upper()) + + # select the first ENV that is not false-y or return None + env_vars = (os.environ.get(e) for e in envs) + default = six.next(six.moves.filter(None, env_vars), None) + + parser.add_argument(*args, + default=default or opt.default, + metavar=opt.metavar, + help=opt.help, + dest='os_%s' % opt.dest) + + def load_from_argparse_arguments(self, namespace, **kwargs): + """Load a specific plugin object from an argparse result. + + Convert the results of a parse into the specified plugin. + + :param namespace: The result from CLI parsing. + :type namespace: argparse.Namespace + + :returns: An auth plugin, or None if a name is not provided. + :rtype: :py:class:`keystonauth.auth.BaseAuthPlugin` + """ + + def _getter(opt): + return getattr(namespace, 'os_%s' % opt.dest) + + return self.load_from_options_getter(_getter, **kwargs) + + def register_conf_options(self, conf, group): + """Register the oslo_config options that are needed for a plugin. + + :param conf: A config object. + :type conf: oslo_config.cfg.ConfigOpts + :param string group: The group name that options should be read from. + """ + plugin_opts = self.get_options() + conf.register_opts(plugin_opts, group=group) + + def load_from_conf_options(self, conf, group, **kwargs): + """Load the plugin from a CONF object. + + Convert the options already registered into a real plugin. + + :param conf: A config object. + :type conf: oslo_config.cfg.ConfigOpts + :param string group: The group name that options should be read from. + + :returns: An authentication Plugin. + :rtype: :py:class:`keystonauth.auth.BaseAuthPlugin` + """ + + def _getter(opt): + return conf[group][opt.dest] + + return self.load_from_options_getter(_getter, **kwargs) + + def load_from_options_getter(self, getter, **kwargs): + """Load a plugin from a getter function that returns appropriate values + + To handle cases other than the provided CONF and CLI loading you can + specify a custom loader function that will be queried for the option + value. + + The getter is a function that takes one value, an + :py:class:`oslo_config.cfg.Opt` and returns a value to load with. + + :param getter: A function that returns a value for the given opt. + :type getter: callable + + :returns: An authentication Plugin. + :rtype: :py:class:`keystonauth.auth.BaseAuthPlugin` + """ + + plugin_opts = self.get_options() + + for opt in plugin_opts: + val = getter(opt) + if val is not None: + val = opt.type(val) + kwargs.setdefault(opt.dest, val) + + return self.load_from_options(**kwargs) diff --git a/keystoneauth1/cli.py b/keystoneauth1/loading/cli.py similarity index 94% rename from keystoneauth1/cli.py rename to keystoneauth1/loading/cli.py index b27299c..b124a29 100644 --- a/keystoneauth1/cli.py +++ b/keystoneauth1/loading/cli.py @@ -14,7 +14,7 @@ import argparse import os from keystoneauth1 import _utils as utils -from keystoneauth1 import base +from keystoneauth1.loading import base @utils.positional() @@ -53,7 +53,7 @@ def register_argparse_arguments(parser, argv, default=None): plugin = options.os_auth_plugin else: msg = 'Options specific to the %s plugin.' % options.os_auth_plugin - plugin = base.get_plugin_class(options.os_auth_plugin) + plugin = base.get_plugin_loader(options.os_auth_plugin) group = parser.add_argument_group('Authentication Options', msg) plugin.register_argparse_arguments(group) @@ -80,6 +80,6 @@ def load_from_argparse_arguments(namespace, **kwargs): if isinstance(namespace.os_auth_plugin, type): plugin = namespace.os_auth_plugin else: - plugin = base.get_plugin_class(namespace.os_auth_plugin) + plugin = base.get_plugin_loader(namespace.os_auth_plugin) return plugin.load_from_argparse_arguments(namespace, **kwargs) diff --git a/keystoneauth1/conf.py b/keystoneauth1/loading/conf.py similarity index 96% rename from keystoneauth1/conf.py rename to keystoneauth1/loading/conf.py index 1a7b9c2..4f316b4 100644 --- a/keystoneauth1/conf.py +++ b/keystoneauth1/loading/conf.py @@ -12,7 +12,7 @@ from oslo_config import cfg -from keystoneauth1 import base +from keystoneauth1.loading import base _AUTH_PLUGIN_OPT = cfg.StrOpt('auth_plugin', help='Name of the plugin to load') @@ -43,7 +43,7 @@ def get_plugin_options(name): :returns: A list of oslo_config options. """ - return base.get_plugin_class(name).get_options() + return base.get_plugin_loader(name).get_options() def register_conf_options(conf, group): @@ -106,6 +106,6 @@ def load_from_conf_options(conf, group, **kwargs): if not name: return None - plugin_class = base.get_plugin_class(name) + plugin_class = base.get_plugin_loader(name) plugin_class.register_conf_options(conf, group) return plugin_class.load_from_conf_options(conf, group, **kwargs) diff --git a/keystoneauth1/base.py b/keystoneauth1/plugin.py similarity index 54% rename from keystoneauth1/base.py rename to keystoneauth1/plugin.py index 6b85973..80e1999 100644 --- a/keystoneauth1/base.py +++ b/keystoneauth1/plugin.py @@ -10,72 +10,14 @@ # License for the specific language governing permissions and limitations # under the License. -import os - -import six -import stevedore - -from keystoneauth1 import exceptions - - # NOTE(jamielennox): The AUTH_INTERFACE is a special value that can be # requested from get_endpoint. If a plugin receives this as the value of # 'interface' it should return the initial URL that was passed to the plugin. AUTH_INTERFACE = object() -PLUGIN_NAMESPACE = 'keystoneauth1.auth.plugin' IDENTITY_AUTH_HEADER_NAME = 'X-Auth-Token' -def get_available_plugin_names(): - """Get the names of all the plugins that are available on the system. - - This is particularly useful for help and error text to prompt a user for - example what plugins they may specify. - - :returns: A list of names. - :rtype: frozenset - """ - mgr = stevedore.ExtensionManager(namespace=PLUGIN_NAMESPACE, - invoke_on_load=False) - return frozenset(mgr.names()) - - -def get_available_plugin_classes(): - """Retrieve all the plugin classes available on the system. - - :returns: A dict with plugin entrypoint name as the key and the plugin - class as the value. - :rtype: dict - """ - mgr = stevedore.ExtensionManager(namespace=PLUGIN_NAMESPACE, - propagate_map_exceptions=True, - invoke_on_load=False) - - return dict(mgr.map(lambda ext: (ext.entry_point.name, ext.plugin))) - - -def get_plugin_class(name): - """Retrieve a plugin class by its entrypoint name. - - :param str name: The name of the object to get. - - :returns: An auth plugin class. - :rtype: :py:class:`keystonauth.auth.BaseAuthPlugin` - - :raises keystonauth.exceptions.NoMatchingPlugin: if a plugin cannot be - created. - """ - try: - mgr = stevedore.DriverManager(namespace=PLUGIN_NAMESPACE, - name=name, - invoke_on_load=False) - except RuntimeError: - raise exceptions.NoMatchingPlugin(name) - - return mgr.driver - - class BaseAuthPlugin(object): """The basic structure of an authentication plugin.""" @@ -255,136 +197,3 @@ class BaseAuthPlugin(object): """ return None - - @classmethod - def get_options(cls): - """Return the list of parameters associated with the auth plugin. - - This list may be used to generate CLI or config arguments. - - :returns: A list of Param objects describing available plugin - parameters. - :rtype: list - """ - return [] - - @classmethod - def load_from_options(cls, **kwargs): - """Create a plugin from the arguments retrieved from get_options. - - A client can override this function to do argument validation or to - handle differences between the registered options and what is required - to create the plugin. - """ - return cls(**kwargs) - - @classmethod - def register_argparse_arguments(cls, parser): - """Register the CLI options provided by a specific plugin. - - Given a plugin class convert it's options into argparse arguments and - add them to a parser. - - :param parser: the parser to attach argparse options. - :type parser: argparse.ArgumentParser - """ - - # NOTE(jamielennox): ideally oslo_config would be smart enough to - # handle all the Opt manipulation that goes on in this file. However it - # is currently not. Options are handled in as similar a way as - # possible to oslo_config such that when available we should be able to - # transition. - - for opt in cls.get_options(): - args = [] - envs = [] - - for o in [opt] + opt.deprecated_opts: - args.append('--os-%s' % o.name) - envs.append('OS_%s' % o.name.replace('-', '_').upper()) - - # select the first ENV that is not false-y or return None - env_vars = (os.environ.get(e) for e in envs) - default = six.next(six.moves.filter(None, env_vars), None) - - parser.add_argument(*args, - default=default or opt.default, - metavar=opt.metavar, - help=opt.help, - dest='os_%s' % opt.dest) - - @classmethod - def load_from_argparse_arguments(cls, namespace, **kwargs): - """Load a specific plugin object from an argparse result. - - Convert the results of a parse into the specified plugin. - - :param namespace: The result from CLI parsing. - :type namespace: argparse.Namespace - - :returns: An auth plugin, or None if a name is not provided. - :rtype: :py:class:`keystonauth.auth.BaseAuthPlugin` - """ - - def _getter(opt): - return getattr(namespace, 'os_%s' % opt.dest) - - return cls.load_from_options_getter(_getter, **kwargs) - - @classmethod - def register_conf_options(cls, conf, group): - """Register the oslo_config options that are needed for a plugin. - - :param conf: A config object. - :type conf: oslo_config.cfg.ConfigOpts - :param string group: The group name that options should be read from. - """ - plugin_opts = cls.get_options() - conf.register_opts(plugin_opts, group=group) - - @classmethod - def load_from_conf_options(cls, conf, group, **kwargs): - """Load the plugin from a CONF object. - - Convert the options already registered into a real plugin. - - :param conf: A config object. - :type conf: oslo_config.cfg.ConfigOpts - :param string group: The group name that options should be read from. - - :returns: An authentication Plugin. - :rtype: :py:class:`keystonauth.auth.BaseAuthPlugin` - """ - - def _getter(opt): - return conf[group][opt.dest] - - return cls.load_from_options_getter(_getter, **kwargs) - - @classmethod - def load_from_options_getter(cls, getter, **kwargs): - """Load a plugin from a getter function that returns appropriate values - - To handle cases other than the provided CONF and CLI loading you can - specify a custom loader function that will be queried for the option - value. - - The getter is a function that takes one value, an - :py:class:`oslo_config.cfg.Opt` and returns a value to load with. - - :param getter: A function that returns a value for the given opt. - :type getter: callable - - :returns: An authentication Plugin. - :rtype: :py:class:`keystonauth.auth.BaseAuthPlugin` - """ - - plugin_opts = cls.get_options() - - for opt in plugin_opts: - val = getter(opt) - if val is not None: - val = opt.type(val) - kwargs.setdefault(opt.dest, val) - - return cls.load_from_options(**kwargs) diff --git a/keystoneauth1/tests/unit/auth/test_access.py b/keystoneauth1/tests/unit/auth/test_access.py index 1c1803c..15eaba3 100644 --- a/keystoneauth1/tests/unit/auth/test_access.py +++ b/keystoneauth1/tests/unit/auth/test_access.py @@ -13,9 +13,9 @@ import uuid from keystoneauth1 import access -from keystoneauth1 import base from keystoneauth1 import fixture from keystoneauth1.identity import access as access_plugin +from keystoneauth1 import plugin from keystoneauth1 import session from keystoneauth1.tests.unit import utils @@ -36,20 +36,20 @@ class AccessInfoPluginTests(utils.TestCase): return access_plugin.AccessInfoPlugin(auth_ref, **kwargs) def test_auth_ref(self): - plugin = self._plugin() + plugin_obj = self._plugin() self.assertEqual(self.TEST_ROOT_URL, - plugin.get_endpoint(self.session, - service_type='identity', - interface='public')) - self.assertEqual(self.auth_token, plugin.get_token(session)) + plugin_obj.get_endpoint(self.session, + service_type='identity', + interface='public')) + self.assertEqual(self.auth_token, plugin_obj.get_token(session)) def test_auth_url(self): auth_url = 'http://keystone.test.url' - plugin = self._plugin(auth_url=auth_url) + obj = self._plugin(auth_url=auth_url) self.assertEqual(auth_url, - plugin.get_endpoint(self.session, - interface=base.AUTH_INTERFACE)) + obj.get_endpoint(self.session, + interface=plugin.AUTH_INTERFACE)) def test_invalidate(self): plugin = self._plugin() diff --git a/keystoneauth1/tests/unit/auth/test_identity_common.py b/keystoneauth1/tests/unit/auth/test_identity_common.py index dfc2dd8..85d4517 100644 --- a/keystoneauth1/tests/unit/auth/test_identity_common.py +++ b/keystoneauth1/tests/unit/auth/test_identity_common.py @@ -18,10 +18,10 @@ import six from keystoneauth1 import _utils from keystoneauth1 import access -from keystoneauth1 import base from keystoneauth1 import exceptions from keystoneauth1 import fixture from keystoneauth1 import identity +from keystoneauth1 import plugin from keystoneauth1 import session from keystoneauth1.tests.unit import utils @@ -187,7 +187,7 @@ class CommonIdentityTests(object): s = session.Session(auth=a) auth_url = s.get_endpoint(service_type='compute', - interface=base.AUTH_INTERFACE) + interface=plugin.AUTH_INTERFACE) self.assertEqual(self.TEST_URL, auth_url) @@ -394,13 +394,13 @@ class CatalogHackTests(utils.TestCase): sess = session.Session(auth=v2_auth) - endpoint = sess.get_endpoint(interface=base.AUTH_INTERFACE, + endpoint = sess.get_endpoint(interface=plugin.AUTH_INTERFACE, version=(3, 0)) self.assertEqual(self.V3_URL, endpoint) -class GenericPlugin(base.BaseAuthPlugin): +class GenericPlugin(plugin.BaseAuthPlugin): BAD_TOKEN = uuid.uuid4().hex diff --git a/keystoneauth1/tests/unit/auth/test_identity_v3_federation.py b/keystoneauth1/tests/unit/auth/test_identity_v3_federation.py index 5557075..714bc3e 100644 --- a/keystoneauth1/tests/unit/auth/test_identity_v3_federation.py +++ b/keystoneauth1/tests/unit/auth/test_identity_v3_federation.py @@ -93,12 +93,6 @@ class V3FederatedPlugin(utils.TestCase): self.assertTrue(self.unscoped_mock.called) self.assertTrue(self.scoped_mock.called) - def test_options(self): - opts = [o.name for o in v3.FederationBaseAuth.get_options()] - - self.assertIn('protocol', opts) - self.assertIn('identity-provider', opts) - class K2KAuthPluginTest(utils.TestCase): @@ -167,10 +161,6 @@ class K2KAuthPluginTest(utils.TestCase): kwargs.setdefault('service_provider', self.SP_ID) return v3.Keystone2Keystone(**kwargs) - def test_options(self): - opts = [o.name for o in v3.Keystone2Keystone.get_options()] - self.assertIn('service-provider', opts) - def test_remote_url(self): remote_auth_url = self.k2kplugin._remote_auth_url(self.SP_AUTH_URL) self.assertEqual(self.SP_ROOT_URL, remote_auth_url) diff --git a/keystoneauth1/tests/unit/auth/test_loading.py b/keystoneauth1/tests/unit/auth/test_loading.py index 382a68c..2b90bbb 100644 --- a/keystoneauth1/tests/unit/auth/test_loading.py +++ b/keystoneauth1/tests/unit/auth/test_loading.py @@ -35,7 +35,7 @@ class TestOtherLoading(utils.TestCase): # return str because oslo.config should convert them back return str(vals[opt.name]) - p = utils.MockPlugin.load_from_options_getter(_getter, other=val) + p = utils.MockLoader().load_from_options_getter(_getter, other=val) self.assertEqual(set(vals), set(called_opts)) diff --git a/keystoneauth1/tests/unit/auth/test_password.py b/keystoneauth1/tests/unit/auth/test_password.py index 22b4e86..08e62fc 100644 --- a/keystoneauth1/tests/unit/auth/test_password.py +++ b/keystoneauth1/tests/unit/auth/test_password.py @@ -16,6 +16,7 @@ from keystoneauth1.identity.generic import password from keystoneauth1.identity import v2 from keystoneauth1.identity import v3 from keystoneauth1.identity.v3 import password as v3_password +from keystoneauth1.loading._plugins.identity import generic from keystoneauth1.tests.unit.auth import utils @@ -41,7 +42,7 @@ class PasswordTests(utils.GenericPluginTestCase): self.assertDiscoveryFailure(user_domain_id=uuid.uuid4().hex) def test_options(self): - opts = [o.name for o in self.PLUGIN_CLASS.get_options()] + opts = [o.name for o in generic.Password().get_options()] allowed_opts = ['user-name', 'user-domain-id', diff --git a/keystoneauth1/tests/unit/auth/test_token.py b/keystoneauth1/tests/unit/auth/test_token.py index 25a717c..ecb8f4c 100644 --- a/keystoneauth1/tests/unit/auth/test_token.py +++ b/keystoneauth1/tests/unit/auth/test_token.py @@ -16,6 +16,7 @@ from keystoneauth1.identity.generic import token from keystoneauth1.identity import v2 from keystoneauth1.identity import v3 from keystoneauth1.identity.v3 import token as v3_token +from keystoneauth1.loading._plugins.identity import generic from keystoneauth1.tests.unit.auth import utils @@ -30,7 +31,7 @@ class TokenTests(utils.GenericPluginTestCase): return super(TokenTests, self).new_plugin(**kwargs) def test_options(self): - opts = [o.name for o in self.PLUGIN_CLASS.get_options()] + opts = [o.name for o in generic.Token().get_options()] allowed_opts = ['token', 'domain-id', diff --git a/keystoneauth1/tests/unit/auth/test_token_endpoint.py b/keystoneauth1/tests/unit/auth/test_token_endpoint.py index 0824c9b..9b2417d 100644 --- a/keystoneauth1/tests/unit/auth/test_token_endpoint.py +++ b/keystoneauth1/tests/unit/auth/test_token_endpoint.py @@ -12,6 +12,7 @@ from testtools import matchers +from keystoneauth1.loading._plugins import token_endpoint as loader from keystoneauth1 import session from keystoneauth1.tests.unit import utils from keystoneauth1 import token_endpoint @@ -47,7 +48,7 @@ class TokenEndpointTest(utils.TestCase): self.assertRequestHeaderEqual('X-Auth-Token', self.TEST_TOKEN) def test_token_endpoint_options(self): - opt_names = [opt.name for opt in token_endpoint.Token.get_options()] + opt_names = [opt.name for opt in loader.TokenEndpoint().get_options()] self.assertThat(opt_names, matchers.HasLength(2)) diff --git a/keystoneauth1/tests/unit/auth/utils.py b/keystoneauth1/tests/unit/auth/utils.py index a4a363f..4dd8655 100644 --- a/keystoneauth1/tests/unit/auth/utils.py +++ b/keystoneauth1/tests/unit/auth/utils.py @@ -18,20 +18,15 @@ from oslo_config import cfg import six from keystoneauth1 import access -from keystoneauth1 import base from keystoneauth1 import exceptions from keystoneauth1 import fixture +from keystoneauth1 import loading +from keystoneauth1 import plugin from keystoneauth1 import session from keystoneauth1.tests.unit import utils -class MockPlugin(base.BaseAuthPlugin): - - INT_DESC = 'test int' - FLOAT_DESC = 'test float' - BOOL_DESC = 'test bool' - STR_DESC = 'test str' - STR_DEFAULT = uuid.uuid4().hex +class MockPlugin(plugin.BaseAuthPlugin): def __init__(self, **kwargs): self._data = kwargs @@ -45,13 +40,25 @@ class MockPlugin(base.BaseAuthPlugin): def get_endpoint(self, *args, **kwargs): return 'http://test' - @classmethod - def get_options(cls): + +class MockLoader(loading.BaseLoader): + + INT_DESC = 'test int' + FLOAT_DESC = 'test float' + BOOL_DESC = 'test bool' + STR_DESC = 'test str' + STR_DEFAULT = uuid.uuid4().hex + + @property + def plugin_class(self): + return MockPlugin + + def get_options(self): return [ - cfg.IntOpt('a-int', default='3', help=cls.INT_DESC), - cfg.BoolOpt('a-bool', help=cls.BOOL_DESC), - cfg.FloatOpt('a-float', help=cls.FLOAT_DESC), - cfg.StrOpt('a-str', help=cls.STR_DESC, default=cls.STR_DEFAULT), + cfg.IntOpt('a-int', default='3', help=self.INT_DESC), + cfg.BoolOpt('a-bool', help=self.BOOL_DESC), + cfg.FloatOpt('a-float', help=self.FLOAT_DESC), + cfg.StrOpt('a-str', help=self.STR_DESC, default=self.STR_DEFAULT), ] @@ -64,7 +71,7 @@ class MockManager(object): def mock_plugin(f): @functools.wraps(f) def inner(*args, **kwargs): - with mock.patch.object(base, 'get_plugin_class') as m: + with mock.patch.object(loading, 'get_plugin_loader') as m: m.return_value = MockPlugin args = list(args) + [m] return f(*args, **kwargs) diff --git a/keystoneauth1/tests/unit/auth/test_cli.py b/keystoneauth1/tests/unit/loading/test_cli.py similarity index 77% rename from keystoneauth1/tests/unit/auth/test_cli.py rename to keystoneauth1/tests/unit/loading/test_cli.py index 912dcfe..11f3369 100644 --- a/keystoneauth1/tests/unit/auth/test_cli.py +++ b/keystoneauth1/tests/unit/loading/test_cli.py @@ -18,7 +18,7 @@ import mock from oslo_config import cfg from keystoneauth1 import base -from keystoneauth1 import cli +from keystoneauth1 import loading from keystoneauth1.tests.unit.auth import utils @@ -27,8 +27,14 @@ class TesterPlugin(base.BaseAuthPlugin): def get_token(self, *args, **kwargs): return None - @classmethod - def get_options(cls): + +class TesterLoader(loading.BaseLoader): + + @property + def plugin_class(self): + return TesterPlugin + + def get_options(self): # NOTE(jamielennox): this is kind of horrible. If you specify this as # a deprecated_name= value it will convert - to _ which is not what we # want for a CLI option. @@ -52,20 +58,20 @@ class CliTests(utils.TestCase): return self.useFixture(fixtures.EnvironmentVariable(name, value)) def test_creating_with_no_args(self): - ret = cli.register_argparse_arguments(self.p, []) + ret = loading.register_argparse_arguments(self.p, []) self.assertIsNone(ret) self.assertIn('--os-auth-plugin', self.p.format_usage()) def test_load_with_nothing(self): - cli.register_argparse_arguments(self.p, []) + loading.register_argparse_arguments(self.p, []) opts = self.p.parse_args([]) - self.assertIsNone(cli.load_from_argparse_arguments(opts)) + self.assertIsNone(loading.load_from_argparse_arguments(opts)) @utils.mock_plugin def test_basic_params_added(self, m): name = uuid.uuid4().hex argv = ['--os-auth-plugin', name] - ret = cli.register_argparse_arguments(self.p, argv) + ret = loading.register_argparse_arguments(self.p, argv) self.assertIs(utils.MockPlugin, ret) for n in ('--os-a-int', '--os-a-bool', '--os-a-float'): @@ -81,13 +87,13 @@ class CliTests(utils.TestCase): '--os-a-float', str(self.a_float), '--os-a-bool', str(self.a_bool)] - klass = cli.register_argparse_arguments(self.p, argv) + klass = loading.register_argparse_arguments(self.p, argv) self.assertIs(utils.MockPlugin, klass) opts = self.p.parse_args(argv) self.assertEqual(name, opts.os_auth_plugin) - a = cli.load_from_argparse_arguments(opts) + a = loading.load_from_argparse_arguments(opts) self.assertTestVals(a) self.assertEqual(name, opts.os_auth_plugin) @@ -101,13 +107,13 @@ class CliTests(utils.TestCase): argv = ['--os-auth-plugin', name, '--os-a-float', str(self.a_float)] - klass = cli.register_argparse_arguments(self.p, argv) + klass = loading.register_argparse_arguments(self.p, argv) self.assertIs(utils.MockPlugin, klass) opts = self.p.parse_args(argv) self.assertEqual(name, opts.os_auth_plugin) - a = cli.load_from_argparse_arguments(opts) + a = loading.load_from_argparse_arguments(opts) self.assertEqual(self.a_float, a['a_float']) self.assertEqual(3, a['a_int']) @@ -115,7 +121,7 @@ class CliTests(utils.TestCase): @utils.mock_plugin def test_with_default_string_value(self, m): name = uuid.uuid4().hex - klass = cli.register_argparse_arguments(self.p, [], default=name) + klass = loading.register_argparse_arguments(self.p, [], default=name) self.assertIs(utils.MockPlugin, klass) m.assert_called_once_with(name) @@ -124,14 +130,17 @@ class CliTests(utils.TestCase): name = uuid.uuid4().hex default = uuid.uuid4().hex argv = ['--os-auth-plugin', name] - klass = cli.register_argparse_arguments(self.p, argv, default=default) + klass = loading.register_argparse_arguments(self.p, + argv, + default=default) self.assertIs(utils.MockPlugin, klass) m.assert_called_once_with(name) @utils.mock_plugin def test_with_default_type_value(self, m): - klass = cli.register_argparse_arguments(self.p, [], - default=utils.MockPlugin) + klass = loading.register_argparse_arguments(self.p, + [], + default=utils.MockPlugin) self.assertIs(utils.MockPlugin, klass) self.assertEqual(0, m.call_count) @@ -143,8 +152,9 @@ class CliTests(utils.TestCase): pass name = uuid.uuid4().hex argv = ['--os-auth-plugin', name] - klass = cli.register_argparse_arguments(self.p, argv, - default=TestPlugin) + klass = loading.register_argparse_arguments(self.p, + argv, + default=TestPlugin) self.assertIs(utils.MockPlugin, klass) m.assert_called_once_with(name) @@ -154,20 +164,20 @@ class CliTests(utils.TestCase): val = uuid.uuid4().hex self.env('OS_A_STR', val) - klass = cli.register_argparse_arguments(self.p, [], default=name) + klass = loading.register_argparse_arguments(self.p, [], default=name) opts = self.p.parse_args([]) a = klass.load_from_argparse_arguments(opts) self.assertEqual(val, a['a_str']) def test_deprecated_cli_options(self): - TesterPlugin.register_argparse_arguments(self.p) + TesterLoader().register_argparse_arguments(self.p) val = uuid.uuid4().hex opts = self.p.parse_args(['--os-test-other', val]) self.assertEqual(val, opts.os_test_opt) def test_deprecated_multi_cli_options(self): - TesterPlugin.register_argparse_arguments(self.p) + TesterLoader().register_argparse_arguments(self.p) val1 = uuid.uuid4().hex val2 = uuid.uuid4().hex # argarse rules say that the last specified wins. @@ -179,7 +189,7 @@ class CliTests(utils.TestCase): val = uuid.uuid4().hex with mock.patch.dict('os.environ', {'OS_TEST_OTHER': val}): - TesterPlugin.register_argparse_arguments(self.p) + TesterLoader().register_argparse_arguments(self.p) opts = self.p.parse_args([]) self.assertEqual(val, opts.os_test_opt) @@ -190,7 +200,7 @@ class CliTests(utils.TestCase): with mock.patch.dict('os.environ', {'OS_TEST_OPT': val1, 'OS_TEST_OTHER': val2}): - TesterPlugin.register_argparse_arguments(self.p) + TesterLoader().register_argparse_arguments(self.p) opts = self.p.parse_args([]) self.assertEqual(val1, opts.os_test_opt) diff --git a/keystoneauth1/tests/unit/auth/test_conf.py b/keystoneauth1/tests/unit/loading/test_conf.py similarity index 74% rename from keystoneauth1/tests/unit/auth/test_conf.py rename to keystoneauth1/tests/unit/loading/test_conf.py index 9f49ad5..48a857d 100644 --- a/keystoneauth1/tests/unit/auth/test_conf.py +++ b/keystoneauth1/tests/unit/loading/test_conf.py @@ -17,11 +17,10 @@ from oslo_config import cfg from oslo_config import fixture as config import stevedore -from keystoneauth1 import base -from keystoneauth1 import conf from keystoneauth1 import exceptions -from keystoneauth1.identity import v2 as v2_auth -from keystoneauth1.identity import v3 as v3_auth +from keystoneauth1 import loading +from keystoneauth1.loading._plugins.identity import v2 +from keystoneauth1.loading._plugins.identity import v3 from keystoneauth1.tests.unit.auth import utils @@ -35,7 +34,7 @@ class ConfTests(utils.TestCase): # we need them in place before we can stub them. We will need to run # the register again after we stub the auth section and auth plugin so # it can load the plugin specific options. - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) + loading.register_conf_options(self.conf_fixture.conf, group=self.GROUP) def test_loading_v2(self): section = uuid.uuid4().hex @@ -45,9 +44,9 @@ class ConfTests(utils.TestCase): tenant_id = uuid.uuid4().hex self.conf_fixture.config(auth_section=section, group=self.GROUP) - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) + loading.register_conf_options(self.conf_fixture.conf, group=self.GROUP) - self.conf_fixture.register_opts(v2_auth.Password.get_options(), + self.conf_fixture.register_opts(v2.Password.get_options(), group=section) self.conf_fixture.config(auth_plugin=self.V2PASS, @@ -57,7 +56,7 @@ class ConfTests(utils.TestCase): tenant_id=tenant_id, group=section) - a = conf.load_from_conf_options(self.conf_fixture.conf, self.GROUP) + a = loading.load_from_conf_options(self.conf_fixture.conf, self.GROUP) self.assertEqual(username, a.username) self.assertEqual(password, a.password) @@ -72,9 +71,9 @@ class ConfTests(utils.TestCase): project_domain_name = uuid.uuid4().hex self.conf_fixture.config(auth_section=section, group=self.GROUP) - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) + loading.register_conf_options(self.conf_fixture.conf, group=self.GROUP) - self.conf_fixture.register_opts(v3_auth.Token.get_options(), + self.conf_fixture.register_opts(v3.Token().get_options(), group=section) self.conf_fixture.config(auth_plugin=self.V3TOKEN, @@ -84,7 +83,7 @@ class ConfTests(utils.TestCase): project_domain_name=project_domain_name, group=section) - a = conf.load_from_conf_options(self.conf_fixture.conf, self.GROUP) + a = loading.load_from_conf_options(self.conf_fixture.conf, self.GROUP) self.assertEqual(token, a.auth_methods[0].token) self.assertEqual(trust_id, a.trust_id) @@ -97,15 +96,15 @@ class ConfTests(utils.TestCase): group=self.GROUP) e = self.assertRaises(exceptions.NoMatchingPlugin, - conf.load_from_conf_options, + loading.load_from_conf_options, self.conf_fixture.conf, self.GROUP) self.assertEqual(auth_plugin, e.name) def test_loading_with_no_data(self): - self.assertIsNone(conf.load_from_conf_options(self.conf_fixture.conf, - self.GROUP)) + l = loading.load_from_conf_options(self.conf_fixture.conf, self.GROUP) + self.assertIsNone(l) @mock.patch('stevedore.DriverManager') def test_other_params(self, m): @@ -118,23 +117,22 @@ class ConfTests(utils.TestCase): group=self.GROUP, **self.TEST_VALS) - a = conf.load_from_conf_options(self.conf_fixture.conf, self.GROUP) + a = loading.load_from_conf_options(self.conf_fixture.conf, self.GROUP) self.assertTestVals(a) - m.assert_called_once_with(namespace=base.PLUGIN_NAMESPACE, - name=driver_name, - invoke_on_load=False) + m.assert_called_once_with(namespace=loading.PLUGIN_NAMESPACE, + name=driver_name) @utils.mock_plugin def test_same_section(self, m): self.conf_fixture.register_opts(utils.MockPlugin.get_options(), group=self.GROUP) - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) + loading.register_conf_options(self.conf_fixture.conf, group=self.GROUP) self.conf_fixture.config(auth_plugin=uuid.uuid4().hex, group=self.GROUP, **self.TEST_VALS) - a = conf.load_from_conf_options(self.conf_fixture.conf, self.GROUP) + a = loading.load_from_conf_options(self.conf_fixture.conf, self.GROUP) self.assertTestVals(a) @utils.mock_plugin @@ -142,7 +140,7 @@ class ConfTests(utils.TestCase): section = uuid.uuid4().hex self.conf_fixture.config(auth_section=section, group=self.GROUP) - conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) + loading.register_conf_options(self.conf_fixture.conf, group=self.GROUP) self.conf_fixture.register_opts(utils.MockPlugin.get_options(), group=section) @@ -150,28 +148,27 @@ class ConfTests(utils.TestCase): auth_plugin=uuid.uuid4().hex, **self.TEST_VALS) - a = conf.load_from_conf_options(self.conf_fixture.conf, self.GROUP) + a = loading.load_from_conf_options(self.conf_fixture.conf, self.GROUP) self.assertTestVals(a) def test_plugins_are_all_opts(self): - manager = stevedore.ExtensionManager(base.PLUGIN_NAMESPACE, - invoke_on_load=False, + manager = stevedore.ExtensionManager(loading.PLUGIN_NAMESPACE, propagate_map_exceptions=True) def inner(driver): - for p in driver.plugin.get_options(): + for p in driver.plugin().get_options(): self.assertIsInstance(p, cfg.Opt) manager.map(inner) def test_get_common(self): - opts = conf.get_common_conf_options() + opts = loading.get_common_conf_options() for opt in opts: self.assertIsInstance(opt, cfg.Opt) self.assertEqual(2, len(opts)) def test_get_named(self): - loaded_opts = conf.get_plugin_options('v2password') - plugin_opts = v2_auth.Password.get_options() + loaded_opts = loading.get_plugin_options('v2password') + plugin_opts = v2.Password.get_options() self.assertEqual(plugin_opts, loaded_opts) diff --git a/keystoneauth1/tests/unit/test_session.py b/keystoneauth1/tests/unit/test_session.py index 1ac50e1..8c499ac 100644 --- a/keystoneauth1/tests/unit/test_session.py +++ b/keystoneauth1/tests/unit/test_session.py @@ -24,8 +24,8 @@ import six from testtools import matchers from keystoneauth1 import adapter -from keystoneauth1 import base from keystoneauth1 import exceptions +from keystoneauth1 import plugin from keystoneauth1 import session as client_session from keystoneauth1.tests.unit import utils @@ -320,7 +320,7 @@ class RedirectTests(utils.TestCase): self.assertEqual(r.status_code, s.status_code) -class AuthPlugin(base.BaseAuthPlugin): +class AuthPlugin(plugin.BaseAuthPlugin): """Very simple debug authentication plugin. Takes Parameters such that it can throw exceptions at the right times. @@ -363,7 +363,7 @@ class AuthPlugin(base.BaseAuthPlugin): return self.TEST_PROJECT_ID -class CalledAuthPlugin(base.BaseAuthPlugin): +class CalledAuthPlugin(plugin.BaseAuthPlugin): ENDPOINT = 'http://fakeendpoint/' diff --git a/keystoneauth1/token_endpoint.py b/keystoneauth1/token_endpoint.py index 642c26d..4f049f9 100644 --- a/keystoneauth1/token_endpoint.py +++ b/keystoneauth1/token_endpoint.py @@ -10,12 +10,10 @@ # License for the specific language governing permissions and limitations # under the License. -from oslo_config import cfg - -from keystoneauth1 import base +from keystoneauth1 import plugin -class Token(base.BaseAuthPlugin): +class Token(plugin.BaseAuthPlugin): """A provider that will always use the given token and endpoint. This is really only useful for testing and in certain CLI cases where you @@ -38,17 +36,3 @@ class Token(base.BaseAuthPlugin): parameters passed to the plugin. """ return self.endpoint - - @classmethod - def get_options(cls): - options = super(Token, cls).get_options() - - options.extend([ - cfg.StrOpt('endpoint', - help='The endpoint that will always be used'), - cfg.StrOpt('token', - secret=True, - help='The token that will always be used'), - ]) - - return options diff --git a/setup.cfg b/setup.cfg index 92869cc..cebff3b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -25,14 +25,13 @@ packages = [entry_points] -keystoneauth1.auth.plugin = - password = keystoneauth1.identity.generic:Password - token = keystoneauth1.identity.generic:Token - v2password = keystoneauth1.identity.v2:Password - v2token = keystoneauth1.identity.v2:Token - v3password = keystoneauth1.identity.v3:Password - v3token = keystoneauth1.identity.v3:Token - k2k = keystoneauth1.identity.v3:Keystone2Keystone +keystoneauth1.plugin = + password = keystoneauth1.loading._plugins.identity.generic:Password + token = keystoneauth1.loading._plugins.identity.generic:Token + v2password = keystoneauth1.loading._plugins.identity.v2:Password + v2token = keystoneauth1.loading._plugins.identity.v2:Token + v3password = keystoneauth1.loading._plugins.identity.v3:Password + v3token = keystoneauth1.loading._plugins.identity.v3:Token [build_sphinx] source-dir = doc/source