Merge "Verify project unique constraints for projects acting as domains"
This commit is contained in:
commit
8d7d49edaf
@ -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'],
|
||||
|
@ -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):
|
||||
|
Loading…
Reference in New Issue
Block a user