Commit 3c64fb4d authored by Daniele Venzano's avatar Daniele Venzano

Execution list API filters

parent f16c6073
...@@ -126,8 +126,21 @@ class ExecutionCollectionAPI(RequestHandler): ...@@ -126,8 +126,21 @@ class ExecutionCollectionAPI(RequestHandler):
def get(self): def get(self):
""" """
Returns a list of all active executions. Returns a list of all active executions.
Return a list of all executions which have status equal to ..." The list can be filtered by passing a non-empty JSON dictionary. Any combination of the following filters is supported:
* status: one of submitted, scheduled, starting, error, running, cleaning up, terminated
* name: execution mane
* user_id: user_id owning the execution (admin only)
* limit: limit the number of returned entries
* earlier_than_submit: all execution that where submitted earlier than this timestamp
* earlier_than_start: all execution that started earlier than this timestamp
* earlier_than_end: all execution that ended earlier than this timestamp
* later_than_submit: all execution that where submitted later than this timestamp
* later_than_start: all execution that started later than this timestamp
* later_than_end: all execution that started later than this timestamp
All timestamps should be passed as number of seconds since the epoch (UTC timezone).
example: curl -u 'username:password' -X GET -H "Content-Type: application/json" -d '{"status":"terminated"}' http://bf5:8080/api/0.6/execution example: curl -u 'username:password' -X GET -H "Content-Type: application/json" -d '{"status":"terminated"}' http://bf5:8080/api/0.6/execution
...@@ -137,16 +150,26 @@ class ExecutionCollectionAPI(RequestHandler): ...@@ -137,16 +150,26 @@ class ExecutionCollectionAPI(RequestHandler):
filt_dict = {} filt_dict = {}
try: filters = [
if self.request.body: ('status', str),
filt_dict = tornado.escape.json_decode(self.request.body) ('name', str),
except ValueError: ('user_id', str),
raise zoe_api.exceptions.ZoeRestAPIException('Error decoding JSON data') ('limit', int),
('earlier_than_submit', int),
if 'status' in filt_dict: ('earlier_than_start', int),
execs = self.api_endpoint.execution_list(uid, role, status=filt_dict['status']) ('earlier_than_end', int),
else: ('later_than_submit', int),
execs = self.api_endpoint.execution_list(uid, role) ('later_than_start', int),
('later_than_end', int)
]
for f in filters:
if f[0] in self.request.arguments:
if f[1] == str:
filt_dict[f[0]] = self.request.arguments[f[0]][0].decode('utf-8')
else:
filt_dict[f[0]] = f[1](self.request.arguments[f[0]][0])
execs = self.api_endpoint.execution_list(uid, role, **filt_dict)
self.write(dict([(e.id, e.serialize()) for e in execs])) self.write(dict([(e.id, e.serialize()) for e in execs]))
......
...@@ -66,10 +66,26 @@ def app_get_cmd(args): ...@@ -66,10 +66,26 @@ def app_get_cmd(args):
json.dump(execution['description'], sys.stdout, sort_keys=True, indent=4) json.dump(execution['description'], sys.stdout, sort_keys=True, indent=4)
def exec_list_cmd(args_): def exec_list_cmd(args):
"""List executions""" """List executions"""
exec_api = ZoeExecutionsAPI(utils.zoe_url(), utils.zoe_user(), utils.zoe_pass()) exec_api = ZoeExecutionsAPI(utils.zoe_url(), utils.zoe_user(), utils.zoe_pass())
data = exec_api.list() filter_names = [
'status',
'name',
'user_id',
'limit',
'earlier_than_submit',
'earlier_than_start',
'earlier_than_end',
'later_than_submit',
'later_than_start',
'later_than_end'
]
filters = {}
for k, v in vars(args).items():
if k in filter_names:
filters[k] = v
data = exec_api.list(**filters)
for e in sorted(data.values(), key=lambda x: x['id']): for e in sorted(data.values(), key=lambda x: x['id']):
print('Execution {} (User: {}, ID: {}): {}'.format(e['name'], e['user_id'], e['id'], e['status'])) print('Execution {} (User: {}, ID: {}): {}'.format(e['name'], e['user_id'], e['id'], e['status']))
...@@ -181,6 +197,16 @@ def process_arguments() -> Tuple[ArgumentParser, Namespace]: ...@@ -181,6 +197,16 @@ def process_arguments() -> Tuple[ArgumentParser, Namespace]:
argparser_exec_start.set_defaults(func=exec_start_cmd) argparser_exec_start.set_defaults(func=exec_start_cmd)
argparser_app_list = subparser.add_parser('exec-ls', help="List all executions for the calling user") argparser_app_list = subparser.add_parser('exec-ls', help="List all executions for the calling user")
argparser_app_list.add_argument('--limit', type=int, help='Limit the number of executions')
argparser_app_list.add_argument('--name', help='Show only executions with this name')
argparser_app_list.add_argument('--user', help='Show only executions belonging to this user')
argparser_app_list.add_argument('--status', choices=["submitted", "scheduled", "starting", "error", "running", "cleaning up", "terminated"], help='Show only executions with this status')
argparser_app_list.add_argument('--earlier-than-submit', help='Show only executions submitted earlier than this timestamp (seconds since UTC epoch)')
argparser_app_list.add_argument('--earlier-than-start', help='Show only executions submitted earlier than this timestamp (seconds since UTC epoch)')
argparser_app_list.add_argument('--earlier-than-end', help='Show only executions submitted earlier than this timestamp (seconds since UTC epoch)')
argparser_app_list.add_argument('--later-than-submit', help='Show only executions submitted earlier than this timestamp (seconds since UTC epoch)')
argparser_app_list.add_argument('--later-than-start', help='Show only executions submitted earlier than this timestamp (seconds since UTC epoch)')
argparser_app_list.add_argument('--later-than-end', help='Show only executions submitted earlier than this timestamp (seconds since UTC epoch)')
argparser_app_list.set_defaults(func=exec_list_cmd) argparser_app_list.set_defaults(func=exec_list_cmd)
argparser_execution_get = subparser.add_parser('exec-get', help="Get execution status") argparser_execution_get = subparser.add_parser('exec-get', help="Get execution status")
...@@ -195,9 +221,9 @@ def process_arguments() -> Tuple[ArgumentParser, Namespace]: ...@@ -195,9 +221,9 @@ def process_arguments() -> Tuple[ArgumentParser, Namespace]:
argparser_execution_kill.add_argument('id', type=int, help="Execution id") argparser_execution_kill.add_argument('id', type=int, help="Execution id")
argparser_execution_kill.set_defaults(func=exec_kill_cmd) argparser_execution_kill.set_defaults(func=exec_kill_cmd)
argparser_execution_kill = subparser.add_parser('exec-rm', help="Deletes an execution") argparser_execution_rm = subparser.add_parser('exec-rm', help="Deletes an execution")
argparser_execution_kill.add_argument('id', type=int, help="Execution id") argparser_execution_rm.add_argument('id', type=int, help="Execution id")
argparser_execution_kill.set_defaults(func=exec_rm_cmd) argparser_execution_rm.set_defaults(func=exec_rm_cmd)
argparser_stats = subparser.add_parser('stats', help="Prints all available statistics") argparser_stats = subparser.add_parser('stats', help="Prints all available statistics")
argparser_stats.set_defaults(func=stats_cmd) argparser_stats.set_defaults(func=stats_cmd)
......
...@@ -79,14 +79,15 @@ class ZoeAPIBase: ...@@ -79,14 +79,15 @@ class ZoeAPIBase:
return req, req.status_code return req, req.status_code
@retry(ZoeAPIException) @retry(ZoeAPIException)
def _rest_get(self, path): def _rest_get(self, path, payload=None):
""" """
:type path: str :type path: str
:type payload: dict
:rtype: (dict, int) :rtype: (dict, int)
""" """
url = self.url + '/api/' + ZOE_API_VERSION + path url = self.url + '/api/' + ZOE_API_VERSION + path
try: try:
req = requests.get(url, auth=(self.user, self.password)) req = requests.get(url, auth=(self.user, self.password), params=payload)
except requests.exceptions.Timeout: except requests.exceptions.Timeout:
raise ZoeAPIException('HTTP connection timeout') raise ZoeAPIException('HTTP connection timeout')
except requests.exceptions.HTTPError: except requests.exceptions.HTTPError:
......
...@@ -61,13 +61,26 @@ class ZoeExecutionsAPI(ZoeAPIBase): ...@@ -61,13 +61,26 @@ class ZoeExecutionsAPI(ZoeAPIBase):
else: else:
raise ZoeAPIException(data['message']) raise ZoeAPIException(data['message'])
def list(self): def list(self, **kwargs):
""" """
Returns a list of all executions for the calling user, all of them if the user is admin. Returns a list of all executions for the calling user, all of them if the user is admin.
The list can be filtered by passing arguments. Any combination of the following filters is supported:
* status: one of submitted, scheduled, starting, error, running, cleaning up, terminated
* name: execution mane
* user_id: user_id owning the execution (admin only)
* limit: limit the number of returned entries
* earlier_than_submit: all execution that where submitted earlier than this timestamp
* earlier_than_start: all execution that started earlier than this timestamp
* earlier_than_end: all execution that ended earlier than this timestamp
* later_than_submit: all execution that where submitted later than this timestamp
* later_than_start: all execution that started later than this timestamp
* later_than_end: all execution that started later than this timestamp
:return: :return:
""" """
data, status_code = self._rest_get('/execution') data, status_code = self._rest_get('/execution', kwargs)
if status_code == 200: if status_code == 200:
return data return data
else: else:
......
...@@ -59,12 +59,14 @@ class SQLManager: ...@@ -59,12 +59,14 @@ class SQLManager:
cur.execute('SET search_path TO {},public'.format(self.schema)) cur.execute('SET search_path TO {},public'.format(self.schema))
return cur return cur
def execution_list(self, only_one=False, **kwargs): def execution_list(self, only_one=False, limit=-1, **kwargs):
""" """
Return a list of executions. Return a list of executions.
:param only_one: only one result is expected :param only_one: only one result is expected
:type only_one: bool :type only_one: bool
:param limit: limit the result to this number of entries
:type limit: int
:param kwargs: filter executions based on their fields/columns :param kwargs: filter executions based on their fields/columns
:return: one or more executions :return: one or more executions
""" """
...@@ -75,11 +77,28 @@ class SQLManager: ...@@ -75,11 +77,28 @@ class SQLManager:
filter_list = [] filter_list = []
args_list = [] args_list = []
for key, value in kwargs.items(): for key, value in kwargs.items():
filter_list.append('{} = %s'.format(key)) if key == 'earlier_than_submit':
filter_list.append('"time_submit" <= to_timestamp(%s)')
elif key == 'earlier_than_start':
filter_list.append('"time_start" <= to_timestamp(%s)')
elif key == 'earlier_than_end':
filter_list.append('"time_end" <= to_timestamp(%s)')
elif key == 'later_than_submit':
filter_list.append('"time_submit" >= to_timestamp(%s)')
elif key == 'later_than_start':
filter_list.append('"time_start" >= to_timestamp(%s)')
elif key == 'later_than_end':
filter_list.append('"time_end" >= to_timestamp(%s)')
else:
filter_list.append('{} = %s'.format(key))
args_list.append(value) args_list.append(value)
q += ' AND '.join(filter_list) q += ' AND '.join(filter_list)
if limit > 0:
q += ' LIMIT {}'.format(limit)
query = cur.mogrify(q, args_list) query = cur.mogrify(q, args_list)
else: else:
if limit > 0:
q_base += ' LIMIT {}'.format(limit)
query = cur.mogrify(q_base) query = cur.mogrify(q_base)
cur.execute(query) cur.execute(query)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment