Support filtering for execution query
Change-Id: Iab965386f57948d4c333dfadde589c76ea639764 Implements: blueprint qinling-execution-filter
This commit is contained in:
parent
a7496f4e16
commit
601410e119
43
example/functions/python/openstack/create_thumbnail.py
Normal file
43
example/functions/python/openstack/create_thumbnail.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
from PIL import Image
|
||||||
|
import swiftclient
|
||||||
|
|
||||||
|
|
||||||
|
def main(context, container, object):
|
||||||
|
conn = swiftclient.Connection(
|
||||||
|
session=context['os_session'],
|
||||||
|
os_options={'region_name': 'RegionOne'},
|
||||||
|
)
|
||||||
|
|
||||||
|
# obj_header = conn.head_object(container, object)
|
||||||
|
new_container = '%s_thumb' % container
|
||||||
|
|
||||||
|
# Download original photo
|
||||||
|
image_path = '/%s' % object
|
||||||
|
_, obj_contents = conn.get_object(container, object)
|
||||||
|
with open(image_path, 'w') as local:
|
||||||
|
local.write(obj_contents)
|
||||||
|
|
||||||
|
print('Downloaded object % from container %s' % (object, container))
|
||||||
|
|
||||||
|
# Resize
|
||||||
|
SIZE = (75, 75)
|
||||||
|
thumb_path = '/%s_thumb' % object
|
||||||
|
im = Image.open(image_path)
|
||||||
|
im.convert('RGB')
|
||||||
|
im.thumbnail(SIZE, Image.ANTIALIAS)
|
||||||
|
im.save(thumb_path, 'JPEG', quality=80)
|
||||||
|
|
||||||
|
print('Resized.')
|
||||||
|
|
||||||
|
# Upload thumb photo
|
||||||
|
with open(thumb_path, 'r') as new_local:
|
||||||
|
conn.put_object(
|
||||||
|
new_container,
|
||||||
|
object,
|
||||||
|
contents=new_local,
|
||||||
|
content_type='text/plain'
|
||||||
|
)
|
||||||
|
|
||||||
|
print('Uploaded object %s to container %s' % (object, new_container))
|
||||||
|
|
||||||
|
return True
|
@ -15,6 +15,7 @@
|
|||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
import pecan
|
import pecan
|
||||||
from pecan import rest
|
from pecan import rest
|
||||||
|
from wsme import types as wtypes
|
||||||
import wsmeext.pecan as wsme_pecan
|
import wsmeext.pecan as wsme_pecan
|
||||||
|
|
||||||
from qinling.api.controllers.v1 import resources
|
from qinling.api.controllers.v1 import resources
|
||||||
@ -61,12 +62,13 @@ class ExecutionsController(rest.RestController):
|
|||||||
return resources.Execution.from_dict(db_model.to_dict())
|
return resources.Execution.from_dict(db_model.to_dict())
|
||||||
|
|
||||||
@rest_utils.wrap_wsme_controller_exception
|
@rest_utils.wrap_wsme_controller_exception
|
||||||
@wsme_pecan.wsexpose(resources.Executions)
|
@wsme_pecan.wsexpose(resources.Executions, wtypes.text)
|
||||||
def get_all(self):
|
def get_all(self, function_id=None):
|
||||||
LOG.info("Get all %ss.", self.type)
|
filters = rest_utils.get_filters(function_id=function_id)
|
||||||
|
LOG.info("Get all %ss. filters=%s", self.type, filters)
|
||||||
|
|
||||||
executions = [resources.Execution.from_dict(db_model.to_dict())
|
executions = [resources.Execution.from_dict(db_model.to_dict())
|
||||||
for db_model in db_api.get_executions()]
|
for db_model in db_api.get_executions(**filters)]
|
||||||
|
|
||||||
return resources.Executions(executions=executions)
|
return resources.Executions(executions=executions)
|
||||||
|
|
||||||
|
@ -130,8 +130,8 @@ def get_execution(id):
|
|||||||
return IMPL.get_execution(id)
|
return IMPL.get_execution(id)
|
||||||
|
|
||||||
|
|
||||||
def get_executions():
|
def get_executions(**filters):
|
||||||
return IMPL.get_executions()
|
return IMPL.get_executions(**filters)
|
||||||
|
|
||||||
|
|
||||||
def delete_execution(id):
|
def delete_execution(id):
|
||||||
|
@ -70,6 +70,24 @@ class TestExecutionController(base.APITest):
|
|||||||
)
|
)
|
||||||
self._assertDictContainsSubset(actual, body)
|
self._assertDictContainsSubset(actual, body)
|
||||||
|
|
||||||
|
@mock.patch('qinling.rpc.EngineClient.create_execution')
|
||||||
|
def test_get_all_filter(self, mock_create_execution):
|
||||||
|
body = {
|
||||||
|
'function_id': self.func_id,
|
||||||
|
}
|
||||||
|
resp = self.app.post_json('/v1/executions', body)
|
||||||
|
exec_id = resp.json.get('id')
|
||||||
|
|
||||||
|
self.assertEqual(201, resp.status_int)
|
||||||
|
|
||||||
|
resp = self.app.get('/v1/executions?function_id=%s' % self.func_id)
|
||||||
|
|
||||||
|
self.assertEqual(200, resp.status_int)
|
||||||
|
actual = self._assert_single_item(
|
||||||
|
resp.json['executions'], id=exec_id
|
||||||
|
)
|
||||||
|
self._assertDictContainsSubset(actual, body)
|
||||||
|
|
||||||
@mock.patch('qinling.rpc.EngineClient.create_execution')
|
@mock.patch('qinling.rpc.EngineClient.create_execution')
|
||||||
def test_delete(self, mock_create_execution):
|
def test_delete(self, mock_create_execution):
|
||||||
body = {
|
body = {
|
||||||
|
@ -70,3 +70,86 @@ def wrap_pecan_controller_exception(func):
|
|||||||
)
|
)
|
||||||
|
|
||||||
return wrapped
|
return wrapped
|
||||||
|
|
||||||
|
|
||||||
|
def get_filters(**params):
|
||||||
|
"""Create filters from REST request parameters.
|
||||||
|
|
||||||
|
:param req_params: REST request parameters.
|
||||||
|
:return: filters dictionary.
|
||||||
|
"""
|
||||||
|
filters = {}
|
||||||
|
|
||||||
|
for column, data in params.items():
|
||||||
|
if data is not None:
|
||||||
|
if isinstance(data, six.string_types):
|
||||||
|
f_type, value = _extract_filter_type_and_value(data)
|
||||||
|
|
||||||
|
create_or_update_filter(column, value, f_type, filters)
|
||||||
|
else:
|
||||||
|
create_or_update_filter(column, data, _filter=filters)
|
||||||
|
|
||||||
|
return filters
|
||||||
|
|
||||||
|
|
||||||
|
def create_or_update_filter(column, value, filter_type='eq', _filter=None):
|
||||||
|
"""Create or Update filter.
|
||||||
|
|
||||||
|
:param column: Column name by which user want to filter.
|
||||||
|
:param value: Column value.
|
||||||
|
:param filter_type: filter type. Filter type can be
|
||||||
|
'eq', 'neq', 'gt', 'gte', 'lte', 'in',
|
||||||
|
'lt', 'nin'. Default is 'eq'.
|
||||||
|
:param _filter: Optional. If provided same filter dictionary will
|
||||||
|
be updated.
|
||||||
|
:return: filter dictionary.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if _filter is None:
|
||||||
|
_filter = {}
|
||||||
|
|
||||||
|
_filter[column] = {filter_type: value}
|
||||||
|
|
||||||
|
return _filter
|
||||||
|
|
||||||
|
|
||||||
|
def _extract_filter_type_and_value(data):
|
||||||
|
"""Extract filter type and its value from the data.
|
||||||
|
|
||||||
|
:param data: REST parameter value from which filter type and
|
||||||
|
value can be get. It should be in format of
|
||||||
|
'filter_type:value'.
|
||||||
|
:return: filter type and value.
|
||||||
|
"""
|
||||||
|
if data.startswith("in:"):
|
||||||
|
value = list(six.text_type(data[3:]).split(","))
|
||||||
|
filter_type = 'in'
|
||||||
|
elif data.startswith("nin:"):
|
||||||
|
value = list(six.text_type(data[4:]).split(","))
|
||||||
|
filter_type = 'nin'
|
||||||
|
elif data.startswith("neq:"):
|
||||||
|
value = six.text_type(data[4:])
|
||||||
|
filter_type = 'neq'
|
||||||
|
elif data.startswith("gt:"):
|
||||||
|
value = six.text_type(data[3:])
|
||||||
|
filter_type = 'gt'
|
||||||
|
elif data.startswith("gte:"):
|
||||||
|
value = six.text_type(data[4:])
|
||||||
|
filter_type = 'gte'
|
||||||
|
elif data.startswith("lt:"):
|
||||||
|
value = six.text_type(data[3:])
|
||||||
|
filter_type = 'lt'
|
||||||
|
elif data.startswith("lte:"):
|
||||||
|
value = six.text_type(data[4:])
|
||||||
|
filter_type = 'lte'
|
||||||
|
elif data.startswith("eq:"):
|
||||||
|
value = six.text_type(data[3:])
|
||||||
|
filter_type = 'eq'
|
||||||
|
elif data.startswith("has:"):
|
||||||
|
value = six.text_type(data[4:])
|
||||||
|
filter_type = 'has'
|
||||||
|
else:
|
||||||
|
value = data
|
||||||
|
filter_type = 'eq'
|
||||||
|
|
||||||
|
return filter_type, value
|
||||||
|
Loading…
x
Reference in New Issue
Block a user