Merge "Pecan: Find subresource controllers by parent"
This commit is contained in:
commit
de8c390dda
@ -82,8 +82,9 @@ class ItemController(utils.NeutronPecanController):
|
||||
@utils.expose()
|
||||
def _lookup(self, collection, *remainder):
|
||||
request.context['collection'] = collection
|
||||
collection_path = '/'.join([self.resource, collection])
|
||||
controller = manager.NeutronManager.get_controller_for_resource(
|
||||
collection)
|
||||
collection_path)
|
||||
if not controller:
|
||||
if collection not in self._member_actions:
|
||||
LOG.warning(_LW("No controller found for: %s - returning"
|
||||
@ -157,16 +158,17 @@ class CollectionsController(utils.NeutronPecanController):
|
||||
creator = self.plugin_bulk_creator
|
||||
key = self.collection
|
||||
data = {key: [{self.resource: res} for res in resources]}
|
||||
creator_kwargs = {self.collection: data}
|
||||
else:
|
||||
creator = self.plugin_creator
|
||||
key = self.resource
|
||||
data = {key: resources[0]}
|
||||
creator_kwargs = {self.resource: data}
|
||||
neutron_context = request.context['neutron_context']
|
||||
creator_args = [neutron_context]
|
||||
if 'parent_id' in request.context:
|
||||
creator_args.append(request.context['parent_id'])
|
||||
creator_args.append(data)
|
||||
return {key: creator(*creator_args)}
|
||||
if 'parent_id' in request.context and self._parent_id_name:
|
||||
creator_kwargs[self._parent_id_name] = request.context['parent_id']
|
||||
return {key: creator(*creator_args, **creator_kwargs)}
|
||||
|
||||
|
||||
class MemberActionController(ItemController):
|
||||
|
@ -127,8 +127,8 @@ class NeutronPecanController(object):
|
||||
|
||||
self.parent = parent_resource
|
||||
parent_resource = '_%s' % parent_resource if parent_resource else ''
|
||||
self._parent_id_name = ('%s_id' % parent_resource
|
||||
if parent_resource else None)
|
||||
self._parent_id_name = ('%s_id' % self.parent
|
||||
if self.parent else None)
|
||||
self._plugin_handlers = {
|
||||
self.LIST: 'get%s_%s' % (parent_resource, self.collection),
|
||||
self.SHOW: 'get%s_%s' % (parent_resource, self.resource)
|
||||
|
@ -18,7 +18,7 @@ from oslo_serialization import jsonutils
|
||||
from pecan import hooks
|
||||
|
||||
from neutron.api.v2 import base as v2_base
|
||||
from neutron import manager
|
||||
from neutron.pecan_wsgi.hooks import utils
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
@ -51,8 +51,7 @@ class BodyValidationHook(hooks.PecanHook):
|
||||
# member action is being processed or on agent scheduler operations
|
||||
return
|
||||
# Prepare data to be passed to the plugin from request body
|
||||
controller = manager.NeutronManager.get_controller_for_resource(
|
||||
collection)
|
||||
controller = utils.get_controller(state)
|
||||
data = v2_base.Controller.prepare_request_body(
|
||||
neutron_context,
|
||||
json_data,
|
||||
|
@ -59,7 +59,18 @@ def initialize_all():
|
||||
for ext_res in resources:
|
||||
path_prefix = ext_res.path_prefix.strip('/')
|
||||
collection = ext_res.collection
|
||||
if manager.NeutronManager.get_controller_for_resource(collection):
|
||||
# Retrieving the parent resource. It is expected the format of
|
||||
# the parent resource to be:
|
||||
# {'collection_name': 'name-of-collection',
|
||||
# 'member_name': 'name-of-resource'}
|
||||
# collection_name does not appear to be used in the legacy code
|
||||
# inside the controller logic, so we can assume we do not need it.
|
||||
parent = ext_res.parent or {}
|
||||
parent_resource = parent.get('member_name')
|
||||
collection_key = collection
|
||||
if parent_resource:
|
||||
collection_key = '/'.join([parent_resource, collection])
|
||||
if manager.NeutronManager.get_controller_for_resource(collection_key):
|
||||
# This is a collection that already has a pecan controller, we
|
||||
# do not need to do anything else
|
||||
continue
|
||||
@ -71,14 +82,6 @@ def initialize_all():
|
||||
plugin = legacy_controller.plugin
|
||||
attr_info = legacy_controller.attr_info
|
||||
member_actions = legacy_controller.member_actions
|
||||
# Retrieving the parent resource. It is expected the format of
|
||||
# the parent resource to be:
|
||||
# {'collection_name': 'name-of-collection',
|
||||
# 'member_name': 'name-of-resource'}
|
||||
# collection_name does not appear to be used in the legacy code
|
||||
# inside the controller logic, so we can assume we do not need it.
|
||||
parent = legacy_controller.parent or {}
|
||||
parent_resource = parent.get('member_name')
|
||||
new_controller = res_ctrl.CollectionsController(
|
||||
collection, resource, resource_info=attr_info,
|
||||
parent_resource=parent_resource, member_actions=member_actions)
|
||||
@ -93,7 +96,7 @@ def initialize_all():
|
||||
LOG.warning(_LW("Unknown controller type encountered %s. It will"
|
||||
"be ignored."), legacy_controller)
|
||||
manager.NeutronManager.set_controller_for_resource(
|
||||
collection, new_controller)
|
||||
collection_key, new_controller)
|
||||
|
||||
# Certain policy checks require that the extensions are loaded
|
||||
# and the RESOURCE_ATTRIBUTE_MAP populated before they can be
|
||||
|
@ -894,3 +894,45 @@ class TestMemberActionController(test_functional.PecanFunctionalTest):
|
||||
url = '/v2.0/{}/something/put_meh.json'.format(self.collection)
|
||||
resp = self.app.get(url, expect_errors=True)
|
||||
self.assertEqual(405, resp.status_int)
|
||||
|
||||
|
||||
class TestParentSubresourceController(test_functional.PecanFunctionalTest):
|
||||
def setUp(self):
|
||||
fake_ext = pecan_utils.FakeExtension()
|
||||
fake_plugin = pecan_utils.FakePlugin()
|
||||
plugins = {pecan_utils.FakePlugin.PLUGIN_TYPE: fake_plugin}
|
||||
new_extensions = {fake_ext.get_alias(): fake_ext}
|
||||
super(TestParentSubresourceController, self).setUp(
|
||||
service_plugins=plugins, extensions=new_extensions)
|
||||
policy.init()
|
||||
policy._ENFORCER.set_rules(
|
||||
oslo_policy.Rules.from_dict(
|
||||
{'get_fake_duplicate': '',
|
||||
'get_meh_meh_fake_duplicates': ''}),
|
||||
overwrite=False)
|
||||
self.addCleanup(policy.reset)
|
||||
hyphen_collection = pecan_utils.FakeExtension.HYPHENATED_COLLECTION
|
||||
self.collection = hyphen_collection.replace('_', '-')
|
||||
self.fake_collection = (pecan_utils.FakeExtension.
|
||||
FAKE_PARENT_SUBRESOURCE_COLLECTION)
|
||||
|
||||
def test_get_duplicate_parent_resource(self):
|
||||
url = '/v2.0/{}'.format(self.fake_collection)
|
||||
resp = self.app.get(url)
|
||||
self.assertEqual(200, resp.status_int)
|
||||
self.assertEqual({'fake_duplicates': [{'fake': 'fakeduplicates'}]},
|
||||
resp.json)
|
||||
|
||||
def test_get_duplicate_parent_resource_item(self):
|
||||
url = '/v2.0/{}/something'.format(self.fake_collection)
|
||||
resp = self.app.get(url)
|
||||
self.assertEqual(200, resp.status_int)
|
||||
self.assertEqual({'fake_duplicate': {'fake': 'something'}}, resp.json)
|
||||
|
||||
def test_get_parent_resource_and_duplicate_subresources(self):
|
||||
url = '/v2.0/{0}/something/{1}'.format(self.collection,
|
||||
self.fake_collection)
|
||||
resp = self.app.get(url)
|
||||
self.assertEqual(200, resp.status_int)
|
||||
self.assertEqual({'fake_duplicates': [{'fake': 'something'}]},
|
||||
resp.json)
|
||||
|
@ -109,23 +109,35 @@ class FakeExtension(extensions.ExtensionDescriptor):
|
||||
|
||||
HYPHENATED_RESOURCE = 'meh_meh'
|
||||
HYPHENATED_COLLECTION = HYPHENATED_RESOURCE + 's'
|
||||
FAKE_PARENT_SUBRESOURCE_COLLECTION = 'fake_duplicates'
|
||||
FAKE_SUB_RESOURCE_COLLECTION = 'fake_subresources'
|
||||
|
||||
RESOURCE_ATTRIBUTE_MAP = {
|
||||
'meh_mehs': {
|
||||
'fake': {'is_visible': True}
|
||||
},
|
||||
'fake_duplicates': {
|
||||
'fake': {'is_visible': True}
|
||||
}
|
||||
}
|
||||
|
||||
SUB_RESOURCE_ATTRIBUTE_MAP = {
|
||||
'fake_subresources': {
|
||||
'parent': {
|
||||
'collection_name': (
|
||||
HYPHENATED_COLLECTION),
|
||||
'member_name': HYPHENATED_RESOURCE},
|
||||
'meh_mehs'),
|
||||
'member_name': 'meh_meh'},
|
||||
'parameters': {'foo': {'is_visible': True},
|
||||
'bar': {'is_visible': True}
|
||||
}
|
||||
}
|
||||
}
|
||||
FAKE_SUB_RESOURCE_COLLECTION = 'fake_subresources'
|
||||
|
||||
RAM = {
|
||||
HYPHENATED_COLLECTION: {
|
||||
'fake': {'is_visible': True}
|
||||
},
|
||||
'fake_duplicates': {
|
||||
'parent': {
|
||||
'collection_name': (
|
||||
'meh_mehs'),
|
||||
'member_name': 'meh_meh'},
|
||||
'parameters': {'fake': {'is_visible': True}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,21 +158,26 @@ class FakeExtension(extensions.ExtensionDescriptor):
|
||||
return "meh"
|
||||
|
||||
def get_resources(self):
|
||||
collection = self.HYPHENATED_COLLECTION.replace('_', '-')
|
||||
params = self.RAM.get(self.HYPHENATED_COLLECTION, {})
|
||||
attributes.PLURALS.update({self.HYPHENATED_COLLECTION:
|
||||
self.HYPHENATED_RESOURCE})
|
||||
member_actions = {'put_meh': 'PUT', 'boo_meh': 'GET'}
|
||||
"""Returns Ext Resources."""
|
||||
resources = []
|
||||
fake_plugin = FakePlugin()
|
||||
controller = base.create_resource(
|
||||
collection, self.HYPHENATED_RESOURCE, FakePlugin(),
|
||||
params, allow_bulk=True, allow_pagination=True,
|
||||
allow_sorting=True, member_actions=member_actions)
|
||||
resources = [extensions.ResourceExtension(
|
||||
collection, controller, attr_map=params,
|
||||
member_actions=member_actions)]
|
||||
for collection_name in self.RESOURCE_ATTRIBUTE_MAP:
|
||||
resource_name = collection_name[:-1]
|
||||
params = self.RESOURCE_ATTRIBUTE_MAP.get(collection_name, {})
|
||||
attributes.PLURALS.update({collection_name: resource_name})
|
||||
member_actions = {'put_meh': 'PUT', 'boo_meh': 'GET'}
|
||||
if collection_name == self.HYPHENATED_COLLECTION:
|
||||
collection_name = collection_name.replace('_', '-')
|
||||
controller = base.create_resource(
|
||||
collection_name, resource_name, fake_plugin,
|
||||
params, allow_bulk=True, allow_pagination=True,
|
||||
allow_sorting=True, member_actions=member_actions)
|
||||
resource = extensions.ResourceExtension(
|
||||
collection_name, controller, attr_map=params)
|
||||
resources.append(resource)
|
||||
|
||||
for collection_name in self.SUB_RESOURCE_ATTRIBUTE_MAP:
|
||||
resource_name = collection_name
|
||||
resource_name = collection_name[:-1]
|
||||
parent = self.SUB_RESOURCE_ATTRIBUTE_MAP[collection_name].get(
|
||||
'parent')
|
||||
params = self.SUB_RESOURCE_ATTRIBUTE_MAP[collection_name].get(
|
||||
@ -170,7 +187,6 @@ class FakeExtension(extensions.ExtensionDescriptor):
|
||||
fake_plugin, params,
|
||||
allow_bulk=True,
|
||||
parent=parent)
|
||||
|
||||
resource = extensions.ResourceExtension(
|
||||
collection_name,
|
||||
controller, parent,
|
||||
@ -182,7 +198,7 @@ class FakeExtension(extensions.ExtensionDescriptor):
|
||||
|
||||
def get_extended_resources(self, version):
|
||||
if version == "2.0":
|
||||
return self.RAM
|
||||
return self.RESOURCE_ATTRIBUTE_MAP
|
||||
else:
|
||||
return {}
|
||||
|
||||
@ -202,6 +218,16 @@ class FakePlugin(object):
|
||||
def get_meh_mehs(self, context, filters=None, fields=None):
|
||||
return [{'fake': 'fake'}]
|
||||
|
||||
def get_fake_duplicate(self, context, id_, fields=None):
|
||||
return {'fake': id_}
|
||||
|
||||
def get_fake_duplicates(self, context, filters=None, fields=None):
|
||||
return [{'fake': 'fakeduplicates'}]
|
||||
|
||||
def get_meh_meh_fake_duplicates(self, context, id_, fields=None,
|
||||
filters=None):
|
||||
return [{'fake': id_}]
|
||||
|
||||
def get_meh_meh_fake_subresources(self, context, id_, fields=None,
|
||||
filters=None):
|
||||
return {'foo': id_}
|
||||
|
Loading…
Reference in New Issue
Block a user