Merge "Verify project unique constraints for projects acting as domains"

This commit is contained in:
Jenkins 2016-02-17 20:27:17 +00:00 committed by Gerrit Code Review
commit 8d7d49edaf
2 changed files with 75 additions and 2 deletions

View File

@ -177,6 +177,16 @@ class Manager(manager.Manager):
'chars': utils.list_url_unsafe_chars(name)
})
def _generate_project_name_conflict_msg(self, project):
if project['is_domain']:
return _('it is not permitted to have two projects '
'acting as domains with the same name: %s'
) % project['name']
else:
return _('it is not permitted to have two projects '
'within a domain with the same name : %s'
) % project['name']
def create_project(self, project_id, project, initiator=None):
project = project.copy()
@ -205,7 +215,17 @@ class Manager(manager.Manager):
self._enforce_project_constraints(project, parent_id)
ret = self.driver.create_project(project_id, project)
# We leave enforcing name uniqueness to the underlying driver (instead
# of doing it in code in the project_constraints above), so as to allow
# this check to be done at the storage level, avoiding race conditions
# in multi-process keystone configurations.
try:
ret = self.driver.create_project(project_id, project)
except exception.Conflict:
raise exception.Conflict(
type='project',
details=self._generate_project_name_conflict_msg(project))
notifications.Audit.created(self._PROJECT, project_id, initiator)
if MEMOIZE.should_cache(ret):
self.get_project.set(ret, self, project_id)
@ -366,7 +386,13 @@ class Manager(manager.Manager):
original_project)
self._update_project_enabled_cascade(project_id, project_enabled)
ret = self.driver.update_project(project_id, project)
try:
ret = self.driver.update_project(project_id, project)
except exception.Conflict:
raise exception.Conflict(
type='project',
details=self._generate_project_name_conflict_msg(project))
notifications.Audit.updated(self._PROJECT, project_id, initiator)
self.get_project.invalidate(self, project_id)
self.get_project_by_name.invalidate(self, original_project['name'],

View File

@ -2656,6 +2656,53 @@ class IdentityTests(AssignmentTestHelperMixin):
self.assertTrue(ref['is_domain'])
self.assertEqual(DEFAULT_DOMAIN_ID, ref['domain_id'])
@unit.skip_if_no_multiple_domains_support
def test_project_as_a_domain_uniqueness_constraints(self):
"""Tests project uniqueness for those acting as domains.
If it is a project acting as a domain, we can't have two or more with
the same name.
"""
# Create two projects acting as a domain
project = unit.new_project_ref(is_domain=True)
project = self.resource_api.create_project(project['id'], project)
project2 = unit.new_project_ref(is_domain=True)
project2 = self.resource_api.create_project(project2['id'], project2)
# All projects acting as domains have a null domain_id, so should not
# be able to create another with the same name but a different
# project ID.
new_project = project.copy()
new_project['id'] = uuid.uuid4().hex
self.assertRaises(exception.Conflict,
self.resource_api.create_project,
new_project['id'],
new_project)
# We also should not be able to update one to have a name clash
project2['name'] = project['name']
self.assertRaises(exception.Conflict,
self.resource_api.update_project,
project2['id'],
project2)
# But updating it to a unique name is OK
project2['name'] = uuid.uuid4().hex
self.resource_api.update_project(project2['id'], project2)
# Finally, it should be OK to create a project with same name as one of
# these acting as a domain, as long as it is a regular project
project3 = unit.new_project_ref(domain_id=DEFAULT_DOMAIN_ID,
name=project2['name'])
self.resource_api.create_project(project3['id'], project3)
# In fact, it should be OK to create such a project in the domain which
# has the matching name.
# TODO(henry-nash): Once we fully support projects acting as a domain,
# add a test here to create a sub-project with a name that matches its
# project acting as a domain
@unit.skip_if_no_multiple_domains_support
@test_utils.wip('waiting for sub projects acting as domains support')
def test_is_domain_sub_project_has_parent_domain_id(self):