Merge "Remove v2.0 resource APIs"

This commit is contained in:
Jenkins 2017-09-12 23:45:48 +00:00 committed by Gerrit Code Review
commit 30eb190995
11 changed files with 4 additions and 576 deletions

View File

@ -5,41 +5,6 @@ Tenants
=======
Show tenant details, by ID
==========================
.. rest_method:: GET /v2.0/tenants/{tenantId}
Shows details for a tenant, by ID.
Normal response codes: 200,203
Error response codes: 413,405,404,403,401,400,503
Request
-------
.. rest_parameters:: parameters.yaml
- tenantId: tenant_id_path
Response Parameters
-------------------
.. rest_parameters:: parameters.yaml
- tenant: tenant
- enabled: tenant_enabled
- description: tenant_description
- name: tenant_name
- id: tenant_id
Response Example
----------------
.. literalinclude:: samples/admin/tenant-show-response.json
:language: javascript
List users on a tenant
======================
@ -110,158 +75,3 @@ Response Example
.. literalinclude:: samples/admin/roles-list-response.json
:language: javascript
List tenants (admin endpoint)
=============================
.. rest_method:: GET /v2.0/tenants
Lists all tenants.
Normal response codes: 200,203
Error response codes: 413,405,404,403,401,400,503
Response Parameters
-------------------
.. rest_parameters:: parameters.yaml
- tenants: tenants
- tenant_links: tenant_links
- enabled: tenant_enabled
- description: tenant_description
- name: tenant_name
- id: tenant_id
Response Example
----------------
.. literalinclude:: ../v2/samples/admin/tenants-list-response.json
:language: javascript
Show tenant details, by name
============================
.. rest_method:: GET /v2.0/tenants
Shows details for a tenant, by name.
Normal response codes: 200,203
Error response codes: 413,405,404,403,401,400,503
Request
-------
.. rest_parameters:: parameters.yaml
- name: tenant_name_query
Response Parameters
-------------------
.. rest_parameters:: parameters.yaml
- tenant: tenant
- enabled: tenant_enabled
- description: tenant_description
- name: tenant_name
- id: tenant_id
Response Example
----------------
.. literalinclude:: samples/admin/tenant-show-response.json
:language: javascript
Delete tenant
=============
.. rest_method:: DELETE /v2.0/tenants/{tenantId}
Deletes a tenant.
Normal response codes: 204
Error response codes: 413,415,405,404,403,401,400,503,409
Request
-------
.. rest_parameters:: parameters.yaml
- tenantId: tenant_id_path
Update tenant
=============
.. rest_method:: POST /v2.0/tenants/{tenantId}
Updates a tenant.
Normal response codes: 200
Error response codes: 413,415,405,404,403,401,400,503,409
Request
-------
.. rest_parameters:: parameters.yaml
- tenantId: tenant_id_path
- tenant: tenant
- enabled: tenant_enabled
- description: tenant_description
- name: tenant_name
Request Example
---------------
.. literalinclude:: samples/admin/tenant-update-request.json
:language: javascript
Response Parameters
-------------------
.. rest_parameters:: parameters.yaml
- tenant: tenant
- enabled: tenant_enabled
- description: tenant_description
- name: tenant_name
- id: tenant_id
Response Example
----------------
.. literalinclude:: samples/admin/tenant-show-response.json
:language: javascript
Create tenant
=============
.. rest_method:: POST /v2.0/tenants
Creates a tenant.
Normal response codes: 201
Error response codes: 413,415,405,404,403,401,400,503,409
Request Example
---------------
.. literalinclude:: samples/admin/tenantwithoutid-create-request.json
:language: javascript
Response Parameters
-------------------
.. rest_parameters:: parameters.yaml
- tenant: tenant
- enabled: tenant_enabled
- description: tenant_description
- name: tenant_name
- id: tenant_id

View File

