diff --git a/api/api.py b/api/api.py index a9b707aa8f6db93ee1f1cb21599622ebbcfd2d25..74b1acba18085c5be4d1d2123cffb6742cd6ee57 100644 --- a/api/api.py +++ b/api/api.py @@ -9,7 +9,7 @@ import webapp2_extras.routes from . import base from .jobs.jobs import Job -from .jobs.handlers import JobsHandler, JobHandler +from .jobs.handlers import JobsHandler, JobHandler, GearsHandler, GearHandler from .dao.containerutil import FileReference, ContainerReference from . import encoder from . import root @@ -210,6 +210,10 @@ routes = [ webapp2.Route(r'/add', JobsHandler, handler_method='add', methods=['POST']), webapp2.Route(r'/<:[^/]+>', JobHandler, name='job'), ]), + webapp2.Route(r'/api/gears', GearsHandler), + webapp2_extras.routes.PathPrefixRoute(r'/api/gears', [ + webapp2.Route(r'/<:[^/]+>', GearHandler, name='job'), + ]), webapp2.Route(r'/api/groups', grouphandler.GroupHandler, handler_method='get_all', methods=['GET']), webapp2.Route(r'/api/groups', grouphandler.GroupHandler, methods=['POST']), webapp2.Route(_format(r'/api/groups/<_id:{group_id_re}>'), grouphandler.GroupHandler, name='group_details'), diff --git a/api/jobs/gears.py b/api/jobs/gears.py index 7c7f12f51cfde024bdf768ac594ce85d6931ab2b..e63e5fc6c6ff368c1fb9b9219c29af23e25fb724 100644 --- a/api/jobs/gears.py +++ b/api/jobs/gears.py @@ -6,27 +6,44 @@ from .. import config log = config.log +# For now, gears are in a singleton, prefixed by a key +SINGLETON_KEY = 'gear_list' -def get_gears(): +def get_gears(fields=None): """ Fetch the install-global gears from the database """ - gear_doc = config.db.singletons.find_one({'_id': 'gears'}) - return gear_doc['gear_list'] + projection = { } + + if fields is None: + fields = [ ] + projection = { SINGLETON_KEY: 1 } + else: + fields.append('name') + + query = {'_id': 'gears'} + + for f in fields: + projection[SINGLETON_KEY + '.' + f] = 1 + + gear_doc = config.db.singletons.find_one(query, projection) + + # print gear_doc + return gear_doc[SINGLETON_KEY] def get_gear_by_name(name): # Find a gear from the list by name gear_doc = config.db.singletons.find_one( {'_id': 'gears'}, - {'gear_list': { '$elemMatch': { + {SINGLETON_KEY: { '$elemMatch': { 'name': name }} }) - if gear_doc is None: + if gear_doc is None or gear_doc.get(SINGLETON_KEY) is None: raise Exception('Unknown gear ' + name) # Mongo returns the full document: { '_id' : 'gears', 'gear_list' : [ { .. } ] }, so strip that out - return gear_doc['gear_list'][0] + return gear_doc[SINGLETON_KEY][0] diff --git a/api/jobs/handlers.py b/api/jobs/handlers.py index 1e371f7b9f113006e8a5c2ba96d48c9df5f8e306..01dd700aebac28ca83be5feb8226eec4a2dae6bd 100644 --- a/api/jobs/handlers.py +++ b/api/jobs/handlers.py @@ -7,12 +7,121 @@ from ..dao.containerutil import create_filereference_from_dictionary, create_con from .. import base from .. import config +from .gears import get_gears, get_gear_by_name from .jobs import Job from .queue import Queue log = config.log + +class GearsHandler(base.RequestHandler): + + """Provide /gears API routes.""" + + def get(self): + """ + .. http:get:: /api/gears + + List all gears. + + :query fields: filter fields returned. Defaults to ['name']. Pass 'all' for everything. + :type fields: string + + :statuscode 200: no error + + **Example request**: + + .. sourcecode:: http + + GET /api/gears HTTP/1.1 + Host: demo.flywheel.io + Accept: */* + + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + Vary: Accept-Encoding + Content-Type: application/json; charset=utf-8 + [ + { + "name": "dicom_mr_classifier" + }, + { + "name": "dcm_convert" + }, + { + "name": "qa-report-fmri" + } + ] + """ + + if self.public_request: + self.abort(403, 'Request requires login') + + fields = self.request.GET.getall('fields') + if 'all' in fields: + fields = None + + return get_gears(fields) + + +class GearHandler(base.RequestHandler): + + """Provide /gears/x API routes.""" + + def get(self, _id): + """ + .. http:get:: /api/gears/(gid) + + Detail a gear. + + :statuscode 200: no error + + **Example request**: + + .. sourcecode:: http + + GET /api/gears/dcm_convert HTTP/1.1 + Host: demo.flywheel.io + Accept: */* + + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + Vary: Accept-Encoding + Content-Type: application/json; charset=utf-8 + { + "name": "dcm_convert" + "manifest": { + "config": {}, + "inputs": { + "dicom": { + "base": "file", + "type": { + "enum": [ + "dicom" + ] + } + } + }, + }, + } + + """ + + if self.public_request: + self.abort(403, 'Request requires login') + + return get_gear_by_name(_id) + + class JobsHandler(base.RequestHandler): """Provide /jobs API routes."""