Log exception generated in Controller.prepare_request_body

While implementing some Neutron extension, I noticed that whenever a parameter
that is expected by the API is not entered, we receive an internal error
message. However, from the user/operator/dev calling the API, it might not be
clear what the error is. Therefore, we should at least, log these validation
errors.

This patch proposes to enclose the call to Controller.prepare_request_body with
a try/except block, and then we log the exception in warning level. After
logging the exception, we raise it to allow the normal execution flow to
continue.

Change-Id: I855442ee8c0c4b4f0aff19968a5db07fca898146
This commit is contained in:
Rafael Weingärtner 2020-08-13 09:42:34 -03:00
parent 114ac0ae89
commit 2f0c352973
3 changed files with 60 additions and 25 deletions

View File

@ -440,10 +440,15 @@ class Controller(object):
def _create(self, request, body, **kwargs): def _create(self, request, body, **kwargs):
"""Creates a new instance of the requested entity.""" """Creates a new instance of the requested entity."""
parent_id = kwargs.get(self._parent_id_name) parent_id = kwargs.get(self._parent_id_name)
body = Controller.prepare_request_body(request.context, try:
body, True, body = Controller.prepare_request_body(
self._resource, self._attr_info, request.context, body, True, self._resource, self._attr_info,
allow_bulk=self._allow_bulk) allow_bulk=self._allow_bulk)
except Exception as e:
LOG.warning("An exception happened while processing the request "
"body. The exception message is [%s].", e)
raise e
action = self._plugin_handlers[self.CREATE] action = self._plugin_handlers[self.CREATE]
# Check authz # Check authz
if self._collection in body: if self._collection in body:
@ -626,10 +631,15 @@ class Controller(object):
@db_api.retry_db_errors @db_api.retry_db_errors
def _update(self, request, id, body, **kwargs): def _update(self, request, id, body, **kwargs):
body = Controller.prepare_request_body(request.context, try:
body, False, body = Controller.prepare_request_body(
self._resource, self._attr_info, request.context, body, False, self._resource, self._attr_info,
allow_bulk=self._allow_bulk) allow_bulk=self._allow_bulk)
except Exception as e:
LOG.warning("An exception happened while processing the request "
"body. The exception message is [%s].", e)
raise e
action = self._plugin_handlers[self.UPDATE] action = self._plugin_handlers[self.UPDATE]
# Load object to check authz # Load object to check authz
# but pass only attributes in the original body and required # but pass only attributes in the original body and required
@ -724,13 +734,20 @@ class Controller(object):
"not supported")) "not supported"))
if not body[collection]: if not body[collection]:
raise webob.exc.HTTPBadRequest(_("Resources required")) raise webob.exc.HTTPBadRequest(_("Resources required"))
bulk_body = [ try:
Controller.prepare_request_body( bulk_body = [
context, item if resource in item Controller.prepare_request_body(
else {resource: item}, is_create, resource, attr_info, context, item if resource in item
allow_bulk) for item in body[collection] else {resource: item}, is_create, resource,
] attr_info, allow_bulk) for item in body[collection]
return {collection: bulk_body} ]
return {collection: bulk_body}
except Exception as e:
LOG.warning(
"An exception happened while processing the request "
"body. The exception message is [%s].", e)
raise e
res_dict = body.get(resource) res_dict = body.get(resource)
except (AttributeError, TypeError): except (AttributeError, TypeError):
msg = _("Body contains invalid data") msg = _("Body contains invalid data")

View File

@ -20,6 +20,7 @@ from neutron_lib.db import constants as const
from neutron_lib import exceptions from neutron_lib import exceptions
from neutron_lib.plugins import directory from neutron_lib.plugins import directory
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import importutils from oslo_utils import importutils
import webob import webob
@ -41,6 +42,7 @@ DB_QUOTA_DRIVER = 'neutron.db.quota.driver.DbQuotaDriver'
EXTENDED_ATTRIBUTES_2_0 = { EXTENDED_ATTRIBUTES_2_0 = {
RESOURCE_COLLECTION: {} RESOURCE_COLLECTION: {}
} }
LOG = logging.getLogger(__name__)
def validate_policy(context, policy_name): def validate_policy(context, policy_name):
@ -118,9 +120,15 @@ class QuotaSetsController(wsgi.Controller):
validate_policy(request.context, "update_quota") validate_policy(request.context, "update_quota")
if self._update_extended_attributes: if self._update_extended_attributes:
self._update_attributes() self._update_attributes()
body = base.Controller.prepare_request_body( try:
request.context, body, False, self._resource_name, body = base.Controller.prepare_request_body(
EXTENDED_ATTRIBUTES_2_0[RESOURCE_COLLECTION]) request.context, body, False, self._resource_name,
EXTENDED_ATTRIBUTES_2_0[RESOURCE_COLLECTION])
except Exception as e:
LOG.warning(
"An exception happened while processing the request "
"body. The exception message is [%s].", e)
raise e
for key, value in body[self._resource_name].items(): for key, value in body[self._resource_name].items():
self._driver.update_quota_limit(request.context, id, key, value) self._driver.update_quota_limit(request.context, id, key, value)
return {self._resource_name: self._get_quotas(request, id)} return {self._resource_name: self._get_quotas(request, id)}

View File

@ -13,7 +13,9 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from oslo_log import log as logging
from oslo_serialization import jsonutils from oslo_serialization import jsonutils
from pecan import hooks from pecan import hooks
import webob.exc import webob.exc
@ -21,6 +23,8 @@ from neutron._i18n import _
from neutron.api.v2 import base as v2_base from neutron.api.v2 import base as v2_base
from neutron.pecan_wsgi.hooks import utils from neutron.pecan_wsgi.hooks import utils
LOG = logging.getLogger(__name__)
class BodyValidationHook(hooks.PecanHook): class BodyValidationHook(hooks.PecanHook):
@ -53,13 +57,19 @@ class BodyValidationHook(hooks.PecanHook):
return return
# Prepare data to be passed to the plugin from request body # Prepare data to be passed to the plugin from request body
controller = utils.get_controller(state) controller = utils.get_controller(state)
data = v2_base.Controller.prepare_request_body( try:
neutron_context, data = v2_base.Controller.prepare_request_body(
json_data, neutron_context,
is_create, json_data,
resource, is_create,
controller.resource_info, resource,
allow_bulk=is_create) controller.resource_info,
allow_bulk=is_create)
except Exception as e:
LOG.warning("An exception happened while processing the request "
"body. The exception message is [%s].", e)
raise e
if collection in data: if collection in data:
state.request.context['resources'] = [item[resource] for item in state.request.context['resources'] = [item[resource] for item in
data[collection]] data[collection]]