Merge "Pecan: bind attribute map to controllers"
This commit is contained in:
commit
d36dfb2ecc
|
@ -68,6 +68,10 @@ class Controller(object):
|
|||
def resource(self):
|
||||
return self._resource
|
||||
|
||||
@property
|
||||
def attr_info(self):
|
||||
return self._attr_info
|
||||
|
||||
def __init__(self, plugin, collection, resource, attr_info,
|
||||
allow_bulk=False, member_actions=None, parent=None,
|
||||
allow_pagination=False, allow_sorting=False):
|
||||
|
|
|
@ -269,6 +269,7 @@ class NeutronManager(object):
|
|||
|
||||
@classmethod
|
||||
def get_controller_for_resource(cls, resource):
|
||||
resource = resource.replace('_', '-')
|
||||
res_ctrl_mappings = cls.get_instance().resource_controller_mappings
|
||||
# If no controller is found for resource, try replacing dashes with
|
||||
# underscores
|
||||
|
|
|
@ -27,13 +27,14 @@ LOG = logging.getLogger(__name__)
|
|||
|
||||
class ItemController(utils.NeutronPecanController):
|
||||
|
||||
def __init__(self, resource, item):
|
||||
super(ItemController, self).__init__(None, resource)
|
||||
def __init__(self, resource, item, plugin=None, resource_info=None):
|
||||
super(ItemController, self).__init__(None, resource, plugin=plugin,
|
||||
resource_info=resource_info)
|
||||
self.item = item
|
||||
|
||||
@utils.expose(generic=True)
|
||||
def index(self, *args, **kwargs):
|
||||
return self.get()
|
||||
return self.get(*args, **kwargs)
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
getter = getattr(self.plugin, 'get_%s' % self.resource)
|
||||
|
@ -89,7 +90,9 @@ class CollectionsController(utils.NeutronPecanController):
|
|||
request.context['resource_id'] = item
|
||||
uri_identifier = '%s_id' % self.resource
|
||||
request.context['uri_identifiers'][uri_identifier] = item
|
||||
return self.item_controller_class(self.resource, item), remainder
|
||||
return (self.item_controller_class(
|
||||
self.resource, item, resource_info=self.resource_info),
|
||||
remainder)
|
||||
|
||||
@utils.expose(generic=True)
|
||||
def index(self, *args, **kwargs):
|
||||
|
@ -101,7 +104,7 @@ class CollectionsController(utils.NeutronPecanController):
|
|||
_listify = lambda x: x if isinstance(x, list) else [x]
|
||||
filters = api_common.get_filters_from_dict(
|
||||
{k: _listify(v) for k, v in kwargs.items()},
|
||||
self._resource_info,
|
||||
self.resource_info,
|
||||
skips=['fields', 'sort_key', 'sort_dir',
|
||||
'limit', 'marker', 'page_reverse'])
|
||||
lister = getattr(self.plugin, 'get_%s' % self.collection)
|
||||
|
|
|
@ -87,18 +87,17 @@ def when(index, *args, **kwargs):
|
|||
|
||||
class NeutronPecanController(object):
|
||||
|
||||
def __init__(self, collection, resource, plugin=None):
|
||||
def __init__(self, collection, resource, plugin=None, resource_info=None):
|
||||
# Ensure dashes are always replaced with underscores
|
||||
self.collection = collection and collection.replace('-', '_')
|
||||
self.resource = resource and resource.replace('-', '_')
|
||||
self._resource_info = api_attributes.get_collection_info(
|
||||
self.collection)
|
||||
self._resource_info = resource_info
|
||||
self._plugin = plugin
|
||||
# Controllers for some resources that are not mapped to anything in
|
||||
# RESOURCE_ATTRIBUTE_MAP will not have anything in _resource_info
|
||||
if self._resource_info:
|
||||
if self.resource_info:
|
||||
self._mandatory_fields = set([field for (field, data) in
|
||||
self._resource_info.items() if
|
||||
self.resource_info.items() if
|
||||
data.get('required_by_policy')])
|
||||
else:
|
||||
self._mandatory_fields = set()
|
||||
|
@ -113,6 +112,13 @@ class NeutronPecanController(object):
|
|||
self.resource)
|
||||
return self._plugin
|
||||
|
||||
@property
|
||||
def resource_info(self):
|
||||
if not self._resource_info:
|
||||
self._resource_info = api_attributes.get_collection_info(
|
||||
self.collection)
|
||||
return self._resource_info
|
||||
|
||||
|
||||
class ShimRequest(object):
|
||||
|
||||
|
|
|
@ -17,8 +17,8 @@ from oslo_log import log
|
|||
from oslo_serialization import jsonutils
|
||||
from pecan import hooks
|
||||
|
||||
from neutron.api.v2 import attributes as v2_attributes
|
||||
from neutron.api.v2 import base as v2_base
|
||||
from neutron import manager
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
@ -51,12 +51,14 @@ 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)
|
||||
data = v2_base.Controller.prepare_request_body(
|
||||
neutron_context,
|
||||
json_data,
|
||||
is_create,
|
||||
resource,
|
||||
v2_attributes.get_collection_info(collection),
|
||||
controller.resource_info,
|
||||
allow_bulk=is_create)
|
||||
if collection in data:
|
||||
state.request.context['resources'] = [item[resource] for item in
|
||||
|
|
|
@ -21,7 +21,6 @@ from pecan import hooks
|
|||
import webob
|
||||
|
||||
from neutron._i18n import _
|
||||
from neutron.api.v2 import attributes as v2_attributes
|
||||
from neutron.common import constants as const
|
||||
from neutron.extensions import quotasv2
|
||||
from neutron import manager
|
||||
|
@ -36,8 +35,10 @@ def _custom_getter(resource, resource_id):
|
|||
return quota.get_tenant_quotas(resource_id)[quotasv2.RESOURCE_NAME]
|
||||
|
||||
|
||||
def fetch_resource(neutron_context, resource, resource_id):
|
||||
attrs = v2_attributes.get_resource_info(resource)
|
||||
def fetch_resource(neutron_context, collection, resource, resource_id):
|
||||
controller = manager.NeutronManager.get_controller_for_resource(
|
||||
collection)
|
||||
attrs = controller.resource_info
|
||||
if not attrs:
|
||||
# this isn't a request for a normal resource. it could be
|
||||
# an action like removing a network from a dhcp agent.
|
||||
|
@ -96,7 +97,7 @@ class PolicyHook(hooks.PecanHook):
|
|||
# Ops... this was a delete after all!
|
||||
item = {}
|
||||
resource_id = state.request.context.get('resource_id')
|
||||
resource_obj = fetch_resource(neutron_context,
|
||||
resource_obj = fetch_resource(neutron_context, collection,
|
||||
resource, resource_id)
|
||||
if resource_obj:
|
||||
original_resources.append(resource_obj)
|
||||
|
@ -196,8 +197,9 @@ class PolicyHook(hooks.PecanHook):
|
|||
"""
|
||||
attributes_to_exclude = []
|
||||
for attr_name in data.keys():
|
||||
attr_data = v2_attributes.get_resource_info(
|
||||
resource).get(attr_name)
|
||||
controller = manager.NeutronManager.get_controller_for_resource(
|
||||
collection)
|
||||
attr_data = controller.resource_info.get(attr_name)
|
||||
if attr_data and attr_data['is_visible']:
|
||||
if policy.check(
|
||||
context,
|
||||
|
|
|
@ -68,8 +68,9 @@ def initialize_all():
|
|||
if isinstance(legacy_controller, base.Controller):
|
||||
resource = legacy_controller.resource
|
||||
plugin = legacy_controller.plugin
|
||||
attr_info = legacy_controller.attr_info
|
||||
new_controller = res_ctrl.CollectionsController(
|
||||
collection, resource)
|
||||
collection, resource, resource_info=attr_info)
|
||||
manager.NeutronManager.set_plugin_for_resource(resource, plugin)
|
||||
if path_prefix:
|
||||
manager.NeutronManager.add_resource_for_path_prefix(
|
||||
|
|
|
@ -335,7 +335,7 @@ class TestNovaNotifierHook(test_functional.PecanFunctionalTest):
|
|||
# NOTE(kevinbenton): the original passed into the notifier does
|
||||
# not contain all of the fields of the object. Only those required
|
||||
# by the policy engine are included.
|
||||
orig = pe.fetch_resource(context.get_admin_context(),
|
||||
orig = pe.fetch_resource(context.get_admin_context(), 'networks',
|
||||
'network', network_id)
|
||||
response = self.app.put_json(
|
||||
'/v2.0/networks/%s.json' % network_id,
|
||||
|
@ -347,7 +347,7 @@ class TestNovaNotifierHook(test_functional.PecanFunctionalTest):
|
|||
orig, json_body)
|
||||
self.mock_notifier.reset_mock()
|
||||
|
||||
orig = pe.fetch_resource(context.get_admin_context(),
|
||||
orig = pe.fetch_resource(context.get_admin_context(), 'networks',
|
||||
'network', network_id)
|
||||
response = self.app.delete(
|
||||
'/v2.0/networks/%s.json' % network_id, headers=req_headers)
|
||||
|
|
Loading…
Reference in New Issue