Create keystone session instance if not present

Since all authentication plugins should be stored in Keystone, there is no
need to share responsibility for authentication stuff with Keystone team.
Let's use convinient and the right way to use keystone - keystone sessions.
We have own adapter for it - novaclient.client.Session which can be used in
100% cases of novaclient usage. Let's create session object if it is not
transmitted via arguments and get rid of novaclient.client.HTTPClient
implementation.

NOTE: novaclient.client.HTTPClient and all related code will be removed
      separately.

Co-Authored-By: Clenimar Filemon <clenimar@lsd.ufcg.edu.br>
Change-Id: Ibb99fdafbf02b3e92f1a5d04d168151b3400b901
This commit is contained in:
Andrey Kurilin 2016-06-17 14:45:55 +03:00
parent e4dc84e0f6
commit 8409e006c5
6 changed files with 67 additions and 95 deletions

View File

@ -30,7 +30,8 @@ import re
import warnings
from keystoneauth1 import adapter
from keystoneauth1 import session
from keystoneauth1 import identity
from keystoneauth1 import session as ksession
from oslo_utils import importutils
from oslo_utils import netutils
import pkg_resources
@ -65,7 +66,7 @@ class _ClientConnectionPool(object):
def get(self, url):
"""Store and reuse HTTP adapters per Service URL."""
if url not in self._adapters:
self._adapters[url] = session.TCPKeepAliveAdapter()
self._adapters[url] = ksession.TCPKeepAliveAdapter()
return self._adapters[url]
@ -705,6 +706,7 @@ def _construct_http_client(api_version=None,
endpoint_type='publicURL',
http_log_debug=False,
insecure=False,
logger=None,
os_cache=False,
password=None,
project_domain_id=None,
@ -724,49 +726,39 @@ def _construct_http_client(api_version=None,
username=None,
volume_service_name=None,
**kwargs):
# TODO(mordred): If not session, just make a Session, then return
# SessionClient always
if session:
return SessionClient(api_version=api_version,
auth=auth,
endpoint_override=endpoint_override,
interface=endpoint_type,
region_name=region_name,
service_name=service_name,
service_type=service_type,
session=session,
timings=timings,
user_agent=user_agent,
**kwargs)
else:
# FIXME(jamielennox): username and password are now optional. Need
# to test that they were provided in this mode.
logger = kwargs.get('logger')
return HTTPClient(username,
password,
user_id=user_id,
# NOTE(andreykurilin): HTTPClient will be replaced
# fully by SessionClient soon, so there are no
# reasons to spend time renaming projectid variable
# to tenant_name/project_name.
projectid=project_name,
tenant_id=project_id,
auth_url=auth_url,
auth_token=auth_token,
insecure=insecure,
timeout=timeout,
region_name=region_name,
endpoint_type=endpoint_type,
service_type=service_type,
service_name=service_name,
volume_service_name=volume_service_name,
timings=timings,
bypass_url=endpoint_override,
os_cache=os_cache,
http_log_debug=http_log_debug,
cacert=cacert,
api_version=api_version,
logger=logger)
if not session:
if not auth and auth_token:
auth = identity.Token(auth_url=auth_url,
token=auth_token)
elif not auth:
auth = identity.Password(username=username,
user_id=user_id,
password=password,
project_id=project_id,
project_name=project_name,
auth_url=auth_url,
project_domain_id=project_domain_id,
project_domain_name=project_domain_name,
user_domain_id=user_domain_id,
user_domain_name=user_domain_name)
session = ksession.Session(auth=auth,
verify=(cacert or not insecure),
timeout=timeout,
cert=cert,
user_agent=user_agent)
return SessionClient(api_version=api_version,
auth=auth,
endpoint_override=endpoint_override,
interface=endpoint_type,
logger=logger,
region_name=region_name,
service_name=service_name,
service_type=service_type,
session=session,
timings=timings,
user_agent=user_agent,
**kwargs)
def discover_extensions(version, only_contrib=False):

View File

@ -674,6 +674,7 @@ class OpenStackComputeShell(object):
volume_service_name = args.volume_service_name
endpoint_override = args.endpoint_override
os_cache = args.os_cache
cert = args.os_cert
cacert = args.os_cacert
cert = args.os_cert
timeout = args.timeout
@ -707,11 +708,6 @@ class OpenStackComputeShell(object):
# Expired tokens are handled by client.py:_cs_request
must_auth = not (auth_token and endpoint_override)
# Do not use Keystone session for cases with no session support.
use_session = True
if endpoint_override or os_cache or volume_service_name:
use_session = False
# FIXME(usrleon): Here should be restrict for project id same as
# for os_username or os_password but for compatibility it is not.
if must_auth and not skip_auth:
@ -735,17 +731,12 @@ class OpenStackComputeShell(object):
_("You must provide an auth url "
"via either --os-auth-url or env[OS_AUTH_URL]."))
if use_session:
# Not using Nova auth plugin, so use keystone
with utils.record_time(self.times, args.timings,
'auth_url', args.os_auth_url):
keystone_session = (
loading.load_session_from_argparse_arguments(args))
keystone_auth = (
loading.load_auth_from_argparse_arguments(args))
else:
# set password for auth plugins
os_password = args.os_password
with utils.record_time(self.times, args.timings,
'auth_url', args.os_auth_url):
keystone_session = (
loading.load_session_from_argparse_arguments(args))
keystone_auth = (
loading.load_auth_from_argparse_arguments(args))
if (not skip_auth and
not any([os_project_name, os_project_id])):
@ -870,20 +861,6 @@ class OpenStackComputeShell(object):
# the result in our helper.
self.cs.client.password = helper.password
try:
# This does a couple of bits which are useful even if we've
# got the token + service URL already. It exits fast in that case.
if not utils.isunauthenticated(args.func):
if not use_session:
# Only call authenticate() if Nova auth plugin is used.
# If keystone is used, authentication is handled as part
# of session.
self.cs.authenticate()
except exc.Unauthorized:
raise exc.CommandError(_("Invalid OpenStack Nova credentials."))
except exc.AuthorizationFailure:
raise exc.CommandError(_("Unable to authorize user"))
args.func(self.cs, args)
if args.timings:

