e41893c9d0
This change addresses nit-level review comments from this task. Story: 1651346 Task: 10551 Change-Id: I01608004ce90facadb73e252203900a1e62cbea1
141 lines
4.3 KiB
Python
141 lines
4.3 KiB
Python
#
|
|
# Copyright 2015 Rackspace, Inc
|
|
# All Rights Reserved
|
|
#
|
|
# 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 functools
|
|
from http import client as http_client
|
|
import json
|
|
import sys
|
|
import traceback
|
|
|
|
from oslo_config import cfg
|
|
from oslo_log import log
|
|
import pecan
|
|
|
|
LOG = log.getLogger(__name__)
|
|
|
|
|
|
pecan_json_decorate = pecan.expose(
|
|
content_type='application/json',
|
|
generic=False)
|
|
|
|
|
|
def expose(status_code=None):
|
|
|
|
def decorate(f):
|
|
|
|
@functools.wraps(f)
|
|
def callfunction(self, *args, **kwargs):
|
|
try:
|
|
result = f(self, *args, **kwargs)
|
|
if status_code:
|
|
pecan.response.status = status_code
|
|
|
|
except Exception:
|
|
try:
|
|
exception_info = sys.exc_info()
|
|
orig_exception = exception_info[1]
|
|
orig_code = getattr(orig_exception, 'code', None)
|
|
result = format_exception(
|
|
exception_info,
|
|
cfg.CONF.debug_tracebacks_in_api
|
|
)
|
|
finally:
|
|
del exception_info
|
|
|
|
if orig_code and orig_code in http_client.responses:
|
|
pecan.response.status = orig_code
|
|
else:
|
|
pecan.response.status = 500
|
|
|
|
def _empty():
|
|
# This is for a pecan workaround originally in WSME,
|
|
# but the original issue description is in an issue tracker
|
|
# that is now offline
|
|
pecan.request.pecan['content_type'] = None
|
|
pecan.response.content_type = None
|
|
|
|
# never return content for NO_CONTENT
|
|
if pecan.response.status_code == 204:
|
|
return _empty()
|
|
|
|
# don't encode None for ACCEPTED responses
|
|
if result is None and pecan.response.status_code == 202:
|
|
return _empty()
|
|
|
|
return json.dumps(result)
|
|
|
|
pecan_json_decorate(callfunction)
|
|
return callfunction
|
|
|
|
return decorate
|
|
|
|
|
|
def body(body_arg):
|
|
"""Decorator which places HTTP request body JSON into a method argument
|
|
|
|
:param body_arg: Name of argument to populate with body JSON
|
|
"""
|
|
|
|
def inner_function(function):
|
|
|
|
@functools.wraps(function)
|
|
def inner_body(*args, **kwargs):
|
|
|
|
if pecan.request.body:
|
|
data = pecan.request.json
|
|
else:
|
|
data = {}
|
|
if isinstance(data, dict):
|
|
# remove any keyword arguments which pecan has
|
|
# extracted from the body
|
|
for field in data.keys():
|
|
kwargs.pop(field, None)
|
|
|
|
kwargs[body_arg] = data
|
|
|
|
return function(*args, **kwargs)
|
|
return inner_body
|
|
return inner_function
|
|
|
|
|
|
def format_exception(excinfo, debug=False):
|
|
"""Extract informations that can be sent to the client."""
|
|
error = excinfo[1]
|
|
code = getattr(error, 'code', None)
|
|
if code and code in http_client.responses and (400 <= code < 500):
|
|
faultstring = (error.faultstring if hasattr(error, 'faultstring')
|
|
else str(error))
|
|
faultcode = getattr(error, 'faultcode', 'Client')
|
|
r = dict(faultcode=faultcode,
|
|
faultstring=faultstring)
|
|
LOG.debug("Client-side error: %s", r['faultstring'])
|
|
r['debuginfo'] = None
|
|
return r
|
|
else:
|
|
faultstring = str(error)
|
|
debuginfo = "\n".join(traceback.format_exception(*excinfo))
|
|
|
|
LOG.error('Server-side error: "%s". Detail: \n%s',
|
|
faultstring, debuginfo)
|
|
|
|
faultcode = getattr(error, 'faultcode', 'Server')
|
|
r = dict(faultcode=faultcode, faultstring=faultstring)
|
|
if debug:
|
|
r['debuginfo'] = debuginfo
|
|
else:
|
|
r['debuginfo'] = None
|
|
return r
|