@ -15,8 +15,6 @@
"""Workflow Logic the Resource service."""
import uuid
from six.moves import http_client
from keystone.common import controller
@ -32,93 +30,6 @@ from keystone.resource import schema
CONF = keystone.conf.CONF
@dependency.requires('resource_api')
class Tenant(controller.V2Controller):
@controller.v2_deprecated
def get_all_projects(self, request, **kw):
"""Get a list of all tenants for an admin user."""
self.assert_admin(request)
name = request.params.get('name')
if name:
return self._get_project_by_name(name)
try:
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)
for tenant_ref in tenant_refs
if not tenant_ref.get('is_domain')]
params = {
'limit': request.params.get('limit'),
'marker': request.params.get('marker'),
}
return self.format_project_list(tenant_refs, **params)
def _assert_not_is_domain_project(self, project_id, project_ref=None):
# Projects acting as a domain should not be visible via v2
if not project_ref:
project_ref = self.resource_api.get_project(project_id)
if project_ref.get('is_domain'):
raise exception.ProjectNotFound(project_id)
@controller.v2_deprecated
def get_project(self, request, tenant_id):
# TODO(termie): this stuff should probably be moved to middleware
self.assert_admin(request)
ref = self.resource_api.get_project(tenant_id)
self._assert_not_is_domain_project(tenant_id, ref)
return {'tenant': self.v3_to_v2_project(ref)}
def _get_project_by_name(self, tenant_name):
# Projects acting as a domain should not be visible via v2
ref = self.resource_api.get_project_by_name(
tenant_name, CONF.identity.default_domain_id)
self._assert_not_is_domain_project(ref['id'], ref)
return {'tenant': self.v3_to_v2_project(ref)}
# CRUD Extension
@controller.v2_deprecated
def create_project(self, request, tenant):
tenant_ref = self._normalize_dict(tenant)
validation.lazy_validate(schema.tenant_create, tenant)
self.assert_admin(request)
self.resource_api.ensure_default_domain_exists()
tenant_ref['id'] = tenant_ref.get('id', uuid.uuid4().hex)
tenant = self.resource_api.create_project(
tenant_ref['id'],
self._normalize_domain_id(request, tenant_ref),
initiator=request.audit_initiator)
return {'tenant': self.v3_to_v2_project(tenant)}
@controller.v2_deprecated
def update_project(self, request, tenant_id, tenant):
validation.lazy_validate(schema.tenant_update, tenant)
self.assert_admin(request)
self._assert_not_is_domain_project(tenant_id)
tenant_ref = self.resource_api.update_project(
tenant_id, tenant, initiator=request.audit_initiator)
return {'tenant': self.v3_to_v2_project(tenant_ref)}
@controller.v2_deprecated
def delete_project(self, request, tenant_id):
self.assert_admin(request)
self._assert_not_is_domain_project(tenant_id)
self.resource_api.delete_project(
tenant_id,
initiator=request.audit_initiator
)
@dependency.requires('resource_api')
class DomainV3(controller.V3Controller):
collection_name = 'domains'

View File

@ -21,20 +21,6 @@ from keystone.common import wsgi
from keystone.resource import controllers
class Admin(wsgi.ComposableRouter):
def add_routes(self, mapper):
# Tenant Operations
tenant_controller = controllers.Tenant()
mapper.connect('/tenants',
controller=tenant_controller,
action='get_all_projects',
conditions=dict(method=['GET']))
mapper.connect('/tenants/{tenant_id}',
controller=tenant_controller,
action='get_project',
conditions=dict(method=['GET']))
class Routers(wsgi.RoutersBase):
def append_v3_routers(self, mapper, routers):

View File

@ -918,34 +918,6 @@ class V2Notifications(BaseNotificationTest):
'user',
cadftaxonomy.SECURITY_ACCOUNT_USER)
def test_project(self):
token = self.get_scoped_token()
resp = self.admin_request(
method='POST',
path='/v2.0/tenants',
body={
'tenant': {
'name': uuid.uuid4().hex,
'description': uuid.uuid4().hex,
'enabled': True
},
},
token=token,
)
project_id = resp.result.get('tenant').get('id')
self._assert_initiator_data_is_set(CREATED_OPERATION,
'project',
cadftaxonomy.SECURITY_PROJECT)
# test for delete project
self.admin_request(
method='DELETE',
path='/v2.0/tenants/%s' % project_id,
token=token,
)
self._assert_initiator_data_is_set(DELETED_OPERATION,
'project',
cadftaxonomy.SECURITY_PROJECT)
class TestEventCallbacks(test_v3.RestfulTestCase):

