Split plugin loading

One of the issues raised with keystoneclient plugins is the way that
loading of a plugin is mixed in with the definition of a plugin. Amongst
other things this really meant that there was only one way to utilize
each plugin class, to do another plugin that utilized an existing one
you would have to define a new class and proxy to it.

In this patch we split the concerns. There is a whole new section called
loading that is solely responsible for ways to load the auth plugin from
CLI or from argparse and other future methods.

This new section will likely be split into its own repository.

Change-Id: I8387b86fc0e3a8403f9806440196e8723eaf1ee4
This commit is contained in:
Jamie Lennox 2015-08-03 09:32:56 +10:00
parent a08ca8f494
commit efcadd6937
36 changed files with 656 additions and 544 deletions

View File

@ -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',
]

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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."""

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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',
]

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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()

View File

@ -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

View File

@ -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)

View File

@ -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))

View File

@ -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',

View File

@ -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',

View File

@ -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))

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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/'

View File

@ -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

View File

@ -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