From 8101082fb670054f4ae5a76cd302aa8f8f4da11e Mon Sep 17 00:00:00 2001 From: Federico Ressi Date: Wed, 13 Mar 2019 09:28:27 +0100 Subject: [PATCH] Create model class to store Keystone credentials. Change-Id: I6cae5b4436ed1c5078876d45186374f32ef7e5c5 --- tobiko/openstack/keystone/__init__.py | 20 ++++ tobiko/openstack/keystone/credentials.py | 68 ++++++++++++ tobiko/tests/openstack/__init__.py | 0 tobiko/tests/openstack/keystone/__init__.py | 0 .../openstack/keystone/test_credentials.py | 104 ++++++++++++++++++ 5 files changed, 192 insertions(+) create mode 100644 tobiko/openstack/keystone/__init__.py create mode 100644 tobiko/openstack/keystone/credentials.py create mode 100644 tobiko/tests/openstack/__init__.py create mode 100644 tobiko/tests/openstack/keystone/__init__.py create mode 100644 tobiko/tests/openstack/keystone/test_credentials.py diff --git a/tobiko/openstack/keystone/__init__.py b/tobiko/openstack/keystone/__init__.py new file mode 100644 index 000000000..2b26e38da --- /dev/null +++ b/tobiko/openstack/keystone/__init__.py @@ -0,0 +1,20 @@ +# Copyright 2019 Red Hat +# +# 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. +from __future__ import absolute_import + +from tobiko.openstack.keystone import credentials + +keystone_credentials = credentials.keystone_credentials +KeystoneCredentials = credentials.KeystoneCredentials +InvalidKeystoneCredentials = credentials.InvalidKeystoneCredentials diff --git a/tobiko/openstack/keystone/credentials.py b/tobiko/openstack/keystone/credentials.py new file mode 100644 index 000000000..1df4b8e84 --- /dev/null +++ b/tobiko/openstack/keystone/credentials.py @@ -0,0 +1,68 @@ +# Copyright 2019 Red Hat +# +# 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. +from __future__ import absolute_import + +import collections + +from tobiko.common import exceptions + + +class KeystoneCredentials(collections.namedtuple( + 'KeystoneCredentials', ['auth_url', + 'username', + 'project_name', + 'password', + 'api_version', + 'user_domain_name', + 'project_domain_name'])): + + def to_dict(self): + return collections.OrderedDict( + (k, v) + for k, v in self._asdict().items() + if v is not None) + + def __repr__(self): + params = self.to_dict() + if 'password' in params: + params['password'] = '***' + return 'keystone_credentials({!s})'.format( + ", ".join("{!s}={!r}".format(k, v) + for k, v in params.items())) + + required_params = ('auth_url', 'username', 'project_name', 'password') + + def validate(self, required_params=None): + required_params = required_params or self.required_params + missing_params = [p + for p in required_params + if not getattr(self, p)] + if missing_params: + reason = "undefined parameters: {!s}".format( + ', '.join(missing_params)) + raise InvalidKeystoneCredentials(credentials=self, reason=reason) + + +def keystone_credentials(api_version=None, auth_url=None, + username=None, password=None, project_name=None, + user_domain_name=None, project_domain_name=None, + cls=KeystoneCredentials): + return cls(api_version=api_version, username=username, + password=password, project_name=project_name, + auth_url=auth_url, user_domain_name=user_domain_name, + project_domain_name=project_domain_name) + + +class InvalidKeystoneCredentials(exceptions.TobikoException): + message = "Invalid Keystone credentials (%(credentials)r): %(reason)s." diff --git a/tobiko/tests/openstack/__init__.py b/tobiko/tests/openstack/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tobiko/tests/openstack/keystone/__init__.py b/tobiko/tests/openstack/keystone/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tobiko/tests/openstack/keystone/test_credentials.py b/tobiko/tests/openstack/keystone/test_credentials.py new file mode 100644 index 000000000..fa5d0777e --- /dev/null +++ b/tobiko/tests/openstack/keystone/test_credentials.py @@ -0,0 +1,104 @@ +# Copyright (c) 2019 Red Hat +# 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. +from __future__ import absolute_import + +from tobiko.tests import unit +from tobiko.openstack import keystone + + +V2_PARAMS = { + 'api_version': 2, + 'project_name': 'demo', + 'username': 'demo', + 'password': 'super-secret', + 'auth_url': 'http://10.0.0.1:5678/v2.0'} + +V2_ENVIRON = { + 'OS_PROJECT_NAME': 'demo', + 'OS_USERNAME': 'demo', + 'OS_PASSWORD': 'super-secret', + 'OS_AUTH_URL': 'http://10.0.0.1:5678/v2.0'} + +V2_ENVIRON_WITH_VERSION = dict(V2_ENVIRON, OS_IDENTITY_API_VERSION='2') + + +V3_PARAMS = { + 'api_version': 3, + 'project_name': 'demo', + 'username': 'demo', + 'password': 'super-secret', + 'auth_url': 'http://10.0.0.1:5678/v3', + 'user_domain_name': 'demo', + 'project_domain_name': 'demo'} + +V3_ENVIRON = { + 'OS_PROJECT_NAME': 'demo', + 'OS_USERNAME': 'demo', + 'OS_PASSWORD': 'super-secret', + 'OS_AUTH_URL': 'http://10.0.0.1:5678/v3', + 'OS_USER_DOMAIN_NAME': 'demo', + 'OS_PROJECT_DOMAIN_NAME': 'demo'} + +V3_ENVIRON_WITH_VERSION = dict(V3_ENVIRON, OS_IDENTITY_API_VERSION='3') + + +def make_credentials(params, **kwargs): + if kwargs: + params = dict(params, **kwargs) + return keystone.keystone_credentials(**params) + + +class KeystoneCredentialsTest(unit.TobikoUnitTest): + + def test_validate_from_params_v2(self): + credentials = make_credentials(V2_PARAMS) + credentials.validate() + self.assertEqual(V2_PARAMS, credentials.to_dict()) + self.assertEqual( + "keystone_credentials(auth_url='http://10.0.0.1:5678/v2.0', " + "username='demo', project_name='demo', password='***', " + "api_version=2)", + repr(credentials)) + + def test_validate_from_params_v3(self): + credentials = make_credentials(V3_PARAMS) + credentials.validate() + self.assertEqual(V3_PARAMS, credentials.to_dict()) + self.assertEqual( + "keystone_credentials(auth_url='http://10.0.0.1:5678/v3', " + "username='demo', project_name='demo', password='***', " + "api_version=3, user_domain_name='demo', " + "project_domain_name='demo')", + repr(credentials)) + + def test_validate_without_auth_url(self): + credentials = make_credentials(V2_PARAMS, auth_url=None) + self.assertRaises(keystone.InvalidKeystoneCredentials, + credentials.validate) + + def test_validate_without_username(self): + credentials = make_credentials(V2_PARAMS, username=None) + self.assertRaises(keystone.InvalidKeystoneCredentials, + credentials.validate) + + def test_validate_without_project_name(self): + credentials = make_credentials(V2_PARAMS, project_name=None) + self.assertRaises(keystone.InvalidKeystoneCredentials, + credentials.validate) + + def test_validate_without_password(self): + credentials = make_credentials(V2_PARAMS, password=None) + self.assertRaises(keystone.InvalidKeystoneCredentials, + credentials.validate)