View File

@ -1,57 +0,0 @@
# 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
import keystone.conf
from keystone import exception
from keystone.resource import controllers
from keystone.tests import unit
from keystone.tests.unit.ksfixtures import database
CONF = keystone.conf.CONF
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.
req = self.make_request(is_admin=True)
res = self.tenant_controller.get_all_projects(req)
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(self.make_request(is_admin=True),
tenant)
# If the above doesn't fail then this is successful.

View File

@ -55,7 +55,7 @@ class TestNoAdminTokenAuth(unit.TestCase):
# Note(blk-u): Picked /v2.0/tenants because it's an operation that
# requires is_admin in the context, any operation that requires
# is_admin would work for this test.
REQ_PATH = '/v2.0/tenants'
REQ_PATH = '/v2.0/users'
# If the following does not raise, then the test is successful.
self.admin_app.get(REQ_PATH, headers={'X-Auth-Token': 'NotAdminToken'},

View File

@ -148,11 +148,6 @@ class CoreApiTests(object):
expected_status=http_client.OK)
self.assertValidAuthenticationResponse(r)
def test_get_tenants_for_token(self):
r = self.public_request(path='/v2.0/tenants',
token=self.get_scoped_token())
self.assertValidTenantListResponse(r)
def test_validate_token(self):
token = self.get_scoped_token()
r = self.admin_request(
@ -245,24 +240,6 @@ class CoreApiTests(object):
token=token)
self.assertValidEndpointListResponse(r)
def test_get_tenant(self):
token = self.get_scoped_token()
r = self.admin_request(
path='/v2.0/tenants/%(tenant_id)s' % {
'tenant_id': self.tenant_bar['id'],
},
token=token)
self.assertValidTenantResponse(r)
def test_get_tenant_by_name(self):
token = self.get_scoped_token()
r = self.admin_request(
path='/v2.0/tenants?name=%(tenant_name)s' % {
'tenant_name': self.tenant_bar['name'],
},
token=token)
self.assertValidTenantResponse(r)
def test_get_user(self):
token = self.get_scoped_token()
r = self.admin_request(

View File

@ -1,153 +0,0 @@
# Copyright 2014 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 testtools import matchers
from keystone.assignment import controllers as assignment_controllers
from keystone import exception
from keystone.resource import controllers as resource_controllers
from keystone.tests import unit
from keystone.tests.unit import default_fixtures
from keystone.tests.unit.ksfixtures import database
class TenantTestCase(unit.TestCase):
"""Test for the V2 Tenant controller.
These tests exercise :class:`keystone.assignment.controllers.Tenant`.
"""
def setUp(self):
super(TenantTestCase, self).setUp()
self.useFixture(database.Database())
self.load_backends()
self.load_fixtures(default_fixtures)
self.tenant_controller = resource_controllers.Tenant()
self.assignment_tenant_controller = (
assignment_controllers.TenantAssignment())
def test_list_projects_default_domain(self):
"""Test that list projects only returns those in the default domain."""
domain = unit.new_domain_ref()
self.resource_api.create_domain(domain['id'], domain)
project1 = unit.new_project_ref(domain_id=domain['id'])
self.resource_api.create_project(project1['id'], project1)
# Check the real total number of projects, we should have the:
# - tenants in the default fixtures
# - the project representing the default domain
# - the project representing the domain we created above
# - the project we created above
refs = self.resource_api.list_projects()
self.assertThat(
refs, matchers.HasLength(len(default_fixtures.TENANTS) + 3))
# Now list all projects using the v2 API - we should only get
# back those in the default features, since only those are in the
# default domain.
refs = self.tenant_controller.get_all_projects(
self.make_request(is_admin=True))
self.assertEqual(len(default_fixtures.TENANTS), len(refs['tenants']))
for tenant in default_fixtures.TENANTS:
tenant_copy = tenant.copy()
tenant_copy.pop('domain_id')
tenant_copy.pop('parent_id')
tenant_copy.pop('is_domain')
self.assertIn(tenant_copy, refs['tenants'])
def _create_is_domain_project(self):
project = unit.new_project_ref(is_domain=True)
project_ref = self.resource_api.create_project(project['id'], project)
return self.tenant_controller.v3_to_v2_project(project_ref)
def test_get_is_domain_project_not_found(self):
"""Test that get project does not return is_domain projects."""
project = self._create_is_domain_project()
request = self.make_request(is_admin=True,
query_string='name=%s' % project['name'])
self.assertRaises(
exception.ProjectNotFound,
self.tenant_controller.get_all_projects,
request)
request = self.make_request(is_admin=True,
query_string='name=%s' % project['id'])
self.assertRaises(
exception.ProjectNotFound,
self.tenant_controller.get_all_projects,
request)
def test_create_is_domain_project_fails(self):
"""Test that the creation of a project acting as a domain fails."""
project = {'name': uuid.uuid4().hex, 'domain_id': 'default',
'is_domain': True}
self.assertRaises(
exception.ValidationError,
self.tenant_controller.create_project,
self.make_request(is_admin=True),
project)
def test_create_project_passing_is_domain_false_fails(self):
"""Test that passing is_domain=False is not allowed."""
project = {'name': uuid.uuid4().hex, 'domain_id': 'default',
'is_domain': False}
self.assertRaises(
exception.ValidationError,
self.tenant_controller.create_project,
self.make_request(is_admin=True),
project)
def test_update_is_domain_project_not_found(self):
"""Test that update is_domain project is not allowed in v2."""
project = self._create_is_domain_project()
project['name'] = uuid.uuid4().hex
self.assertRaises(
exception.ProjectNotFound,
self.tenant_controller.update_project,
self.make_request(is_admin=True),
project['id'],
project)
def test_delete_is_domain_project_not_found(self):
"""Test that delete is_domain project is not allowed in v2."""
project = self._create_is_domain_project()
self.assertRaises(
exception.ProjectNotFound,
self.tenant_controller.delete_project,
self.make_request(is_admin=True),
project['id'])
def test_list_is_domain_project_not_found(self):
"""Test v2 get_all_projects having projects that act as a domain.
In v2 no project with the is_domain flag enabled should be returned.
"""
project1 = self._create_is_domain_project()
project2 = self._create_is_domain_project()
refs = self.tenant_controller.get_all_projects(
self.make_request(is_admin=True))
projects = refs.get('tenants')
self.assertNotIn(project1, projects)
self.assertNotIn(project2, projects)

View File

@ -1708,9 +1708,9 @@ class TokenAPITests(object):
'/auth/tokens', headers={'X-Subject-Token': v2_token})
# Attempting to use the deleted token on v2 should fail.
self.admin_request(
path='/v2.0/tenants', method='GET', token=v2_token,
expected_status=http_client.UNAUTHORIZED)
self._validate_token_v2(
v2_token, expected_status=http_client.NOT_FOUND
)
def test_rescoping_token(self):
expires = self.v3_token_data['token']['expires_at']

