Merge "Combine aggregate_forward and search_forward"
This commit is contained in:
commit
749de86ac5
|
@ -116,16 +116,11 @@ class RequestHandler(object):
|
|||
abort(400)
|
||||
|
||||
mapping = None
|
||||
aggregate = False
|
||||
|
||||
if self.details['resource_id']:
|
||||
mapping = model.ResourceMapping.find(
|
||||
resource_type=self.details['action'][0],
|
||||
resource_id=self.details['resource_id'])
|
||||
else:
|
||||
if (self.details['method'] == 'GET' and
|
||||
self.details['action'][0] in RESOURCES_AGGREGATE):
|
||||
aggregate = True
|
||||
|
||||
LOG.debug('Local Token: %s ' % self.details['token'])
|
||||
|
||||
|
@ -142,15 +137,13 @@ class RequestHandler(object):
|
|||
self.details['token']
|
||||
)[0]
|
||||
self._forward = self._targeted_forward
|
||||
elif aggregate:
|
||||
self._forward = self._aggregate_forward
|
||||
elif mapping:
|
||||
# Which we already know the location of, use that SP.
|
||||
self.service_provider = mapping.resource_sp
|
||||
self.project_id = mapping.project_id
|
||||
self._forward = self._targeted_forward
|
||||
else:
|
||||
self._forward = self._search_forward
|
||||
self._forward = self._forward
|
||||
|
||||
LOG.info(format_for_log(title="Request to proxy",
|
||||
method=self.details['method'],
|
||||
|
@ -198,7 +191,6 @@ class RequestHandler(object):
|
|||
headers=headers))
|
||||
LOG.info(format_for_log(title='Response to proxy',
|
||||
status_code=resp.status_code,
|
||||
url=resp.url,
|
||||
headers=resp.headers))
|
||||
return resp
|
||||
|
||||
|
@ -215,7 +207,6 @@ class RequestHandler(object):
|
|||
)
|
||||
LOG.info(format_for_log(title='Response from proxy',
|
||||
status_code=final_response.status_code,
|
||||
url=response.url,
|
||||
headers=dict(final_response.headers)))
|
||||
return final_response
|
||||
|
||||
|
@ -226,26 +217,48 @@ class RequestHandler(object):
|
|||
return self._finalize(
|
||||
self._do_request_on(self.service_provider, self.project_id))
|
||||
|
||||
def _search_forward(self):
|
||||
if not CONF.search_by_broadcast:
|
||||
def _forward(self):
|
||||
if self.fallback_to_local:
|
||||
return self._local_forward()
|
||||
|
||||
responses = {}
|
||||
errors = collections.defaultdict(lambda: [])
|
||||
|
||||
for sp in self.enabled_sps:
|
||||
if sp == 'default':
|
||||
response = self._do_request_on('default')
|
||||
if 200 <= response.status_code < 300:
|
||||
return self._finalize(response)
|
||||
r = self._do_request_on('default')
|
||||
if 200 <= r.status_code < 300:
|
||||
responses['default'] = r
|
||||
if not self.aggregate:
|
||||
return self._finalize(r)
|
||||
else:
|
||||
errors[response.status_code].append(response)
|
||||
errors[r.status_code].append(r)
|
||||
else:
|
||||
self.service_provider = sp
|
||||
for p in auth.get_projects_at_sp(sp, self.details['token']):
|
||||
response = self._do_request_on(sp, p)
|
||||
if 200 <= response.status_code < 300:
|
||||
return self._finalize(response)
|
||||
r = self._do_request_on(sp, p)
|
||||
if 200 <= r.status_code < 300:
|
||||
responses[(sp, p)] = r
|
||||
if not self.aggregate:
|
||||
return self._finalize(r)
|
||||
else:
|
||||
errors[response.status_code].append(response)
|
||||
errors[r.status_code].append(r)
|
||||
|
||||
# NOTE(knikolla): If we haven't returned yet, either we're aggregating
|
||||
# or there are errors.
|
||||
if not errors:
|
||||
# TODO(knikolla): Plug this into _finalize to have a common path
|
||||
# for everything that is returned.
|
||||
return flask.Response(
|
||||
services.aggregate(responses,
|
||||
self.details['action'][0],
|
||||
self.details['service'],
|
||||
version=self.details['version'],
|
||||
params=request.args.to_dict(),
|
||||
path=request.base_url,
|
||||
strip_details=self.strip_details),
|
||||
200,
|
||||
content_type='application/json'
|
||||
)
|
||||
|
||||
if six.viewkeys(errors) == {404}:
|
||||
return self._finalize(errors[404][0])
|
||||
|
@ -258,31 +271,6 @@ class RequestHandler(object):
|
|||
# TODO(jfreud): log
|
||||
return flask.Response("Something strange happened.\n", 500)
|
||||
|
||||
def _aggregate_forward(self):
|
||||
if not CONF.aggregation:
|
||||
return self._local_forward()
|
||||
|
||||
responses = {}
|
||||
|
||||
for sp in self.enabled_sps:
|
||||
if sp == 'default':
|
||||
responses['default'] = self._do_request_on('default')
|
||||
else:
|
||||
for proj in auth.get_projects_at_sp(sp, self.details['token']):
|
||||
responses[(sp, proj)] = self._do_request_on(sp, proj)
|
||||
|
||||
return flask.Response(
|
||||
services.aggregate(responses,
|
||||
self.details['action'][0],
|
||||
self.details['service'],
|
||||
version=self.details['version'],
|
||||
params=request.args.to_dict(),
|
||||
path=request.base_url,
|
||||
strip_details=self.strip_details),
|
||||
200,
|
||||
content_type='application/json'
|
||||
)
|
||||
|
||||
def _list_api_versions(self):
|
||||
return services.list_api_versions(self.details['service'],
|
||||
request.base_url)
|
||||
|
@ -316,15 +304,28 @@ class RequestHandler(object):
|
|||
args.pop('marker', None)
|
||||
return args
|
||||
|
||||
@property
|
||||
@utils.CachedProperty
|
||||
def chunked(self):
|
||||
encoding = self.details['headers'].get('Transfer-Encoding', '')
|
||||
return encoding.lower() == 'chunked'
|
||||
|
||||
@property
|
||||
@utils.CachedProperty
|
||||
def stream(self):
|
||||
return True if self.details['method'] in ['GET'] else False
|
||||
|
||||
@utils.CachedProperty
|
||||
def fallback_to_local(self):
|
||||
"""Return true if can't aggregate or search."""
|
||||
return ((self.aggregate and not CONF.aggregation) or
|
||||
(not self.aggregate and not CONF.search_by_broadcast))
|
||||
|
||||
@utils.CachedProperty
|
||||
def aggregate(self):
|
||||
"""Return true if this is a case where we should aggregate."""
|
||||
return (not self.details['resource_id'] and
|
||||
self.details['method'] == 'GET' and
|
||||
self.details['action'][0] in RESOURCES_AGGREGATE)
|
||||
|
||||
def _set_strip_details(self, details):
|
||||
# if request is to /volumes, change it
|
||||
# to /volumes/detail for aggregation
|
||||
|
|
|
@ -15,6 +15,36 @@
|
|||
import uuid
|
||||
|
||||
|
||||
class CachedProperty(object):
|
||||
"""A decorator that converts a function into a lazy property.
|
||||
|
||||
Taken from : https://github.com/nshah/python-memoize
|
||||
The function wrapped is called the first time to retrieve the result
|
||||
and then that calculated result is used the next time you access
|
||||
the value:
|
||||
|
||||
class Foo(object):
|
||||
|
||||
@CachedProperty
|
||||
def bar(self):
|
||||
# calculate something important here
|
||||
return 42
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, func, name=None, doc=None):
|
||||
self.func = func
|
||||
self.__name__ = name or func.__name__
|
||||
self.__doc__ = doc or func.__doc__
|
||||
|
||||
def __get__(self, obj, owner):
|
||||
if obj is None:
|
||||
return self
|
||||
value = self.func(obj)
|
||||
setattr(obj, self.__name__, value)
|
||||
return value
|
||||
|
||||
|
||||
def safe_get(a, i, default=None):
|
||||
"""Return the i-th element if it exists, or default."""
|
||||
try:
|
||||
|
|
Loading…
Reference in New Issue