Improve keystone client 'lazyness'

Change-Id: Ib6ac662344edaf5167da532991e34c430385001f
This commit is contained in:
Federico Ressi 2019-06-17 16:09:10 +02:00
parent 1dfc6ccc6b
commit 5996055ab6
4 changed files with 154 additions and 117 deletions

View File

@ -17,10 +17,13 @@ from tobiko.openstack.keystone import _credentials
from tobiko.openstack.keystone import _session
keystone_credentials = _credentials.keystone_credentials
get_keystone_credentials = _credentials.get_keystone_credentials
default_keystone_credentials = _credentials.default_keystone_credentials
KeystoneCredentials = _credentials.KeystoneCredentials
KeystoneCredentialsFixture = _credentials.KeystoneCredentialsFixture
InvalidKeystoneCredentials = _credentials.InvalidKeystoneCredentials
keystone_session = _session.keystone_session
KeystoneSessionFixture = _session.KeystoneSessionFixture
KeystoneSessionManager = _session.KeystoneSessionManager
get_keystone_session = _session.get_keystone_session

View File

@ -23,8 +23,26 @@ import tobiko
LOG = log.getLogger(__name__)
def get_keystone_credentials(obj=None):
if not obj:
return default_keystone_credentials()
if tobiko.is_fixture(obj):
obj = tobiko.get_fixture(obj)
if isinstance(obj, KeystoneCredentialsFixture):
obj = tobiko.setup_fixture(obj).credentials
if isinstance(obj, KeystoneCredentials):
return obj
message = "Can't get {!r} object from {!r}".format(
KeystoneCredentials, obj)
raise TypeError(message)
def default_keystone_credentials():
return tobiko.setup_fixture(DefaultKeystoneCredentialsFixture).credentials
credentials = tobiko.setup_fixture(DefaultKeystoneCredentialsFixture
).credentials
tobiko.check_valid_type(credentials, KeystoneCredentials)
return credentials
class KeystoneCredentials(collections.namedtuple(
@ -93,16 +111,47 @@ class InvalidKeystoneCredentials(tobiko.TobikoException):
message = "invalid Keystone credentials; {reason!s}; {credentials!r}"
class EnvironKeystoneCredentialsFixture(tobiko.SharedFixture):
class KeystoneCredentialsFixture(tobiko.SharedFixture):
credentials = None
def __init__(self, credentials=None):
super(KeystoneCredentialsFixture, self).__init__()
if credentials:
self.credentials = credentials
def setup_fixture(self):
self.setup_credentials()
def setup_credentials(self):
credentials = self.credentials
if not self.credentials:
credentials = self.get_credentials()
if credentials:
try:
credentials.validate()
except InvalidKeystoneCredentials as ex:
LOG.info("No such valid credentials from environment: %r",
ex)
else:
self.addCleanup(self.cleanup_credentials)
self.credentials = credentials
def cleanup_credentials(self):
del self.credentials
def get_credentials(self):
return None
class EnvironKeystoneCredentialsFixture(KeystoneCredentialsFixture):
def get_credentials(self):
from tobiko import config
auth_url = config.get_env('OS_AUTH_URL')
if not auth_url:
LOG.debug("OS_AUTH_URL environment variable not defined")
return
return None
api_version = (
config.get_int_env('OS_IDENTITY_API_VERSION') or
@ -117,7 +166,7 @@ class EnvironKeystoneCredentialsFixture(tobiko.SharedFixture):
config.get_env('OS_PROJECT_ID') or
config.get_env('OS_TENANT_ID'))
if api_version == 2:
credentials = keystone_credentials(
return keystone_credentials(
api_version=api_version,
auth_url=auth_url,
username=username,
@ -135,7 +184,7 @@ class EnvironKeystoneCredentialsFixture(tobiko.SharedFixture):
project_domain_id = (
config.get_env('OS_PROJECT_DOMAIN_ID'))
trust_id = config.get_env('OS_TRUST_ID')
credentials = keystone_credentials(
return keystone_credentials(
api_version=api_version,
auth_url=auth_url,
username=username,
@ -146,38 +195,30 @@ class EnvironKeystoneCredentialsFixture(tobiko.SharedFixture):
project_domain_name=project_domain_name,
project_domain_id=project_domain_id,
trust_id=trust_id)
try:
credentials.validate()
except InvalidKeystoneCredentials as ex:
LOG.info("No such valid credentials from environment: %r", ex)
else:
self.credentials = credentials
class ConfigKeystoneCredentialsFixture(tobiko.SharedFixture):
class ConfigKeystoneCredentialsFixture(KeystoneCredentialsFixture):
credentials = None
def setup_fixture(self):
def get_credentials(self):
from tobiko import config
conf = config.CONF.tobiko.keystone
auth_url = conf.auth_url
if not auth_url:
LOG.debug("auth_url option not defined in 'keystone' section of "
"tobiko.conf")
return
return None
api_version = (conf.api_version or
api_version_from_url(auth_url))
if api_version == 2:
credentials = keystone_credentials(
return keystone_credentials(
api_version=api_version,
auth_url=auth_url,
username=conf.username,
password=conf.password,
project_name=conf.project_name)
else:
credentials = keystone_credentials(
return keystone_credentials(
api_version=api_version,
auth_url=auth_url,
username=conf.username,
@ -188,12 +229,6 @@ class ConfigKeystoneCredentialsFixture(tobiko.SharedFixture):
project_domain_name=conf.project_domain_name,
project_domain_id=conf.project_domain_id,
trust_id=conf.trust_id)
try:
credentials.validate()
except InvalidKeystoneCredentials as ex:
LOG.info("No such valid credentials from tobiko.conf: %r", ex)
else:
self.credentials = credentials
DEFAULT_KEYSTONE_CREDENTIALS_FIXTURES = [
@ -201,32 +236,30 @@ DEFAULT_KEYSTONE_CREDENTIALS_FIXTURES = [
ConfigKeystoneCredentialsFixture]
class DefaultKeystoneCredentialsFixture(tobiko.SharedFixture):
class DefaultKeystoneCredentialsFixture(KeystoneCredentialsFixture):
fixtures = DEFAULT_KEYSTONE_CREDENTIALS_FIXTURES
credentials = None
def setup_fixture(self):
def get_credentials(self):
for fixture in self.fixtures:
try:
credentials = tobiko.setup_fixture(fixture).credentials
except Exception:
LOG.exception("Error setting up fixture %r", fixture)
else:
if credentials:
LOG.info("Got default credentials from %r: %r",
fixture, credentials)
self.credentials = credentials
return credentials
raise RuntimeError('Unable to found any valid credentials')
continue
if credentials:
LOG.info("Got default credentials from fixture %r: %r",
fixture, credentials)
return credentials
def api_version_from_url(auth_url):
if auth_url.endswith('/v2.0'):
LOG.info('Got Keystone API version 2 from auth_url: %r', auth_url)
LOG.debug('Got Keystone API version 2 from auth_url: %r', auth_url)
return 2
elif auth_url.endswith('/v3'):
LOG.info('Got Keystone API version 3 from auth_url: %r', auth_url)
LOG.debug('Got Keystone API version 3 from auth_url: %r', auth_url)
return 3
else:
LOG.warning('Unable to get Keystone API version from auth_url: %r',

View File

@ -24,57 +24,80 @@ from tobiko.openstack.keystone import _credentials
LOG = log.getLogger(__name__)
def keystone_session(obj):
if not obj:
return default_keystone_session()
if tobiko.is_fixture(obj):
obj = tobiko.get_fixture(obj)
if isinstance(obj, KeystoneSessionFixture):
obj = tobiko.setup_fixture(obj).session
if isinstance(obj, _session.Session):
return obj
raise TypeError("Can't get {!r} object from {!r}".format(
_session.Session, obj))
class KeystoneSessionFixture(tobiko.SharedFixture):
session = None
credentials = None
credentials_fixture = None
def __init__(self, credentials=None):
VALID_CREDENTIALS_TYPES = (_credentials.KeystoneCredentials,
_credentials.KeystoneCredentialsFixture,
type, str)
def __init__(self, credentials=None, session=None):
super(KeystoneSessionFixture, self).__init__()
if credentials:
if tobiko.is_fixture(credentials):
self.credentials_fixture = credentials
else:
self.credentials = credentials
tobiko.check_valid_type(credentials, *self.VALID_CREDENTIALS_TYPES)
self.credentials = credentials
if session:
self.session = session
def setup_fixture(self):
self.setup_credentials()
self.setup_session(credentials=self.credentials)
self.setup_session()
def setup_credentials(self):
credentials_fixture = self.credentials_fixture
if credentials_fixture:
self.credentials = tobiko.setup_fixture(
credentials_fixture).credentials
elif not self.credentials:
self.credentials = _credentials.default_keystone_credentials()
def setup_session(self):
session = self.session
if not session:
credentials = _credentials.get_keystone_credentials(
self.credentials)
def setup_session(self, credentials):
LOG.debug("Create session for credentials %r", credentials)
loader = loading.get_plugin_loader('password')
params = credentials.to_dict()
del params['api_version'] # parameter not required
auth = loader.load_from_options(**params)
self.session = _session.Session(auth=auth, verify=False)
LOG.debug("Create Keystone session with credentials %r",
credentials)
credentials.validate()
loader = loading.get_plugin_loader('password')
params = credentials.to_dict()
del params['api_version'] # parameter not required
auth = loader.load_from_options(**params)
self.session = _session.Session(auth=auth, verify=False)
self.credentials = credentials
class KeystoneSessionManager(object):
def __init__(self):
self._sessions = {}
self.sessions = {}
def get_session(self, credentials=None, shared=True, init_session=None):
def get_session(self, credentials=None, init_session=None, shared=True):
if shared:
shared_key, session = self.get_shared_session(credentials)
else:
shared_key = session = None
return session or self.create_session(credentials=credentials,
init_session=init_session,
shared=shared,
shared_key=shared_key)
def get_shared_session(self, credentials):
if tobiko.is_fixture(credentials):
key = tobiko.get_fixture_name(credentials)
else:
key = credentials
if credentials:
if tobiko.is_fixture(credentials):
key = tobiko.get_fixture_name(credentials)
session = self._sessions.get(key)
if session:
return session
return key, self.sessions.get(key)
def create_session(self, credentials=None, init_session=None, shared=True,
shared_key=None):
init_session = init_session or KeystoneSessionFixture
assert callable(init_session)
LOG.debug('Initialize Keystone session: %r(credentials=%r)',
@ -82,17 +105,21 @@ class KeystoneSessionManager(object):
session = init_session(credentials=credentials)
if shared:
self._sessions[key] = session
self.sessions[shared_key] = session
return session
SESSIONS = KeystoneSessionManager()
def default_keystone_session(shared=True, init_session=None, manager=None):
return get_keystone_session(shared=shared, init_session=init_session,
manager=manager)
def get_keystone_session(credentials=None, shared=True, init_session=None,
manager=None):
manager = manager or SESSIONS
session = manager.get_session(credentials=credentials, shared=shared,
init_session=init_session)
session.setUp()
return session.session
return tobiko.setup_fixture(session).session

View File

@ -14,8 +14,6 @@
# under the License.
from __future__ import absolute_import
import inspect
from keystoneauth1 import session as keystonesession
import mock
@ -34,22 +32,6 @@ CREDENTIALS = keystone.keystone_credentials(
project_domain_name='Default')
class CredentialsFixture(tobiko.SharedFixture):
credentials = None
def setup_fixture(self):
self.credentials = CREDENTIALS
class DefaultCredentialsFixture(tobiko.SharedFixture):
credentials = None
def setup_fixture(self):
self.credentials = DEFAULT_CREDENTIALS
DEFAULT_CREDENTIALS = keystone.keystone_credentials(
api_version=2,
auth_url='http://127.0.0.1:5000/identiy/v2.0',
@ -58,23 +40,17 @@ DEFAULT_CREDENTIALS = keystone.keystone_credentials(
password='this is a secret')
class CheckSessionCredentialsMixin(object):
class CredentialsFixture(keystone.KeystoneCredentialsFixture):
def check_session_credentials(self, session, credentials):
if credentials:
if tobiko.is_fixture(credentials):
self.assertIsNone(session.credentials)
self.assertIs(credentials, session.credentials_fixture)
else:
self.assertIs(credentials, session.credentials)
self.assertIsNone(session.credentials_fixture)
else:
self.assertIsNone(session.credentials)
self.assertIsNone(session.credentials_fixture)
credentials = CREDENTIALS
class KeystoneSessionFixtureTest(CheckSessionCredentialsMixin,
openstack.OpenstackTest):
class DefaultCredentialsFixture(CredentialsFixture):
credentials = DEFAULT_CREDENTIALS
class KeystoneSessionFixtureTest(openstack.OpenstackTest):
default_credentials_fixture = (
'tobiko.openstack.keystone._credentials.'
@ -83,15 +59,17 @@ class KeystoneSessionFixtureTest(CheckSessionCredentialsMixin,
def setUp(self):
super(KeystoneSessionFixtureTest, self).setUp()
from tobiko.openstack.keystone import _credentials
from tobiko.openstack.keystone import _session
tobiko.remove_fixture(self.default_credentials_fixture)
self.patch(_credentials, 'DefaultKeystoneCredentialsFixture',
DefaultCredentialsFixture)
self.patch(_session, 'SESSIONS',
_session.KeystoneSessionManager())
def test_init(self, credentials=None):
session = keystone.KeystoneSessionFixture(credentials=credentials)
self.check_session_credentials(session=session,
credentials=credentials)
self.assertIs(credentials or None, session.credentials)
def test_init_with_credentials(self):
self.test_init(credentials=CREDENTIALS)
@ -105,15 +83,12 @@ class KeystoneSessionFixtureTest(CheckSessionCredentialsMixin,
def test_setup(self, credentials=None):
session = keystone.KeystoneSessionFixture(credentials=credentials)
session.setUp()
if credentials:
if tobiko.is_fixture(credentials):
if inspect.isclass(credentials):
credentials = tobiko.get_fixture(credentials)
self.assertIs(credentials.credentials, session.credentials)
else:
self.assertIs(credentials, session.credentials)
if tobiko.is_fixture(credentials):
credentials = tobiko.get_fixture(credentials)
self.assertIs(credentials.credentials, session.credentials)
else:
self.assertEqual(DEFAULT_CREDENTIALS, session.credentials)
self.assertIs(credentials or DEFAULT_CREDENTIALS,
session.credentials)
def test_setup_with_credentials(self):
self.test_setup(credentials=CREDENTIALS)
@ -125,21 +100,20 @@ class KeystoneSessionFixtureTest(CheckSessionCredentialsMixin,
self.test_setup(credentials=CredentialsFixture)
class KeystoneSessionManagerTest(CheckSessionCredentialsMixin,
openstack.OpenstackTest):
class KeystoneSessionManagerTest(openstack.OpenstackTest):
def test_init(self):
manager = keystone.KeystoneSessionManager()
self.assertTrue(manager)
self.assertEqual({}, manager.sessions)
def test_get_session(self, credentials=None, shared=True):
manager = keystone.KeystoneSessionManager()
session = manager.get_session(credentials=credentials,
shared=shared)
self.assertIs(credentials or None, session.credentials)
self.assertIsInstance(session, keystone.KeystoneSessionFixture)
self.check_session_credentials(session=session,
credentials=credentials)
if shared:
self.assertIs(session, manager.get_session(
credentials=credentials))