Remove support for non-keystone auth systems
The support for non-keystone auth systems and plugins
was deprecated with 1f11840dd8
back in the 3.1.0 release in mitaka.
Now that we're working on shoring up the support for
keystone auth sessions in the client and eventually moving
to remove support for the non-session HTTPClient, we should
also remove the support to load non-keystone auth plugins.
The whole concept of non-keystone auth systems/plugins is
a legacy artifact and is a barrier to interoperability which
is a goal of nova and OpenStack in general.
Change-Id: Ia649db257c416ca054977812ecb3f1a8044fa584
This commit is contained in:
parent
f5647e35c3
commit
daa9bdc823
@ -1,150 +0,0 @@
|
|||||||
# Copyright 2013 OpenStack Foundation
|
|
||||||
# Copyright 2013 Spanish National Research Council.
|
|
||||||
# All Rights Reserved.
|
|
||||||
#
|
|
||||||
# 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 logging
|
|
||||||
|
|
||||||
import pkg_resources
|
|
||||||
import six
|
|
||||||
|
|
||||||
from novaclient import exceptions
|
|
||||||
from novaclient import utils
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
_discovered_plugins = {}
|
|
||||||
|
|
||||||
|
|
||||||
def discover_auth_systems():
|
|
||||||
"""Discover the available auth-systems.
|
|
||||||
|
|
||||||
This won't take into account the old style auth-systems.
|
|
||||||
"""
|
|
||||||
ep_name = 'openstack.client.auth_plugin'
|
|
||||||
for ep in pkg_resources.iter_entry_points(ep_name):
|
|
||||||
try:
|
|
||||||
# FIXME(dhellmann): It would be better to use stevedore
|
|
||||||
# here, since it abstracts this difference in behavior
|
|
||||||
# between versions of setuptools, but this seemed like a
|
|
||||||
# more expedient fix.
|
|
||||||
if hasattr(ep, 'resolve') and hasattr(ep, 'require'):
|
|
||||||
auth_plugin = ep.resolve()
|
|
||||||
else:
|
|
||||||
auth_plugin = ep.load(require=False)
|
|
||||||
except (ImportError, pkg_resources.UnknownExtra, AttributeError) as e:
|
|
||||||
logger.debug("ERROR: Cannot load auth plugin %s" % ep.name)
|
|
||||||
logger.debug(e, exc_info=1)
|
|
||||||
else:
|
|
||||||
_discovered_plugins[ep.name] = auth_plugin
|
|
||||||
|
|
||||||
|
|
||||||
def load_auth_system_opts(parser):
|
|
||||||
"""Load options needed by the available auth-systems into a parser.
|
|
||||||
|
|
||||||
This function will try to populate the parser with options from the
|
|
||||||
available plugins.
|
|
||||||
"""
|
|
||||||
for name, auth_plugin in six.iteritems(_discovered_plugins):
|
|
||||||
add_opts_fn = getattr(auth_plugin, "add_opts", None)
|
|
||||||
if add_opts_fn:
|
|
||||||
group = parser.add_argument_group("Auth-system '%s' options" %
|
|
||||||
name)
|
|
||||||
add_opts_fn(group)
|
|
||||||
|
|
||||||
|
|
||||||
def load_plugin(auth_system):
|
|
||||||
if auth_system in _discovered_plugins:
|
|
||||||
return _discovered_plugins[auth_system]()
|
|
||||||
|
|
||||||
# NOTE(aloga): If we arrive here, the plugin will be an old-style one,
|
|
||||||
# so we have to create a fake AuthPlugin for it.
|
|
||||||
return DeprecatedAuthPlugin(auth_system)
|
|
||||||
|
|
||||||
|
|
||||||
class BaseAuthPlugin(object):
|
|
||||||
"""Base class for authentication plugins.
|
|
||||||
|
|
||||||
An authentication plugin needs to override at least the authenticate
|
|
||||||
method to be a valid plugin.
|
|
||||||
"""
|
|
||||||
def __init__(self):
|
|
||||||
self.opts = {}
|
|
||||||
|
|
||||||
def get_auth_url(self):
|
|
||||||
"""Return the auth url for the plugin (if any)."""
|
|
||||||
return None
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def add_opts(parser):
|
|
||||||
"""Populate and return the parser with the options for this plugin.
|
|
||||||
|
|
||||||
If the plugin does not need any options, it should return the same
|
|
||||||
parser untouched.
|
|
||||||
"""
|
|
||||||
return parser
|
|
||||||
|
|
||||||
def parse_opts(self, args):
|
|
||||||
"""Parse the actual auth-system options if any.
|
|
||||||
|
|
||||||
This method is expected to populate the attribute self.opts with a
|
|
||||||
dict containing the options and values needed to make authentication.
|
|
||||||
If the dict is empty, the client should assume that it needs the same
|
|
||||||
options as the 'keystone' auth system (i.e. os_username and
|
|
||||||
os_password).
|
|
||||||
|
|
||||||
Returns the self.opts dict.
|
|
||||||
"""
|
|
||||||
return self.opts
|
|
||||||
|
|
||||||
def authenticate(self, cls, auth_url):
|
|
||||||
"""Authenticate using plugin defined method."""
|
|
||||||
raise exceptions.AuthSystemNotFound(self.auth_system)
|
|
||||||
|
|
||||||
|
|
||||||
class DeprecatedAuthPlugin(object):
|
|
||||||
"""Class to mimic the AuthPlugin class for deprecated auth systems.
|
|
||||||
|
|
||||||
Old auth systems only define two entry points: openstack.client.auth_url
|
|
||||||
and openstack.client.authenticate. This class will load those entry points
|
|
||||||
into a class similar to a valid AuthPlugin.
|
|
||||||
"""
|
|
||||||
def __init__(self, auth_system):
|
|
||||||
self.auth_system = auth_system
|
|
||||||
|
|
||||||
def authenticate(cls, auth_url):
|
|
||||||
raise exceptions.AuthSystemNotFound(self.auth_system)
|
|
||||||
|
|
||||||
self.opts = {}
|
|
||||||
|
|
||||||
self.get_auth_url = lambda: None
|
|
||||||
self.authenticate = authenticate
|
|
||||||
|
|
||||||
self._load_endpoints()
|
|
||||||
|
|
||||||
def _load_endpoints(self):
|
|
||||||
ep_name = 'openstack.client.auth_url'
|
|
||||||
fn = utils.load_entry_point(ep_name, name=self.auth_system)
|
|
||||||
if fn:
|
|
||||||
self.get_auth_url = fn
|
|
||||||
|
|
||||||
ep_name = 'openstack.client.authenticate'
|
|
||||||
fn = utils.load_entry_point(ep_name, name=self.auth_system)
|
|
||||||
if fn:
|
|
||||||
self.authenticate = fn
|
|
||||||
|
|
||||||
def parse_opts(self, args):
|
|
||||||
return self.opts
|
|
@ -156,8 +156,7 @@ class HTTPClient(object):
|
|||||||
service_name=None, volume_service_name=None,
|
service_name=None, volume_service_name=None,
|
||||||
timings=False, bypass_url=None,
|
timings=False, bypass_url=None,
|
||||||
os_cache=False, no_cache=True,
|
os_cache=False, no_cache=True,
|
||||||
http_log_debug=False, auth_system='keystone',
|
http_log_debug=False, auth_token=None,
|
||||||
auth_plugin=None, auth_token=None,
|
|
||||||
cacert=None, tenant_id=None, user_id=None,
|
cacert=None, tenant_id=None, user_id=None,
|
||||||
connection_pool=False, api_version=None,
|
connection_pool=False, api_version=None,
|
||||||
logger=None):
|
logger=None):
|
||||||
@ -177,13 +176,6 @@ class HTTPClient(object):
|
|||||||
# been proven invalid
|
# been proven invalid
|
||||||
self.password_func = None
|
self.password_func = None
|
||||||
|
|
||||||
if auth_system and auth_system != 'keystone' and not auth_plugin:
|
|
||||||
raise exceptions.AuthSystemNotFound(auth_system)
|
|
||||||
|
|
||||||
if not auth_url and auth_system and auth_system != 'keystone':
|
|
||||||
auth_url = auth_plugin.get_auth_url()
|
|
||||||
if not auth_url:
|
|
||||||
raise exceptions.EndpointNotFound()
|
|
||||||
self.auth_url = auth_url.rstrip('/') if auth_url else auth_url
|
self.auth_url = auth_url.rstrip('/') if auth_url else auth_url
|
||||||
self.version = 'v1.1'
|
self.version = 'v1.1'
|
||||||
self.region_name = region_name
|
self.region_name = region_name
|
||||||
@ -217,8 +209,6 @@ class HTTPClient(object):
|
|||||||
else:
|
else:
|
||||||
self.verify_cert = True
|
self.verify_cert = True
|
||||||
|
|
||||||
self.auth_system = auth_system
|
|
||||||
self.auth_plugin = auth_plugin
|
|
||||||
self._session = None
|
self._session = None
|
||||||
self._current_url = None
|
self._current_url = None
|
||||||
self._logger = logger or logging.getLogger(__name__)
|
self._logger = logger or logging.getLogger(__name__)
|
||||||
@ -589,10 +579,7 @@ class HTTPClient(object):
|
|||||||
auth_url = self.auth_url
|
auth_url = self.auth_url
|
||||||
if self.version == "v2.0": # FIXME(chris): This should be better.
|
if self.version == "v2.0": # FIXME(chris): This should be better.
|
||||||
while auth_url:
|
while auth_url:
|
||||||
if not self.auth_system or self.auth_system == 'keystone':
|
|
||||||
auth_url = self._v2_auth(auth_url)
|
auth_url = self._v2_auth(auth_url)
|
||||||
else:
|
|
||||||
auth_url = self._plugin_auth(auth_url)
|
|
||||||
|
|
||||||
# Are we acting on behalf of another user via an
|
# Are we acting on behalf of another user via an
|
||||||
# existing token? If so, our actual endpoints may
|
# existing token? If so, our actual endpoints may
|
||||||
@ -659,9 +646,6 @@ class HTTPClient(object):
|
|||||||
else:
|
else:
|
||||||
raise exceptions.from_response(resp, body, url)
|
raise exceptions.from_response(resp, body, url)
|
||||||
|
|
||||||
def _plugin_auth(self, auth_url):
|
|
||||||
return self.auth_plugin.authenticate(self, auth_url)
|
|
||||||
|
|
||||||
def _v2_auth(self, url):
|
def _v2_auth(self, url):
|
||||||
"""Authenticate against a v2.0 auth service."""
|
"""Authenticate against a v2.0 auth service."""
|
||||||
if self.auth_token:
|
if self.auth_token:
|
||||||
@ -707,7 +691,6 @@ def _construct_http_client(username=None, password=None, project_id=None,
|
|||||||
service_name=None, volume_service_name=None,
|
service_name=None, volume_service_name=None,
|
||||||
timings=False, bypass_url=None, os_cache=False,
|
timings=False, bypass_url=None, os_cache=False,
|
||||||
no_cache=True, http_log_debug=False,
|
no_cache=True, http_log_debug=False,
|
||||||
auth_system='keystone', auth_plugin=None,
|
|
||||||
auth_token=None, cacert=None, tenant_id=None,
|
auth_token=None, cacert=None, tenant_id=None,
|
||||||
user_id=None, connection_pool=False, session=None,
|
user_id=None, connection_pool=False, session=None,
|
||||||
auth=None, user_agent='python-novaclient',
|
auth=None, user_agent='python-novaclient',
|
||||||
@ -738,8 +721,6 @@ def _construct_http_client(username=None, password=None, project_id=None,
|
|||||||
auth_token=auth_token,
|
auth_token=auth_token,
|
||||||
insecure=insecure,
|
insecure=insecure,
|
||||||
timeout=timeout,
|
timeout=timeout,
|
||||||
auth_system=auth_system,
|
|
||||||
auth_plugin=auth_plugin,
|
|
||||||
proxy_token=proxy_token,
|
proxy_token=proxy_token,
|
||||||
proxy_tenant_id=proxy_tenant_id,
|
proxy_tenant_id=proxy_tenant_id,
|
||||||
region_name=region_name,
|
region_name=region_name,
|
||||||
|
@ -54,15 +54,6 @@ class NoUniqueMatch(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class AuthSystemNotFound(Exception):
|
|
||||||
"""When the user specify a AuthSystem but not installed."""
|
|
||||||
def __init__(self, auth_system):
|
|
||||||
self.auth_system = auth_system
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "AuthSystemNotFound: %s" % repr(self.auth_system)
|
|
||||||
|
|
||||||
|
|
||||||
class NoTokenLookupException(Exception):
|
class NoTokenLookupException(Exception):
|
||||||
"""This form of authentication does not support looking up
|
"""This form of authentication does not support looking up
|
||||||
endpoints from an existing token.
|
endpoints from an existing token.
|
||||||
|
@ -23,7 +23,6 @@ import argparse
|
|||||||
import getpass
|
import getpass
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
|
||||||
|
|
||||||
from keystoneauth1 import loading
|
from keystoneauth1 import loading
|
||||||
from oslo_utils import encodeutils
|
from oslo_utils import encodeutils
|
||||||
@ -41,7 +40,6 @@ except ImportError:
|
|||||||
|
|
||||||
import novaclient
|
import novaclient
|
||||||
from novaclient import api_versions
|
from novaclient import api_versions
|
||||||
import novaclient.auth_plugin
|
|
||||||
from novaclient import client
|
from novaclient import client
|
||||||
from novaclient import exceptions as exc
|
from novaclient import exceptions as exc
|
||||||
import novaclient.extension
|
import novaclient.extension
|
||||||
@ -455,12 +453,6 @@ class OpenStackComputeShell(object):
|
|||||||
default=utils.env('OS_REGION_NAME', 'NOVA_REGION_NAME'),
|
default=utils.env('OS_REGION_NAME', 'NOVA_REGION_NAME'),
|
||||||
help=_('Defaults to env[OS_REGION_NAME].'))
|
help=_('Defaults to env[OS_REGION_NAME].'))
|
||||||
|
|
||||||
parser.add_argument(
|
|
||||||
'--os-auth-system',
|
|
||||||
metavar='<auth-system>',
|
|
||||||
default=utils.env('OS_AUTH_SYSTEM'),
|
|
||||||
help=argparse.SUPPRESS)
|
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--service-type',
|
'--service-type',
|
||||||
metavar='<service-type>',
|
metavar='<service-type>',
|
||||||
@ -509,9 +501,6 @@ class OpenStackComputeShell(object):
|
|||||||
help=_("Use this API endpoint instead of the Service Catalog. "
|
help=_("Use this API endpoint instead of the Service Catalog. "
|
||||||
"Defaults to env[NOVACLIENT_BYPASS_URL]."))
|
"Defaults to env[NOVACLIENT_BYPASS_URL]."))
|
||||||
|
|
||||||
# The auth-system-plugins might require some extra options
|
|
||||||
novaclient.auth_plugin.load_auth_system_opts(parser)
|
|
||||||
|
|
||||||
self._append_global_identity_args(parser, argv)
|
self._append_global_identity_args(parser, argv)
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
@ -639,9 +628,6 @@ class OpenStackComputeShell(object):
|
|||||||
skip_auth = do_help or (
|
skip_auth = do_help or (
|
||||||
'bash-completion' in argv)
|
'bash-completion' in argv)
|
||||||
|
|
||||||
# Discover available auth plugins
|
|
||||||
novaclient.auth_plugin.discover_auth_systems()
|
|
||||||
|
|
||||||
if not args.os_compute_api_version:
|
if not args.os_compute_api_version:
|
||||||
api_version = api_versions.get_api_version(
|
api_version = api_versions.get_api_version(
|
||||||
DEFAULT_MAJOR_OS_COMPUTE_API_VERSION)
|
DEFAULT_MAJOR_OS_COMPUTE_API_VERSION)
|
||||||
@ -658,7 +644,6 @@ class OpenStackComputeShell(object):
|
|||||||
args, 'os_project_id', getattr(args, 'os_tenant_id', None))
|
args, 'os_project_id', getattr(args, 'os_tenant_id', None))
|
||||||
os_auth_url = args.os_auth_url
|
os_auth_url = args.os_auth_url
|
||||||
os_region_name = args.os_region_name
|
os_region_name = args.os_region_name
|
||||||
os_auth_system = args.os_auth_system
|
|
||||||
|
|
||||||
if "v2.0" not in os_auth_url:
|
if "v2.0" not in os_auth_url:
|
||||||
# NOTE(andreykurilin): assume that keystone V3 is used and try to
|
# NOTE(andreykurilin): assume that keystone V3 is used and try to
|
||||||
@ -691,15 +676,6 @@ class OpenStackComputeShell(object):
|
|||||||
auth_token = getattr(args, 'os_token', None)
|
auth_token = getattr(args, 'os_token', None)
|
||||||
management_url = bypass_url if bypass_url else None
|
management_url = bypass_url if bypass_url else None
|
||||||
|
|
||||||
if os_auth_system and os_auth_system != "keystone":
|
|
||||||
warnings.warn(_(
|
|
||||||
'novaclient auth plugins that are not keystone are deprecated.'
|
|
||||||
' Auth plugins should now be done as plugins to keystoneauth'
|
|
||||||
' and selected with --os-auth-type or OS_AUTH_TYPE'))
|
|
||||||
auth_plugin = novaclient.auth_plugin.load_plugin(os_auth_system)
|
|
||||||
else:
|
|
||||||
auth_plugin = None
|
|
||||||
|
|
||||||
if not endpoint_type:
|
if not endpoint_type:
|
||||||
endpoint_type = DEFAULT_NOVA_ENDPOINT_TYPE
|
endpoint_type = DEFAULT_NOVA_ENDPOINT_TYPE
|
||||||
|
|
||||||
@ -717,20 +693,15 @@ class OpenStackComputeShell(object):
|
|||||||
# Expired tokens are handled by client.py:_cs_request
|
# Expired tokens are handled by client.py:_cs_request
|
||||||
must_auth = not (auth_token and management_url)
|
must_auth = not (auth_token and management_url)
|
||||||
|
|
||||||
# Do not use Keystone session for cases with no session support. The
|
# Do not use Keystone session for cases with no session support.
|
||||||
# presence of auth_plugin means os_auth_system is present and is not
|
|
||||||
# keystone.
|
|
||||||
use_session = True
|
use_session = True
|
||||||
if auth_plugin or bypass_url or os_cache or volume_service_name:
|
if bypass_url or os_cache or volume_service_name:
|
||||||
use_session = False
|
use_session = False
|
||||||
|
|
||||||
# FIXME(usrleon): Here should be restrict for project id same as
|
# FIXME(usrleon): Here should be restrict for project id same as
|
||||||
# for os_username or os_password but for compatibility it is not.
|
# for os_username or os_password but for compatibility it is not.
|
||||||
if must_auth and not skip_auth:
|
if must_auth and not skip_auth:
|
||||||
if auth_plugin:
|
|
||||||
auth_plugin.parse_opts(args)
|
|
||||||
|
|
||||||
if not auth_plugin or not auth_plugin.opts:
|
|
||||||
if not os_username and not os_user_id:
|
if not os_username and not os_user_id:
|
||||||
raise exc.CommandError(
|
raise exc.CommandError(
|
||||||
_("You must provide a username "
|
_("You must provide a username "
|
||||||
@ -745,17 +716,10 @@ class OpenStackComputeShell(object):
|
|||||||
" use os-project and os-tenant"
|
" use os-project and os-tenant"
|
||||||
" interchangeably."))
|
" interchangeably."))
|
||||||
|
|
||||||
if not os_auth_url:
|
|
||||||
if os_auth_system and os_auth_system != 'keystone':
|
|
||||||
os_auth_url = auth_plugin.get_auth_url()
|
|
||||||
|
|
||||||
if not os_auth_url:
|
if not os_auth_url:
|
||||||
raise exc.CommandError(
|
raise exc.CommandError(
|
||||||
_("You must provide an auth url "
|
_("You must provide an auth url "
|
||||||
"via either --os-auth-url or env[OS_AUTH_URL] "
|
"via either --os-auth-url or env[OS_AUTH_URL]."))
|
||||||
"or specify an auth_system which defines a "
|
|
||||||
"default url with --os-auth-system "
|
|
||||||
"or env[OS_AUTH_SYSTEM]"))
|
|
||||||
|
|
||||||
if use_session:
|
if use_session:
|
||||||
# Not using Nova auth plugin, so use keystone
|
# Not using Nova auth plugin, so use keystone
|
||||||
@ -792,8 +756,7 @@ class OpenStackComputeShell(object):
|
|||||||
auth_url=os_auth_url, insecure=insecure,
|
auth_url=os_auth_url, insecure=insecure,
|
||||||
region_name=os_region_name, endpoint_type=endpoint_type,
|
region_name=os_region_name, endpoint_type=endpoint_type,
|
||||||
extensions=self.extensions, service_type=service_type,
|
extensions=self.extensions, service_type=service_type,
|
||||||
service_name=service_name, auth_system=os_auth_system,
|
service_name=service_name, auth_token=auth_token,
|
||||||
auth_plugin=auth_plugin, auth_token=auth_token,
|
|
||||||
volume_service_name=volume_service_name,
|
volume_service_name=volume_service_name,
|
||||||
timings=args.timings, bypass_url=bypass_url,
|
timings=args.timings, bypass_url=bypass_url,
|
||||||
os_cache=os_cache, http_log_debug=args.debug,
|
os_cache=os_cache, http_log_debug=args.debug,
|
||||||
@ -857,8 +820,7 @@ class OpenStackComputeShell(object):
|
|||||||
auth_url=os_auth_url, insecure=insecure,
|
auth_url=os_auth_url, insecure=insecure,
|
||||||
region_name=os_region_name, endpoint_type=endpoint_type,
|
region_name=os_region_name, endpoint_type=endpoint_type,
|
||||||
extensions=self.extensions, service_type=service_type,
|
extensions=self.extensions, service_type=service_type,
|
||||||
service_name=service_name, auth_system=os_auth_system,
|
service_name=service_name, auth_token=auth_token,
|
||||||
auth_plugin=auth_plugin, auth_token=auth_token,
|
|
||||||
volume_service_name=volume_service_name,
|
volume_service_name=volume_service_name,
|
||||||
timings=args.timings, bypass_url=bypass_url,
|
timings=args.timings, bypass_url=bypass_url,
|
||||||
os_cache=os_cache, http_log_debug=args.debug,
|
os_cache=os_cache, http_log_debug=args.debug,
|
||||||
@ -870,11 +832,6 @@ class OpenStackComputeShell(object):
|
|||||||
if must_auth:
|
if must_auth:
|
||||||
helper = SecretsHelper(args, self.cs.client)
|
helper = SecretsHelper(args, self.cs.client)
|
||||||
self.cs.client.keyring_saver = helper
|
self.cs.client.keyring_saver = helper
|
||||||
if (auth_plugin and auth_plugin.opts and
|
|
||||||
"os_password" not in auth_plugin.opts):
|
|
||||||
use_pw = False
|
|
||||||
else:
|
|
||||||
use_pw = True
|
|
||||||
|
|
||||||
tenant_id = helper.tenant_id
|
tenant_id = helper.tenant_id
|
||||||
# Allow commandline to override cache
|
# Allow commandline to override cache
|
||||||
@ -887,7 +844,7 @@ class OpenStackComputeShell(object):
|
|||||||
self.cs.client.auth_token = auth_token
|
self.cs.client.auth_token = auth_token
|
||||||
self.cs.client.management_url = management_url
|
self.cs.client.management_url = management_url
|
||||||
self.cs.client.password_func = lambda: helper.password
|
self.cs.client.password_func = lambda: helper.password
|
||||||
elif use_pw:
|
else:
|
||||||
# We're missing something, so auth with user/pass and save
|
# We're missing something, so auth with user/pass and save
|
||||||
# the result in our helper.
|
# the result in our helper.
|
||||||
self.cs.client.password = helper.password
|
self.cs.client.password = helper.password
|
||||||
|
@ -1,358 +0,0 @@
|
|||||||
# Copyright 2012 OpenStack Foundation
|
|
||||||
# All Rights Reserved.
|
|
||||||
#
|
|
||||||
# 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 argparse
|
|
||||||
|
|
||||||
from keystoneauth1 import fixture
|
|
||||||
import mock
|
|
||||||
import pkg_resources
|
|
||||||
import requests
|
|
||||||
|
|
||||||
try:
|
|
||||||
import json
|
|
||||||
except ImportError:
|
|
||||||
import simplejson as json
|
|
||||||
|
|
||||||
from novaclient import auth_plugin
|
|
||||||
from novaclient import client
|
|
||||||
from novaclient import exceptions
|
|
||||||
from novaclient.tests.unit import utils
|
|
||||||
|
|
||||||
|
|
||||||
def mock_http_request(resp=None):
|
|
||||||
"""Mock an HTTP Request."""
|
|
||||||
if not resp:
|
|
||||||
resp = fixture.V2Token()
|
|
||||||
resp.set_scope()
|
|
||||||
s = resp.add_service('compute')
|
|
||||||
s.add_endpoint("http://localhost:8774/v1.1", region='RegionOne')
|
|
||||||
|
|
||||||
auth_response = utils.TestResponse({
|
|
||||||
"status_code": 200,
|
|
||||||
"text": json.dumps(resp),
|
|
||||||
})
|
|
||||||
return mock.Mock(return_value=(auth_response))
|
|
||||||
|
|
||||||
|
|
||||||
def requested_headers(cs):
|
|
||||||
"""Return requested passed headers."""
|
|
||||||
return {
|
|
||||||
'User-Agent': cs.client.USER_AGENT,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Accept': 'application/json',
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class DeprecatedAuthPluginTest(utils.TestCase):
|
|
||||||
def test_auth_system_success(self):
|
|
||||||
class MockEntrypoint(pkg_resources.EntryPoint):
|
|
||||||
def load(self, require=False):
|
|
||||||
return self.authenticate
|
|
||||||
|
|
||||||
def resolve(self):
|
|
||||||
return self.authenticate
|
|
||||||
|
|
||||||
def authenticate(self, cls, auth_url):
|
|
||||||
cls._authenticate(auth_url, {"fake": "me"})
|
|
||||||
|
|
||||||
def mock_iter_entry_points(_type, name):
|
|
||||||
if _type == 'openstack.client.authenticate':
|
|
||||||
return [MockEntrypoint("fake", "fake", ["fake"])]
|
|
||||||
else:
|
|
||||||
return []
|
|
||||||
|
|
||||||
mock_request = mock_http_request()
|
|
||||||
|
|
||||||
@mock.patch.object(pkg_resources, "iter_entry_points",
|
|
||||||
mock_iter_entry_points)
|
|
||||||
@mock.patch.object(requests, "request", mock_request)
|
|
||||||
def test_auth_call():
|
|
||||||
plugin = auth_plugin.DeprecatedAuthPlugin("fake")
|
|
||||||
cs = client.Client("2", "username", "password", "project_id",
|
|
||||||
utils.AUTH_URL_V2, auth_system="fake",
|
|
||||||
auth_plugin=plugin)
|
|
||||||
cs.client.authenticate()
|
|
||||||
|
|
||||||
headers = requested_headers(cs)
|
|
||||||
token_url = cs.client.auth_url + "/tokens"
|
|
||||||
|
|
||||||
mock_request.assert_called_with(
|
|
||||||
"POST",
|
|
||||||
token_url,
|
|
||||||
headers=headers,
|
|
||||||
data='{"fake": "me"}',
|
|
||||||
allow_redirects=True,
|
|
||||||
**self.TEST_REQUEST_BASE)
|
|
||||||
|
|
||||||
test_auth_call()
|
|
||||||
|
|
||||||
def test_auth_system_not_exists(self):
|
|
||||||
def mock_iter_entry_points(_t, name=None):
|
|
||||||
return [pkg_resources.EntryPoint("fake", "fake", ["fake"])]
|
|
||||||
|
|
||||||
mock_request = mock_http_request()
|
|
||||||
|
|
||||||
@mock.patch.object(pkg_resources, "iter_entry_points",
|
|
||||||
mock_iter_entry_points)
|
|
||||||
@mock.patch.object(requests, "request", mock_request)
|
|
||||||
def test_auth_call():
|
|
||||||
auth_plugin.discover_auth_systems()
|
|
||||||
plugin = auth_plugin.DeprecatedAuthPlugin("notexists")
|
|
||||||
cs = client.Client("2", "username", "password", "project_id",
|
|
||||||
utils.AUTH_URL_V2, auth_system="notexists",
|
|
||||||
auth_plugin=plugin)
|
|
||||||
self.assertRaises(exceptions.AuthSystemNotFound,
|
|
||||||
cs.client.authenticate)
|
|
||||||
|
|
||||||
test_auth_call()
|
|
||||||
|
|
||||||
def test_auth_system_defining_auth_url(self):
|
|
||||||
class MockAuthUrlEntrypoint(pkg_resources.EntryPoint):
|
|
||||||
def load(self, require=False):
|
|
||||||
return self.auth_url
|
|
||||||
|
|
||||||
def resolve(self):
|
|
||||||
return self.auth_url
|
|
||||||
|
|
||||||
def auth_url(self):
|
|
||||||
return "http://faked/v2.0"
|
|
||||||
|
|
||||||
class MockAuthenticateEntrypoint(pkg_resources.EntryPoint):
|
|
||||||
def load(self, require=False):
|
|
||||||
return self.authenticate
|
|
||||||
|
|
||||||
def resolve(self):
|
|
||||||
return self.authenticate
|
|
||||||
|
|
||||||
def authenticate(self, cls, auth_url):
|
|
||||||
cls._authenticate(auth_url, {"fake": "me"})
|
|
||||||
|
|
||||||
def mock_iter_entry_points(_type, name):
|
|
||||||
if _type == 'openstack.client.auth_url':
|
|
||||||
return [MockAuthUrlEntrypoint("fakewithauthurl",
|
|
||||||
"fakewithauthurl",
|
|
||||||
["auth_url"])]
|
|
||||||
elif _type == 'openstack.client.authenticate':
|
|
||||||
return [MockAuthenticateEntrypoint("fakewithauthurl",
|
|
||||||
"fakewithauthurl",
|
|
||||||
["authenticate"])]
|
|
||||||
else:
|
|
||||||
return []
|
|
||||||
|
|
||||||
mock_request = mock_http_request()
|
|
||||||
|
|
||||||
@mock.patch.object(pkg_resources, "iter_entry_points",
|
|
||||||
mock_iter_entry_points)
|
|
||||||
@mock.patch.object(requests, "request", mock_request)
|
|
||||||
def test_auth_call():
|
|
||||||
plugin = auth_plugin.DeprecatedAuthPlugin("fakewithauthurl")
|
|
||||||
cs = client.Client("2", "username", "password", "project_id",
|
|
||||||
auth_system="fakewithauthurl",
|
|
||||||
auth_plugin=plugin)
|
|
||||||
cs.client.authenticate()
|
|
||||||
self.assertEqual("http://faked/v2.0", cs.client.auth_url)
|
|
||||||
|
|
||||||
test_auth_call()
|
|
||||||
|
|
||||||
@mock.patch.object(pkg_resources, "iter_entry_points")
|
|
||||||
def test_client_raises_exc_without_auth_url(self, mock_iter_entry_points):
|
|
||||||
class MockAuthUrlEntrypoint(pkg_resources.EntryPoint):
|
|
||||||
def load(self, require=False):
|
|
||||||
return self.auth_url
|
|
||||||
|
|
||||||
def resolve(self):
|
|
||||||
return self.auth_url
|
|
||||||
|
|
||||||
def auth_url(self):
|
|
||||||
return None
|
|
||||||
|
|
||||||
mock_iter_entry_points.side_effect = lambda _t, name: [
|
|
||||||
MockAuthUrlEntrypoint("fakewithauthurl",
|
|
||||||
"fakewithauthurl",
|
|
||||||
["auth_url"])]
|
|
||||||
|
|
||||||
plugin = auth_plugin.DeprecatedAuthPlugin("fakewithauthurl")
|
|
||||||
self.assertRaises(
|
|
||||||
exceptions.EndpointNotFound,
|
|
||||||
client.Client, "2", "username", "password", "project_id",
|
|
||||||
auth_system="fakewithauthurl", auth_plugin=plugin)
|
|
||||||
|
|
||||||
|
|
||||||
class AuthPluginTest(utils.TestCase):
|
|
||||||
@mock.patch.object(requests, "request")
|
|
||||||
@mock.patch.object(pkg_resources, "iter_entry_points")
|
|
||||||
def test_auth_system_success(self, mock_iter_entry_points, mock_request):
|
|
||||||
"""Test that we can authenticate using the auth system."""
|
|
||||||
class MockEntrypoint(pkg_resources.EntryPoint):
|
|
||||||
def load(self, require=False):
|
|
||||||
return FakePlugin
|
|
||||||
|
|
||||||
def resolve(self):
|
|
||||||
return FakePlugin
|
|
||||||
|
|
||||||
class FakePlugin(auth_plugin.BaseAuthPlugin):
|
|
||||||
def authenticate(self, cls, auth_url):
|
|
||||||
cls._authenticate(auth_url, {"fake": "me"})
|
|
||||||
|
|
||||||
mock_iter_entry_points.side_effect = lambda _t, name=None: [
|
|
||||||
MockEntrypoint("fake", "fake", ["FakePlugin"])]
|
|
||||||
|
|
||||||
mock_request.side_effect = mock_http_request()
|
|
||||||
|
|
||||||
auth_plugin.discover_auth_systems()
|
|
||||||
plugin = auth_plugin.load_plugin("fake")
|
|
||||||
cs = client.Client("2", "username", "password", "project_id",
|
|
||||||
utils.AUTH_URL_V2, auth_system="fake",
|
|
||||||
auth_plugin=plugin)
|
|
||||||
cs.client.authenticate()
|
|
||||||
|
|
||||||
headers = requested_headers(cs)
|
|
||||||
token_url = cs.client.auth_url + "/tokens"
|
|
||||||
|
|
||||||
mock_request.assert_called_with(
|
|
||||||
"POST",
|
|
||||||
token_url,
|
|
||||||
headers=headers,
|
|
||||||
data='{"fake": "me"}',
|
|
||||||
allow_redirects=True,
|
|
||||||
**self.TEST_REQUEST_BASE)
|
|
||||||
|
|
||||||
@mock.patch.object(pkg_resources, "iter_entry_points")
|
|
||||||
def test_discover_auth_system_options(self, mock_iter_entry_points):
|
|
||||||
"""Test that we can load the auth system options."""
|
|
||||||
class FakePlugin(auth_plugin.BaseAuthPlugin):
|
|
||||||
@staticmethod
|
|
||||||
def add_opts(parser):
|
|
||||||
parser.add_argument('--auth_system_opt',
|
|
||||||
default=False,
|
|
||||||
action='store_true',
|
|
||||||
help="Fake option")
|
|
||||||
return parser
|
|
||||||
|
|
||||||
class MockEntrypoint(pkg_resources.EntryPoint):
|
|
||||||
def load(self, require=False):
|
|
||||||
return FakePlugin
|
|
||||||
|
|
||||||
def resolve(self):
|
|
||||||
return FakePlugin
|
|
||||||
|
|
||||||
mock_iter_entry_points.side_effect = lambda _t, name=None: [
|
|
||||||
MockEntrypoint("fake", "fake", ["FakePlugin"])]
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
auth_plugin.discover_auth_systems()
|
|
||||||
auth_plugin.load_auth_system_opts(parser)
|
|
||||||
opts, args = parser.parse_known_args(['--auth_system_opt'])
|
|
||||||
|
|
||||||
self.assertTrue(opts.auth_system_opt)
|
|
||||||
|
|
||||||
@mock.patch.object(pkg_resources, "iter_entry_points")
|
|
||||||
def test_parse_auth_system_options(self, mock_iter_entry_points):
|
|
||||||
"""Test that we can parse the auth system options."""
|
|
||||||
class MockEntrypoint(pkg_resources.EntryPoint):
|
|
||||||
def load(self, require=False):
|
|
||||||
return FakePlugin
|
|
||||||
|
|
||||||
def resolve(self):
|
|
||||||
return FakePlugin
|
|
||||||
|
|
||||||
class FakePlugin(auth_plugin.BaseAuthPlugin):
|
|
||||||
def __init__(self):
|
|
||||||
self.opts = {"fake_argument": True}
|
|
||||||
|
|
||||||
def parse_opts(self, args):
|
|
||||||
return self.opts
|
|
||||||
|
|
||||||
mock_iter_entry_points.side_effect = lambda _t, name=None: [
|
|
||||||
MockEntrypoint("fake", "fake", ["FakePlugin"])]
|
|
||||||
|
|
||||||
auth_plugin.discover_auth_systems()
|
|
||||||
plugin = auth_plugin.load_plugin("fake")
|
|
||||||
|
|
||||||
plugin.parse_opts([])
|
|
||||||
self.assertIn("fake_argument", plugin.opts)
|
|
||||||
|
|
||||||
@mock.patch.object(pkg_resources, "iter_entry_points")
|
|
||||||
def test_auth_system_defining_url(self, mock_iter_entry_points):
|
|
||||||
"""Test the auth_system defining an url."""
|
|
||||||
class MockEntrypoint(pkg_resources.EntryPoint):
|
|
||||||
def load(self, require=False):
|
|
||||||
return FakePlugin
|
|
||||||
|
|
||||||
def resolve(self):
|
|
||||||
return FakePlugin
|
|
||||||
|
|
||||||
class FakePlugin(auth_plugin.BaseAuthPlugin):
|
|
||||||
def get_auth_url(self):
|
|
||||||
return "http://faked/v2.0"
|
|
||||||
|
|
||||||
mock_iter_entry_points.side_effect = lambda _t, name=None: [
|
|
||||||
MockEntrypoint("fake", "fake", ["FakePlugin"])]
|
|
||||||
|
|
||||||
auth_plugin.discover_auth_systems()
|
|
||||||
plugin = auth_plugin.load_plugin("fake")
|
|
||||||
|
|
||||||
cs = client.Client("2", "username", "password", "project_id",
|
|
||||||
auth_system="fakewithauthurl",
|
|
||||||
auth_plugin=plugin)
|
|
||||||
self.assertEqual("http://faked/v2.0", cs.client.auth_url)
|
|
||||||
|
|
||||||
@mock.patch.object(pkg_resources, "iter_entry_points")
|
|
||||||
def test_exception_if_no_authenticate(self, mock_iter_entry_points):
|
|
||||||
"""Test that no authenticate raises a proper exception."""
|
|
||||||
class MockEntrypoint(pkg_resources.EntryPoint):
|
|
||||||
def load(self, require=False):
|
|
||||||
return FakePlugin
|
|
||||||
|
|
||||||
def resolve(self):
|
|
||||||
return FakePlugin
|
|
||||||
|
|
||||||
class FakePlugin(auth_plugin.BaseAuthPlugin):
|
|
||||||
pass
|
|
||||||
|
|
||||||
mock_iter_entry_points.side_effect = lambda _t, name=None: [
|
|
||||||
MockEntrypoint("fake", "fake", ["FakePlugin"])]
|
|
||||||
|
|
||||||
auth_plugin.discover_auth_systems()
|
|
||||||
plugin = auth_plugin.load_plugin("fake")
|
|
||||||
|
|
||||||
self.assertRaises(
|
|
||||||
exceptions.EndpointNotFound,
|
|
||||||
client.Client, "2", "username", "password", "project_id",
|
|
||||||
auth_system="fake", auth_plugin=plugin)
|
|
||||||
|
|
||||||
@mock.patch.object(pkg_resources, "iter_entry_points")
|
|
||||||
def test_exception_if_no_url(self, mock_iter_entry_points):
|
|
||||||
"""Test that no auth_url at all raises exception."""
|
|
||||||
class MockEntrypoint(pkg_resources.EntryPoint):
|
|
||||||
def load(self, require=False):
|
|
||||||
return FakePlugin
|
|
||||||
|
|
||||||
def resolve(self):
|
|
||||||
return FakePlugin
|
|
||||||
|
|
||||||
class FakePlugin(auth_plugin.BaseAuthPlugin):
|
|
||||||
pass
|
|
||||||
|
|
||||||
mock_iter_entry_points.side_effect = lambda _t, name=None: [
|
|
||||||
MockEntrypoint("fake", "fake", ["FakePlugin"])]
|
|
||||||
|
|
||||||
auth_plugin.discover_auth_systems()
|
|
||||||
plugin = auth_plugin.load_plugin("fake")
|
|
||||||
|
|
||||||
self.assertRaises(
|
|
||||||
exceptions.EndpointNotFound,
|
|
||||||
client.Client, "2", "username", "password", "project_id",
|
|
||||||
auth_system="fake", auth_plugin=plugin)
|
|
@ -62,15 +62,7 @@ FAKE_ENV4 = {'OS_USER_ID': 'user_id',
|
|||||||
FAKE_ENV5 = {'OS_USERNAME': 'username',
|
FAKE_ENV5 = {'OS_USERNAME': 'username',
|
||||||
'OS_PASSWORD': 'password',
|
'OS_PASSWORD': 'password',
|
||||||
'OS_TENANT_NAME': 'tenant_name',
|
'OS_TENANT_NAME': 'tenant_name',
|
||||||
'OS_AUTH_URL': 'http://no.where/v2.0',
|
'OS_AUTH_URL': 'http://no.where/v2.0'}
|
||||||
'OS_COMPUTE_API_VERSION': '2',
|
|
||||||
'OS_AUTH_SYSTEM': 'rackspace'}
|
|
||||||
|
|
||||||
FAKE_ENV6 = {'OS_USERNAME': 'username',
|
|
||||||
'OS_PASSWORD': 'password',
|
|
||||||
'OS_TENANT_NAME': 'tenant_name',
|
|
||||||
'OS_AUTH_URL': 'http://no.where/v2.0',
|
|
||||||
'OS_AUTH_SYSTEM': 'rackspace'}
|
|
||||||
|
|
||||||
|
|
||||||
def _create_ver_list(versions):
|
def _create_ver_list(versions):
|
||||||
@ -519,9 +511,7 @@ class ShellTest(utils.TestCase):
|
|||||||
|
|
||||||
def test_no_auth_url(self):
|
def test_no_auth_url(self):
|
||||||
required = ('You must provide an auth url'
|
required = ('You must provide an auth url'
|
||||||
' via either --os-auth-url or env[OS_AUTH_URL] or'
|
' via either --os-auth-url or env[OS_AUTH_URL].',)
|
||||||
' specify an auth_system which defines a default url'
|
|
||||||
' with --os-auth-system or env[OS_AUTH_SYSTEM]',)
|
|
||||||
self.make_env(exclude='OS_AUTH_URL')
|
self.make_env(exclude='OS_AUTH_URL')
|
||||||
try:
|
try:
|
||||||
self.shell('list')
|
self.shell('list')
|
||||||
@ -687,7 +677,7 @@ class ShellTest(utils.TestCase):
|
|||||||
|
|
||||||
@mock.patch('novaclient.client.Client')
|
@mock.patch('novaclient.client.Client')
|
||||||
def test_microversion_with_default_behaviour(self, mock_client):
|
def test_microversion_with_default_behaviour(self, mock_client):
|
||||||
self.make_env(fake_env=FAKE_ENV6)
|
self.make_env(fake_env=FAKE_ENV5)
|
||||||
self.mock_server_version_range.return_value = (
|
self.mock_server_version_range.return_value = (
|
||||||
api_versions.APIVersion("2.1"), api_versions.APIVersion("2.3"))
|
api_versions.APIVersion("2.1"), api_versions.APIVersion("2.3"))
|
||||||
self.shell('list')
|
self.shell('list')
|
||||||
@ -697,7 +687,7 @@ class ShellTest(utils.TestCase):
|
|||||||
@mock.patch('novaclient.client.Client')
|
@mock.patch('novaclient.client.Client')
|
||||||
def test_microversion_with_default_behaviour_with_legacy_server(
|
def test_microversion_with_default_behaviour_with_legacy_server(
|
||||||
self, mock_client):
|
self, mock_client):
|
||||||
self.make_env(fake_env=FAKE_ENV6)
|
self.make_env(fake_env=FAKE_ENV5)
|
||||||
self.mock_server_version_range.return_value = (
|
self.mock_server_version_range.return_value = (
|
||||||
api_versions.APIVersion(), api_versions.APIVersion())
|
api_versions.APIVersion(), api_versions.APIVersion())
|
||||||
self.shell('list')
|
self.shell('list')
|
||||||
@ -777,15 +767,6 @@ class ShellTest(utils.TestCase):
|
|||||||
self.shell,
|
self.shell,
|
||||||
'--os-compute-api-version 2.3 list')
|
'--os-compute-api-version 2.3 list')
|
||||||
|
|
||||||
@mock.patch('novaclient.client.Client')
|
|
||||||
def test_custom_auth_plugin(self, mock_client):
|
|
||||||
self.make_env(fake_env=FAKE_ENV5)
|
|
||||||
self.shell('list')
|
|
||||||
password = mock_client.call_args_list[0][0][2]
|
|
||||||
client_kwargs = mock_client.call_args_list[0][1]
|
|
||||||
self.assertEqual(password, 'password')
|
|
||||||
self.assertIs(client_kwargs['session'], None)
|
|
||||||
|
|
||||||
@mock.patch.object(novaclient.shell.OpenStackComputeShell, 'main')
|
@mock.patch.object(novaclient.shell.OpenStackComputeShell, 'main')
|
||||||
def test_main_error_handling(self, mock_compute_shell):
|
def test_main_error_handling(self, mock_compute_shell):
|
||||||
class MyException(Exception):
|
class MyException(Exception):
|
||||||
|
@ -68,7 +68,7 @@ class Client(object):
|
|||||||
service_type='compute', service_name=None,
|
service_type='compute', service_name=None,
|
||||||
volume_service_name=None, timings=False, bypass_url=None,
|
volume_service_name=None, timings=False, bypass_url=None,
|
||||||
os_cache=False, no_cache=True, http_log_debug=False,
|
os_cache=False, no_cache=True, http_log_debug=False,
|
||||||
auth_system='keystone', auth_plugin=None, auth_token=None,
|
auth_token=None,
|
||||||
cacert=None, tenant_id=None, user_id=None,
|
cacert=None, tenant_id=None, user_id=None,
|
||||||
connection_pool=False, session=None, auth=None,
|
connection_pool=False, session=None, auth=None,
|
||||||
api_version=None, direct_use=True, logger=None, **kwargs):
|
api_version=None, direct_use=True, logger=None, **kwargs):
|
||||||
@ -93,8 +93,6 @@ class Client(object):
|
|||||||
:param bool os_cache: OS cache
|
:param bool os_cache: OS cache
|
||||||
:param bool no_cache: No cache
|
:param bool no_cache: No cache
|
||||||
:param bool http_log_debug: Enable debugging for HTTP connections
|
:param bool http_log_debug: Enable debugging for HTTP connections
|
||||||
:param str auth_system: Auth system
|
|
||||||
:param str auth_plugin: Auth plugin
|
|
||||||
:param str auth_token: Auth token
|
:param str auth_token: Auth token
|
||||||
:param str cacert: cacert
|
:param str cacert: cacert
|
||||||
:param str tenant_id: Tenant ID
|
:param str tenant_id: Tenant ID
|
||||||
@ -194,8 +192,6 @@ class Client(object):
|
|||||||
auth_token=auth_token,
|
auth_token=auth_token,
|
||||||
insecure=insecure,
|
insecure=insecure,
|
||||||
timeout=timeout,
|
timeout=timeout,
|
||||||
auth_system=auth_system,
|
|
||||||
auth_plugin=auth_plugin,
|
|
||||||
proxy_token=proxy_token,
|
proxy_token=proxy_token,
|
||||||
proxy_tenant_id=proxy_tenant_id,
|
proxy_tenant_id=proxy_tenant_id,
|
||||||
region_name=region_name,
|
region_name=region_name,
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
prelude: >
|
||||||
|
The ability to use non-Keystone authentication systems has been removed.
|
||||||
|
upgrade:
|
||||||
|
- The ``--os-auth-system`` CLI option and ``OS_AUTH_SYSTEM`` environment
|
||||||
|
variable usage was deprecated in the 3.1.0 release during the Mitaka
|
||||||
|
development series. This release drops the support for using those options
|
||||||
|
to load non-Keystone authentication systems via the
|
||||||
|
``openstack.client.auth_plugin`` extension point.
|
Loading…
Reference in New Issue
Block a user