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 import warnings
from keystoneauth1 import adapter 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 importutils
from oslo_utils import netutils from oslo_utils import netutils
import pkg_resources import pkg_resources
@ -65,7 +66,7 @@ class _ClientConnectionPool(object):
def get(self, url): def get(self, url):
"""Store and reuse HTTP adapters per Service URL.""" """Store and reuse HTTP adapters per Service URL."""
if url not in self._adapters: if url not in self._adapters:
self._adapters[url] = session.TCPKeepAliveAdapter() self._adapters[url] = ksession.TCPKeepAliveAdapter()
return self._adapters[url] return self._adapters[url]
@ -705,6 +706,7 @@ def _construct_http_client(api_version=None,
endpoint_type='publicURL', endpoint_type='publicURL',
http_log_debug=False, http_log_debug=False,
insecure=False, insecure=False,
logger=None,
os_cache=False, os_cache=False,
password=None, password=None,
project_domain_id=None, project_domain_id=None,
@ -724,13 +726,32 @@ def _construct_http_client(api_version=None,
username=None, username=None,
volume_service_name=None, volume_service_name=None,
**kwargs): **kwargs):
# TODO(mordred): If not session, just make a Session, then return if not session:
# SessionClient always if not auth and auth_token:
if session: 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, return SessionClient(api_version=api_version,
auth=auth, auth=auth,
endpoint_override=endpoint_override, endpoint_override=endpoint_override,
interface=endpoint_type, interface=endpoint_type,
logger=logger,
region_name=region_name, region_name=region_name,
service_name=service_name, service_name=service_name,
service_type=service_type, service_type=service_type,
@ -738,35 +759,6 @@ def _construct_http_client(api_version=None,
timings=timings, timings=timings,
user_agent=user_agent, user_agent=user_agent,
**kwargs) **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)
def discover_extensions(version, only_contrib=False): def discover_extensions(version, only_contrib=False):

View File

@ -674,6 +674,7 @@ class OpenStackComputeShell(object):
volume_service_name = args.volume_service_name volume_service_name = args.volume_service_name
endpoint_override = args.endpoint_override endpoint_override = args.endpoint_override
os_cache = args.os_cache os_cache = args.os_cache
cert = args.os_cert
cacert = args.os_cacert cacert = args.os_cacert
cert = args.os_cert cert = args.os_cert
timeout = args.timeout timeout = args.timeout
@ -707,11 +708,6 @@ 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 endpoint_override) 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 # 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:
@ -735,17 +731,12 @@ class OpenStackComputeShell(object):
_("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]."))
if use_session:
# Not using Nova auth plugin, so use keystone
with utils.record_time(self.times, args.timings, with utils.record_time(self.times, args.timings,
'auth_url', args.os_auth_url): 'auth_url', args.os_auth_url):
keystone_session = ( keystone_session = (
loading.load_session_from_argparse_arguments(args)) loading.load_session_from_argparse_arguments(args))
keystone_auth = ( keystone_auth = (
loading.load_auth_from_argparse_arguments(args)) loading.load_auth_from_argparse_arguments(args))
else:
# set password for auth plugins
os_password = args.os_password
if (not skip_auth and if (not skip_auth and
not any([os_project_name, os_project_id])): not any([os_project_name, os_project_id])):
@ -870,20 +861,6 @@ class OpenStackComputeShell(object):
# the result in our helper. # the result in our helper.
self.cs.client.password = helper.password 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) args.func(self.cs, args)
if args.timings: if args.timings:

View File

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

View File

@ -172,25 +172,7 @@ class ClientTest(utils.TestCase):
self.assertRaises(novaclient.exceptions.UnsupportedVersion, self.assertRaises(novaclient.exceptions.UnsupportedVersion,
novaclient.client.get_client_class, '2.latest') novaclient.client.get_client_class, '2.latest')
def test_client_with_os_cache_enabled(self): def test_client_get_reset_timings_v2(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):
cs = novaclient.client.Client("2", "user", "password", "project_id", cs = novaclient.client.Client("2", "user", "password", "project_id",
auth_url="foo/v2") auth_url="foo/v2")
self.assertEqual(0, len(cs.get_timings())) self.assertEqual(0, len(cs.get_timings()))

View File

@ -29,6 +29,11 @@ def Client(*args, **kwargs):
class AuthenticateAgainstKeystoneTests(utils.TestCase): 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): def get_token(self, **kwargs):
resp = fixture.V2Token(**kwargs) resp = fixture.V2Token(**kwargs)
resp.set_scope() resp.set_scope()
@ -315,6 +320,12 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
class AuthenticationTests(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): def test_authenticate_success(self):
cs = Client("username", "password", project_name="project_id", cs = Client("username", "password", project_name="project_id",
auth_url=utils.AUTH_URL) 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.