View File

@ -329,7 +329,7 @@ class Base(base.Fixture):
headers=self.json_headers)
def put_server_tag(request, context):
assert request.json() is None
assert request.text is None
context.status_code = 201
return None

View File

@ -172,25 +172,7 @@ class ClientTest(utils.TestCase):
self.assertRaises(novaclient.exceptions.UnsupportedVersion,
novaclient.client.get_client_class, '2.latest')
def test_client_with_os_cache_enabled(self):
cs = novaclient.client.Client("2", "user", "password", "project_id",
auth_url="foo/v2", os_cache=True)
self.assertTrue(cs.os_cache)
self.assertTrue(cs.client.os_cache)
def test_client_with_os_cache_disabled(self):
cs = novaclient.client.Client("2", "user", "password", "project_id",
auth_url="foo/v2", os_cache=False)
self.assertFalse(cs.os_cache)
self.assertFalse(cs.client.os_cache)
def test_client_set_management_url_v1_1(self):
cs = novaclient.client.Client("2", "user", "password", "project_id",
auth_url="foo/v2")
cs.set_management_url("blabla")
self.assertEqual("blabla", cs.client.management_url)
def test_client_get_reset_timings_v1_1(self):
def test_client_get_reset_timings_v2(self):
cs = novaclient.client.Client("2", "user", "password", "project_id",
auth_url="foo/v2")
self.assertEqual(0, len(cs.get_timings()))

View File

@ -29,6 +29,11 @@ def Client(*args, **kwargs):
class AuthenticateAgainstKeystoneTests(utils.TestCase):
def setUp(self):
super(AuthenticateAgainstKeystoneTests, self).setUp()
self.skipTest("This TestCase checks deprecated authentication "
"methods, which will be removed in separate patch.")
def get_token(self, **kwargs):
resp = fixture.V2Token(**kwargs)
resp.set_scope()
@ -315,6 +320,12 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
class AuthenticationTests(utils.TestCase):
def setUp(self):
super(AuthenticationTests, self).setUp()
self.skipTest("This TestCase checks deprecated authentication "
"methods, which will be removed in separate patch.")
def test_authenticate_success(self):
cs = Client("username", "password", project_name="project_id",
auth_url=utils.AUTH_URL)

View File

@ -0,0 +1,10 @@
---
upgrade:
- |
When using novaclient as a library (via novaclient.client.Client
entry-point), an internal implementation of HTTPClient was used if a
session object is not specified. For better user experience we switched
to using SessionClient which uses keystoneauth (Keystone folks maintain
this library) for all auth stuff.
The SessionClient interface is similar to HTTPClient, but there is a
small possibility that you will notice a difference.