Merge "V2 operations create default domain on demand"
This commit is contained in:
commit
cf8e30e0dd
|
@ -80,6 +80,8 @@ class User(controller.V2Controller):
|
||||||
self.resource_api.get_project(default_project_id)
|
self.resource_api.get_project(default_project_id)
|
||||||
user['default_project_id'] = default_project_id
|
user['default_project_id'] = default_project_id
|
||||||
|
|
||||||
|
self.resource_api.ensure_default_domain_exists()
|
||||||
|
|
||||||
# The manager layer will generate the unique ID for users
|
# The manager layer will generate the unique ID for users
|
||||||
user_ref = self._normalize_domain_id(context, user.copy())
|
user_ref = self._normalize_domain_id(context, user.copy())
|
||||||
initiator = notifications._get_request_audit_info(context)
|
initiator = notifications._get_request_audit_info(context)
|
||||||
|
|
|
@ -43,8 +43,13 @@ class Tenant(controller.V2Controller):
|
||||||
if 'name' in context['query_string']:
|
if 'name' in context['query_string']:
|
||||||
return self._get_project_by_name(context['query_string']['name'])
|
return self._get_project_by_name(context['query_string']['name'])
|
||||||
|
|
||||||
tenant_refs = self.resource_api.list_projects_in_domain(
|
try:
|
||||||
CONF.identity.default_domain_id)
|
tenant_refs = self.resource_api.list_projects_in_domain(
|
||||||
|
CONF.identity.default_domain_id)
|
||||||
|
except exception.DomainNotFound:
|
||||||
|
# If the default domain doesn't exist then there are no V2
|
||||||
|
# projects.
|
||||||
|
tenant_refs = []
|
||||||
tenant_refs = [self.v3_to_v2_project(tenant_ref)
|
tenant_refs = [self.v3_to_v2_project(tenant_ref)
|
||||||
for tenant_ref in tenant_refs
|
for tenant_ref in tenant_refs
|
||||||
if not tenant_ref.get('is_domain')]
|
if not tenant_ref.get('is_domain')]
|
||||||
|
@ -91,6 +96,9 @@ class Tenant(controller.V2Controller):
|
||||||
raise exception.ValidationError(message=msg)
|
raise exception.ValidationError(message=msg)
|
||||||
|
|
||||||
self.assert_admin(context)
|
self.assert_admin(context)
|
||||||
|
|
||||||
|
self.resource_api.ensure_default_domain_exists()
|
||||||
|
|
||||||
tenant_ref['id'] = tenant_ref.get('id', uuid.uuid4().hex)
|
tenant_ref['id'] = tenant_ref.get('id', uuid.uuid4().hex)
|
||||||
initiator = notifications._get_request_audit_info(context)
|
initiator = notifications._get_request_audit_info(context)
|
||||||
tenant = self.resource_api.create_project(
|
tenant = self.resource_api.create_project(
|
||||||
|
|
|
@ -909,6 +909,32 @@ class Manager(manager.Manager):
|
||||||
# from persistence if persistence is enabled.
|
# from persistence if persistence is enabled.
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def ensure_default_domain_exists(self):
|
||||||
|
"""Creates the default domain if it doesn't exist.
|
||||||
|
|
||||||
|
This is only used for the v2 API and can go away when V2 does.
|
||||||
|
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
default_domain_attrs = {
|
||||||
|
'name': 'Default',
|
||||||
|
'id': CONF.identity.default_domain_id,
|
||||||
|
'description': 'Domain created automatically to support V2.0 '
|
||||||
|
'operations.',
|
||||||
|
}
|
||||||
|
self.create_domain(CONF.identity.default_domain_id,
|
||||||
|
default_domain_attrs)
|
||||||
|
LOG.warning(_LW(
|
||||||
|
'The default domain was created automatically to contain V2 '
|
||||||
|
'resources. This is deprecated in the M release and will not '
|
||||||
|
'be supported in the O release. Create the default domain '
|
||||||
|
'manually or use the keystone-manage bootstrap command.'))
|
||||||
|
except exception.Conflict:
|
||||||
|
LOG.debug('The default domain already exists.')
|
||||||
|
except Exception:
|
||||||
|
LOG.error(_LE('Failed to create the default domain.'))
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
# The ResourceDriverBase class is the set of driver methods from earlier
|
# The ResourceDriverBase class is the set of driver methods from earlier
|
||||||
# drivers that we still support, that have not been removed or modified. This
|
# drivers that we still support, that have not been removed or modified. This
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
# Copyright 2016 IBM Corp.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
|
||||||
|
from keystone import exception
|
||||||
|
from keystone.identity import controllers
|
||||||
|
from keystone.tests import unit
|
||||||
|
from keystone.tests.unit.ksfixtures import database
|
||||||
|
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
|
||||||
|
_ADMIN_CONTEXT = {'is_admin': True, 'query_string': {}}
|
||||||
|
|
||||||
|
|
||||||
|
class UserTestCaseNoDefaultDomain(unit.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(UserTestCaseNoDefaultDomain, self).setUp()
|
||||||
|
self.useFixture(database.Database())
|
||||||
|
self.load_backends()
|
||||||
|
self.user_controller = controllers.User()
|
||||||
|
|
||||||
|
def test_setup(self):
|
||||||
|
# Other tests in this class assume there's no default domain, so make
|
||||||
|
# sure the setUp worked as expected.
|
||||||
|
self.assertRaises(
|
||||||
|
exception.DomainNotFound,
|
||||||
|
self.resource_api.get_domain, CONF.identity.default_domain_id)
|
||||||
|
|
||||||
|
def test_get_users(self):
|
||||||
|
# When list_users is done and there's no default domain, the result is
|
||||||
|
# an empty list.
|
||||||
|
res = self.user_controller.get_users(_ADMIN_CONTEXT)
|
||||||
|
self.assertEqual([], res['users'])
|
||||||
|
|
||||||
|
def test_get_user_by_name(self):
|
||||||
|
# When get_user_by_name is done and there's no default domain, the
|
||||||
|
# result is 404 Not Found
|
||||||
|
user_name = uuid.uuid4().hex
|
||||||
|
self.assertRaises(
|
||||||
|
exception.UserNotFound,
|
||||||
|
self.user_controller.get_user_by_name, _ADMIN_CONTEXT, user_name)
|
||||||
|
|
||||||
|
def test_create_user(self):
|
||||||
|
# When a user is created using the v2 controller and there's no default
|
||||||
|
# domain, it doesn't fail with can't find domain (a default domain is
|
||||||
|
# created)
|
||||||
|
user = {'name': uuid.uuid4().hex}
|
||||||
|
self.user_controller.create_user(_ADMIN_CONTEXT, user)
|
||||||
|
# If the above doesn't fail then this is successful.
|
|
@ -0,0 +1,57 @@
|
||||||
|
# Copyright 2016 IBM Corp.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
|
||||||
|
from keystone import exception
|
||||||
|
from keystone.resource import controllers
|
||||||
|
from keystone.tests import unit
|
||||||
|
from keystone.tests.unit.ksfixtures import database
|
||||||
|
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
|
||||||
|
_ADMIN_CONTEXT = {'is_admin': True, 'query_string': {}}
|
||||||
|
|
||||||
|
|
||||||
|
class TenantTestCaseNoDefaultDomain(unit.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TenantTestCaseNoDefaultDomain, self).setUp()
|
||||||
|
self.useFixture(database.Database())
|
||||||
|
self.load_backends()
|
||||||
|
self.tenant_controller = controllers.Tenant()
|
||||||
|
|
||||||
|
def test_setup(self):
|
||||||
|
# Other tests in this class assume there's no default domain, so make
|
||||||
|
# sure the setUp worked as expected.
|
||||||
|
self.assertRaises(
|
||||||
|
exception.DomainNotFound,
|
||||||
|
self.resource_api.get_domain, CONF.identity.default_domain_id)
|
||||||
|
|
||||||
|
def test_get_all_projects(self):
|
||||||
|
# When get_all_projects is done and there's no default domain, the
|
||||||
|
# result is an empty list.
|
||||||
|
res = self.tenant_controller.get_all_projects(_ADMIN_CONTEXT)
|
||||||
|
self.assertEqual([], res['tenants'])
|
||||||
|
|
||||||
|
def test_create_project(self):
|
||||||
|
# When a project is created using the v2 controller and there's no
|
||||||
|
# default domain, it doesn't fail with can't find domain (a default
|
||||||
|
# domain is created)
|
||||||
|
tenant = {'name': uuid.uuid4().hex}
|
||||||
|
self.tenant_controller.create_project(_ADMIN_CONTEXT, tenant)
|
||||||
|
# If the above doesn't fail then this is successful.
|
|
@ -0,0 +1,91 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
from oslotest import mockpatch
|
||||||
|
|
||||||
|
from keystone import exception
|
||||||
|
from keystone.tests import unit
|
||||||
|
from keystone.tests.unit.ksfixtures import database
|
||||||
|
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
|
||||||
|
|
||||||
|
class TestResourceManagerNoFixtures(unit.SQLDriverOverrides, unit.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestResourceManagerNoFixtures, self).setUp()
|
||||||
|
self.useFixture(database.Database(self.sql_driver_version_overrides))
|
||||||
|
self.load_backends()
|
||||||
|
|
||||||
|
def test_ensure_default_domain_exists(self):
|
||||||
|
# When there's no default domain, ensure_default_domain_exists creates
|
||||||
|
# it.
|
||||||
|
|
||||||
|
# First make sure there's no default domain.
|
||||||
|
self.assertRaises(
|
||||||
|
exception.DomainNotFound,
|
||||||
|
self.resource_api.get_domain, CONF.identity.default_domain_id)
|
||||||
|
|
||||||
|
self.resource_api.ensure_default_domain_exists()
|
||||||
|
default_domain = self.resource_api.get_domain(
|
||||||
|
CONF.identity.default_domain_id)
|
||||||
|
|
||||||
|
expected_domain = {
|
||||||
|
'id': CONF.identity.default_domain_id,
|
||||||
|
'name': 'Default',
|
||||||
|
'enabled': True,
|
||||||
|
'description': 'Domain created automatically to support V2.0 '
|
||||||
|
'operations.',
|
||||||
|
}
|
||||||
|
self.assertEqual(expected_domain, default_domain)
|
||||||
|
|
||||||
|
def test_ensure_default_domain_exists_already_exists(self):
|
||||||
|
# When there's already a default domain, ensure_default_domain_exists
|
||||||
|
# doesn't do anything.
|
||||||
|
|
||||||
|
name = uuid.uuid4().hex
|
||||||
|
description = uuid.uuid4().hex
|
||||||
|
domain_attrs = {
|
||||||
|
'id': CONF.identity.default_domain_id,
|
||||||
|
'name': name,
|
||||||
|
'description': description,
|
||||||
|
}
|
||||||
|
self.resource_api.create_domain(CONF.identity.default_domain_id,
|
||||||
|
domain_attrs)
|
||||||
|
|
||||||
|
self.resource_api.ensure_default_domain_exists()
|
||||||
|
|
||||||
|
default_domain = self.resource_api.get_domain(
|
||||||
|
CONF.identity.default_domain_id)
|
||||||
|
|
||||||
|
expected_domain = {
|
||||||
|
'id': CONF.identity.default_domain_id,
|
||||||
|
'name': name,
|
||||||
|
'enabled': True,
|
||||||
|
'description': description,
|
||||||
|
}
|
||||||
|
|
||||||
|
self.assertEqual(expected_domain, default_domain)
|
||||||
|
|
||||||
|
def test_ensure_default_domain_exists_fails(self):
|
||||||
|
# When there's an unexpected exception creating domain it's passed on.
|
||||||
|
|
||||||
|
self.useFixture(mockpatch.PatchObject(
|
||||||
|
self.resource_api, 'create_domain',
|
||||||
|
side_effect=exception.UnexpectedError))
|
||||||
|
|
||||||
|
self.assertRaises(exception.UnexpectedError,
|
||||||
|
self.resource_api.ensure_default_domain_exists)
|
Loading…
Reference in New Issue