Merge "Allow an explicit_domain_id parameter when creating a domain"
This commit is contained in:
commit
0a66ef5328
@ -113,7 +113,17 @@ class DomainResource(ks_flask.ResourceBase):
|
||||
ENFORCER.enforce_call(action='identity:create_domain')
|
||||
domain = self.request_body_json.get('domain', {})
|
||||
validation.lazy_validate(schema.domain_create, domain)
|
||||
domain = self._assign_unique_id(domain)
|
||||
|
||||
domain_id = domain.get('explicit_domain_id')
|
||||
if domain_id is None:
|
||||
domain = self._assign_unique_id(domain)
|
||||
else:
|
||||
# Domain ID validation provided by PyCADF
|
||||
try:
|
||||
self._validate_id_format(domain_id)
|
||||
except ValueError:
|
||||
raise exception.DomainIdInvalid
|
||||
domain['id'] = domain_id
|
||||
domain = self._normalize_dict(domain)
|
||||
ref = PROVIDERS.resource_api.create_domain(
|
||||
domain['id'], domain, initiator=self.audit_initiator)
|
||||
|
@ -429,6 +429,10 @@ class DomainSpecificRoleNotWithinIdPDomain(Forbidden):
|
||||
"the identity provider: %(identity_provider)s.")
|
||||
|
||||
|
||||
class DomainIdInvalid(ValidationError):
|
||||
message_format = _("Domain ID does not conform to required UUID format.")
|
||||
|
||||
|
||||
class RoleAssignmentNotFound(NotFound):
|
||||
message_format = _("Could not find role assignment with role: "
|
||||
"%(role_id)s, user or group: %(actor_id)s, "
|
||||
|
@ -186,8 +186,10 @@ class Manager(manager.Manager):
|
||||
) % project['name']
|
||||
else:
|
||||
return _('it is not permitted to have two projects '
|
||||
'with the same name in the same domain : %s'
|
||||
) % project['name']
|
||||
'with either the same name or same id in '
|
||||
'the same domain: '
|
||||
'name is %(name)s, project id %(id)s'
|
||||
) % project
|
||||
|
||||
def create_project(self, project_id, project, initiator=None):
|
||||
project = project.copy()
|
||||
|
@ -604,6 +604,12 @@ class ResourceBase(flask_restful.Resource):
|
||||
ref['id'] = uuid.uuid4().hex
|
||||
return ref
|
||||
|
||||
@staticmethod
|
||||
def _validate_id_format(id):
|
||||
uval = uuid.UUID(id).hex
|
||||
if uval != id:
|
||||
raise ValueError('badly formed hexadecimal UUID value')
|
||||
|
||||
@classmethod
|
||||
def _require_matching_id(cls, ref):
|
||||
"""Ensure the value matches the reference's ID, if any."""
|
||||
|
@ -59,7 +59,8 @@ class TestResourceManagerNoFixtures(unit.SQLDriverOverrides, unit.TestCase):
|
||||
|
||||
self.assertRaises(exception.Conflict,
|
||||
PROVIDERS.resource_api.update_project,
|
||||
project['id'], {'name': project1['name']})
|
||||
project['id'], {'name': project1['name'],
|
||||
'id': project['id']})
|
||||
|
||||
|
||||
class DomainConfigDriverTests(object):
|
||||
|
@ -142,6 +142,54 @@ class ResourceTestCase(test_v3.RestfulTestCase,
|
||||
self.assertValidDomainResponse(r)
|
||||
self.assertIsNotNone(r.result['domain'])
|
||||
|
||||
def test_create_domain_valid_explicit_id(self):
|
||||
"""Call ``POST /domains`` with a valid `explicit_domain_id` set."""
|
||||
ref = unit.new_domain_ref()
|
||||
explicit_domain_id = '9aea63518f0040c6b4518d8d2242911c'
|
||||
|
||||
ref['explicit_domain_id'] = explicit_domain_id
|
||||
r = self.post(
|
||||
'/domains',
|
||||
body={'domain': ref})
|
||||
self.assertValidDomainResponse(r, ref)
|
||||
|
||||
r = self.get('/domains/%(domain_id)s' % {
|
||||
'domain_id': explicit_domain_id})
|
||||
self.assertValidDomainResponse(r)
|
||||
self.assertIsNotNone(r.result['domain'])
|
||||
|
||||
def test_create_second_domain_valid_explicit_id_fails(self):
|
||||
"""Call ``POST /domains`` with a valid `explicit_domain_id` set."""
|
||||
ref = unit.new_domain_ref()
|
||||
explicit_domain_id = '9aea63518f0040c6b4518d8d2242911c'
|
||||
|
||||
ref['explicit_domain_id'] = explicit_domain_id
|
||||
r = self.post(
|
||||
'/domains',
|
||||
body={'domain': ref})
|
||||
self.assertValidDomainResponse(r, ref)
|
||||
|
||||
# second one should fail
|
||||
r = self.post(
|
||||
'/domains',
|
||||
body={'domain': ref},
|
||||
expected_status=http_client.CONFLICT)
|
||||
|
||||
def test_create_domain_invalid_explicit_ids(self):
|
||||
"""Call ``POST /domains`` with various invalid explicit_domain_ids."""
|
||||
ref = unit.new_domain_ref()
|
||||
|
||||
bad_ids = ['bad!',
|
||||
'',
|
||||
'9aea63518f0040c',
|
||||
'1234567890123456789012345678901234567890',
|
||||
'9aea63518f0040c6b4518d8d2242911c9aea63518f0040c6b45']
|
||||
|
||||
for explicit_domain_id in bad_ids:
|
||||
ref['explicit_domain_id'] = explicit_domain_id
|
||||
self.post('/domains', body={'domain': {}},
|
||||
expected_status=http_client.BAD_REQUEST)
|
||||
|
||||
def test_list_head_domains(self):
|
||||
"""Call ``GET & HEAD /domains``."""
|
||||
resource_url = '/domains'
|
||||
|
21
releasenotes/notes/bug-1794527-866b1caff67977f3.yaml
Normal file
21
releasenotes/notes/bug-1794527-866b1caff67977f3.yaml
Normal file
@ -0,0 +1,21 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Allow the creating of a domain with the additional, optional
|
||||
parameter of `explicit_domain_id` instead of auto-creating a
|
||||
domain_id from a uuid.
|
||||
|
||||
When keeping two Keystone servers in sync, but avoiding Database
|
||||
replication, it was often necessary to hack the database to update
|
||||
the Domain ID so that entries match. Domain ID is then used for
|
||||
LDAP mapped IDs, and if they don't match, the user IDs are
|
||||
different. It should be possible to add a domain with an explicit
|
||||
ID, so that the two servers can match User IDs.
|
||||
The reason that the variable name is not simple `domain_id` is
|
||||
twofold: First to keep people from thinking that this is a required, or
|
||||
at least suggested field. Second, to prevent copy errors when
|
||||
creating a new domain, where the domain_id would be copied in from
|
||||
the old one, and having spurious failures, or undesirecd domain_id
|
||||
matching.
|
||||
|
||||
https://specs.openstack.org/openstack/keystone-specs/specs/keystone/stein/explicit-domains-ids.html
|
Loading…
Reference in New Issue
Block a user