From b10c6caa1ac94fa8dd81438f39d38607d99f1ee4 Mon Sep 17 00:00:00 2001 From: John Warren Date: Fri, 26 Feb 2016 15:32:37 -0500 Subject: [PATCH] Fix V3 credential behavior, documentation Fixing V3 credential behavior so that contradicting parameter combinations do not result in unpredictable behavior. Updating accounts.yaml.sample file to reference the correct location of the credentials classes and to describe the updated behavior of Identity V3 attributes. Change-Id: I29efe778afcb1e4a55dffd6a8ed8212d62a4dd15 --- etc/accounts.yaml.sample | 20 ++++++++++++++++- tempest/lib/auth.py | 19 ++++++++++++++-- tempest/tests/lib/test_auth.py | 40 ++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 3 deletions(-) diff --git a/etc/accounts.yaml.sample b/etc/accounts.yaml.sample index decc659732..3dbed79e9d 100644 --- a/etc/accounts.yaml.sample +++ b/etc/accounts.yaml.sample @@ -3,7 +3,25 @@ # This is required to provide isolation between test for running in parallel # # Valid fields for credentials are defined in the descendants of -# auth.Credentials - see KeystoneV[2|3]Credentials.CONF_ATTRIBUTES +# lib.auth.Credentials - see KeystoneV[2|3]Credentials.ATTRIBUTES +# +# The fields in KeystoneV3Credentials behave as follows: +# +# tenant_[id|name] also sets project_[id|name]. +# +# project_[id|name] also sets tenant_[id|name]. +# +# Providing distinct values for both tenant_[id|name] and project_[id|name] +# will result in an InvalidCredentials exception. +# +# The value of project_domain_[id|name] is used for user_domain_[id|name] if +# the latter is not specified. +# +# The value of user_domain_[id|name] is used for project_domain_[id|name] if +# the latter is not specified. +# +# The value of domain_[id|name] is used for project_domain_[id|name] if not +# specified and user_domain_[id|name] if not specified. - username: 'user_1' tenant_name: 'test_tenant_1' diff --git a/tempest/lib/auth.py b/tempest/lib/auth.py index 2d20a0be6a..71c4f4fd05 100644 --- a/tempest/lib/auth.py +++ b/tempest/lib/auth.py @@ -622,6 +622,9 @@ class KeystoneV2Credentials(Credentials): return None not in (self.username, self.password) +COLLISIONS = [('project_name', 'tenant_name'), ('project_id', 'tenant_id')] + + class KeystoneV3Credentials(Credentials): """Credentials suitable for the Keystone Identity V3 API""" @@ -630,6 +633,16 @@ class KeystoneV3Credentials(Credentials): 'project_name', 'tenant_id', 'tenant_name', 'user_domain_id', 'user_domain_name', 'user_id'] + def _apply_credentials(self, attr): + for (key1, key2) in COLLISIONS: + val1 = attr.get(key1) + val2 = attr.get(key2) + if val1 and val2 and val1 != val2: + msg = ('Cannot have conflicting values for %s and %s' % + (key1, key2)) + raise exceptions.InvalidCredentials(msg) + super(KeystoneV3Credentials, self)._apply_credentials(attr) + def __setattr__(self, key, value): parent = super(KeystoneV3Credentials, self) # for tenant_* set both project and tenant @@ -657,8 +670,10 @@ class KeystoneV3Credentials(Credentials): parent.__setattr__('user_domain_name', value) # support domain_name coming from config if key == 'domain_name': - parent.__setattr__('user_domain_name', value) - parent.__setattr__('project_domain_name', value) + if self.user_domain_name is None: + parent.__setattr__('user_domain_name', value) + if self.project_domain_name is None: + parent.__setattr__('project_domain_name', value) # finally trigger default behaviour for all attributes parent.__setattr__(key, value) diff --git a/tempest/tests/lib/test_auth.py b/tempest/tests/lib/test_auth.py index ebcfe82883..6a01490ad1 100644 --- a/tempest/tests/lib/test_auth.py +++ b/tempest/tests/lib/test_auth.py @@ -530,3 +530,43 @@ class TestKeystoneV3AuthProvider(TestKeystoneV2AuthProvider): expected = 'http://fake_url/v3' self._test_base_url_helper(expected, filters, ('token', auth_data)) + + +class TestKeystoneV3Credentials(base.TestCase): + def testSetAttrUserDomain(self): + creds = auth.KeystoneV3Credentials() + creds.user_domain_name = 'user_domain' + creds.domain_name = 'domain' + self.assertEqual('user_domain', creds.user_domain_name) + creds = auth.KeystoneV3Credentials() + creds.domain_name = 'domain' + creds.user_domain_name = 'user_domain' + self.assertEqual('user_domain', creds.user_domain_name) + + def testSetAttrProjectDomain(self): + creds = auth.KeystoneV3Credentials() + creds.project_domain_name = 'project_domain' + creds.domain_name = 'domain' + self.assertEqual('project_domain', creds.user_domain_name) + creds = auth.KeystoneV3Credentials() + creds.domain_name = 'domain' + creds.project_domain_name = 'project_domain' + self.assertEqual('project_domain', creds.project_domain_name) + + def testProjectTenantNoCollision(self): + creds = auth.KeystoneV3Credentials(tenant_id='tenant') + self.assertEqual('tenant', creds.project_id) + creds = auth.KeystoneV3Credentials(project_id='project') + self.assertEqual('project', creds.tenant_id) + creds = auth.KeystoneV3Credentials(tenant_name='tenant') + self.assertEqual('tenant', creds.project_name) + creds = auth.KeystoneV3Credentials(project_name='project') + self.assertEqual('project', creds.tenant_name) + + def testProjectTenantCollision(self): + attrs = {'tenant_id': 'tenant', 'project_id': 'project'} + self.assertRaises( + exceptions.InvalidCredentials, auth.KeystoneV3Credentials, **attrs) + attrs = {'tenant_name': 'tenant', 'project_name': 'project'} + self.assertRaises( + exceptions.InvalidCredentials, auth.KeystoneV3Credentials, **attrs)