Browse Source

Support filtering for execution query

Change-Id: Iab965386f57948d4c333dfadde589c76ea639764
Implements: blueprint qinling-execution-filter
changes/69/510369/4
Lingxian Kong 5 years ago
parent
commit
601410e119
  1. 43
      example/functions/python/openstack/create_thumbnail.py
  2. 0
      example/functions/python/openstack/get_swift_object.py
  3. 10
      qinling/api/controllers/v1/execution.py
  4. 4
      qinling/db/api.py
  5. 18
      qinling/tests/unit/api/controllers/v1/test_execution.py
  6. 83
      qinling/utils/rest_utils.py

43
example/functions/python/openstack/create_thumbnail.py

@ -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

0
example/functions/python/get_swift_object.py → example/functions/python/openstack/get_swift_object.py

10
qinling/api/controllers/v1/execution.py

@ -15,6 +15,7 @@
from oslo_log import log as logging
import pecan
from pecan import rest
from wsme import types as wtypes
import wsmeext.pecan as wsme_pecan
from qinling.api.controllers.v1 import resources
@ -61,12 +62,13 @@ class ExecutionsController(rest.RestController):
return resources.Execution.from_dict(db_model.to_dict())
@rest_utils.wrap_wsme_controller_exception
@wsme_pecan.wsexpose(resources.Executions)
def get_all(self):
LOG.info("Get all %ss.", self.type)
@wsme_pecan.wsexpose(resources.Executions, wtypes.text)
def get_all(self, function_id=None):
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())
for db_model in db_api.get_executions()]
for db_model in db_api.get_executions(**filters)]
return resources.Executions(executions=executions)

4
qinling/db/api.py

@ -130,8 +130,8 @@ def get_execution(id):
return IMPL.get_execution(id)
def get_executions():
return IMPL.get_executions()
def get_executions(**filters):
return IMPL.get_executions(**filters)
def delete_execution(id):

18
qinling/tests/unit/api/controllers/v1/test_execution.py

@ -70,6 +70,24 @@ class TestExecutionController(base.APITest):
)
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')
def test_delete(self, mock_create_execution):
body = {

83
qinling/utils/rest_utils.py

@ -70,3 +70,86 @@ def wrap_pecan_controller_exception(func):
)
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…
Cancel
Save