View File

@ -16,7 +16,6 @@ from keystone import assignment
from keystone.common import extension
from keystone.common import wsgi
from keystone import identity
from keystone import resource
extension.register_admin_extension(
@ -46,27 +45,11 @@ class Router(wsgi.ComposableRouter):
"""
def add_routes(self, mapper):
tenant_controller = resource.controllers.Tenant()
assignment_tenant_controller = (
assignment.controllers.TenantAssignment())
user_controller = identity.controllers.User()
# Tenant Operations
mapper.connect(
'/tenants',
controller=tenant_controller,
action='create_project',
conditions=dict(method=['POST']))
mapper.connect(
'/tenants/{tenant_id}',
controller=tenant_controller,
action='update_project',
conditions=dict(method=['PUT', 'POST']))
mapper.connect(
'/tenants/{tenant_id}',
controller=tenant_controller,
action='delete_project',
conditions=dict(method=['DELETE']))
mapper.connect(
'/tenants/{tenant_id}/users',
controller=assignment_tenant_controller,

View File

@ -97,7 +97,6 @@ def admin_app_factory(global_conf, **local_conf):
return wsgi.ComposingRouter(routes.Mapper(),
[identity_routers.Admin(),
token_routers.Router(),
resource_routers.Admin(),
admin_crud.Router(),
routers.VersionV2('admin'),
routers.Extension()])