From 4614979e7e49518c66812b233fbe6389bfc86ee3 Mon Sep 17 00:00:00 2001 From: Matthew Edmonds Date: Fri, 30 Sep 2016 15:01:30 -0400 Subject: [PATCH] avoid usage of keystoneauth1 sessions Passing a keystoneauth1 session to the Connection constructor instead of an openstacksdk session leads to strange errors. This change will check for this usage error and raise a clear exception. Change-Id: I5d2d74502ef8abcb6c609864ce6fd5f5ec55af2a Closes-Bug: #1628316 --- openstack/connection.py | 15 +++++++++++++++ openstack/tests/unit/test_connection.py | 18 +++++++++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/openstack/connection.py b/openstack/connection.py index 3aea24014..fe114372a 100644 --- a/openstack/connection.py +++ b/openstack/connection.py @@ -63,6 +63,7 @@ import sys from keystoneauth1.loading import base as ksa_loader import os_client_config +from openstack import exceptions from openstack import profile as _profile from openstack import proxy from openstack import proxy2 @@ -207,6 +208,20 @@ class Connection(object): """ self.profile = profile if profile else _profile.Profile() if session: + # Make sure it is the right kind of session. A keystoneauth1 + # session would work in some ways but show strange errors in + # others. E.g. a Resource.find would work with an id but fail when + # given a name because it attempts to catch + # openstack.exceptions.NotFoundException to signal that a search by + # ID failed before trying a search by name, but with a + # keystoneauth1 session the lookup by ID raises + # keystoneauth1.exceptions.NotFound instead. We need to ensure our + # Session class gets used so that our implementation of various + # methods always works as we expect. + if not isinstance(session, _session.Session): + raise exceptions.SDKException( + 'Session instance is from %s but must be from %s' % + (session.__module__, _session.__name__)) self.session = session else: self.authenticator = self._create_authenticator(authenticator, diff --git a/openstack/tests/unit/test_connection.py b/openstack/tests/unit/test_connection.py index b829fa5c1..909cca5ea 100644 --- a/openstack/tests/unit/test_connection.py +++ b/openstack/tests/unit/test_connection.py @@ -13,11 +13,14 @@ import os import fixtures +from keystoneauth1 import session as ksa_session import mock import os_client_config from openstack import connection +from openstack import exceptions from openstack import profile +from openstack import session from openstack.tests.unit import base @@ -70,7 +73,7 @@ class TestConnection(base.TestCase): self.assertEqual(mock_session_init, conn.session) def test_session_provided(self): - mock_session = mock.Mock() + mock_session = mock.Mock(spec=session.Session) mock_profile = mock.Mock() mock_profile.get_services = mock.Mock(return_value=[]) conn = connection.Connection(session=mock_session, @@ -78,6 +81,14 @@ class TestConnection(base.TestCase): user_agent='1') self.assertEqual(mock_session, conn.session) + def test_ksa_session_provided(self): + mock_session = mock.Mock(spec=ksa_session.Session) + mock_profile = mock.Mock() + mock_profile.get_services = mock.Mock(return_value=[]) + self.assertRaises(exceptions.SDKException, connection.Connection, + session=mock_session, profile=mock_profile, + user_agent='1') + @mock.patch("keystoneauth1.loading.base.get_plugin_loader") def test_create_authenticator(self, mock_get_plugin): mock_plugin = mock.Mock() @@ -209,7 +220,7 @@ class TestConnection(base.TestCase): self.assertEqual(CONFIG_CACERT, sot.session.verify) def test_authorize_works(self): - fake_session = mock.Mock() + fake_session = mock.Mock(spec=session.Session) fake_headers = {'X-Auth-Token': 'FAKE_TOKEN'} fake_session.get_auth_headers.return_value = fake_headers @@ -219,8 +230,9 @@ class TestConnection(base.TestCase): self.assertEqual('FAKE_TOKEN', res) def test_authorize_silent_failure(self): - fake_session = mock.Mock() + fake_session = mock.Mock(spec=session.Session) fake_session.get_auth_headers.return_value = None + fake_session.__module__ = 'openstack.session' sot = connection.Connection(session=fake_session, authenticator=mock.Mock())