Skip to content
Snippets Groups Projects
Commit d679578d authored by Megan Henning's avatar Megan Henning Committed by GitHub
Browse files

Merge pull request #388 from scitran/gear-configuration

First pass at gear configuration
parents e117c0f6 b9667590
No related branches found
No related tags found
No related merge requests found
......@@ -205,6 +205,7 @@ routes = [
webapp2.Route(r'/reap', JobsHandler, handler_method='reap_stale', methods=['POST']),
webapp2.Route(r'/add', JobsHandler, handler_method='add', methods=['POST']),
webapp2.Route(r'/<:[^/]+>', JobHandler, name='job'),
webapp2.Route(r'/<:[^/]+>/config.json', JobHandler, name='job', handler_method='get_config'),
webapp2.Route(r'/<:[^/]+>/retry', JobHandler, name='job', handler_method='retry', methods=['POST']),
]),
webapp2.Route(r'/api/gears', GearsHandler),
......
......@@ -2,6 +2,9 @@
API request handlers for the jobs module
"""
import json
import StringIO
from ..dao.containerutil import create_filereference_from_dictionary, create_containerreference_from_dictionary, create_containerreference_from_filereference
from .. import base
from .. import config
......@@ -327,6 +330,7 @@ class JobsHandler(base.RequestHandler):
"""
submit = self.request.json
gear_name = submit['gear']
# Translate maps to FileReferences
......@@ -335,8 +339,9 @@ class JobsHandler(base.RequestHandler):
input_map = submit['inputs'][x]
inputs[x] = create_filereference_from_dictionary(input_map)
# Add job tags, attempt number, and/or previous job ID, if present
# Add job tags, config, attempt number, and/or previous job ID, if present
tags = submit.get('tags', None)
config_ = submit.get('config', None)
attempt_n = submit.get('attempt_n', 1)
previous_job_id = submit.get('previous_job_id', None)
......@@ -354,7 +359,7 @@ class JobsHandler(base.RequestHandler):
inputs[x].check_access(self.uid, 'ro')
destination.check_access(self.uid, 'rw')
job = Job(gear_name, inputs, destination=destination, tags=tags, attempt=attempt_n, previous_job_id=previous_job_id)
job = Job(gear_name, inputs, destination=destination, tags=tags, config_=config_, attempt=attempt_n, previous_job_id=previous_job_id)
result = job.insert()
return { "_id": result }
......@@ -398,6 +403,47 @@ class JobHandler(base.RequestHandler):
return Job.get(_id)
def get_config(self, _id):
"""
.. http:get:: /api/jobs/x/config.json
Returns the job's config as a downloadable json file
:statuscode 200: no error
**Example request**:
.. sourcecode:: http
GET /api/jobs/3/config.json HTTP/1.1
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Content-Disposition: attachment; filename="config.json"
Content-Type: application/octet-stream
{
"speed": 5
}
"""
if not self.superuser_request:
self.abort(403, 'Request requires superuser')
c = Job.get(_id).config
if c is None:
c = {}
self.response.headers['Content-Type'] = 'application/octet-stream'
self.response.headers['Content-Disposition'] = 'attachment; filename="config.json"'
# Serve config as formatted json file
encoded = json.dumps(c, sort_keys=True, indent=4, separators=(',', ': ')) + '\n'
self.response.app_iter = StringIO.StringIO(encoded)
def put(self, _id):
"""
Update a job. Updates timestamp.
......
......@@ -13,7 +13,7 @@ from .. import config
log = config.log
class Job(object):
def __init__(self, name, inputs, destination=None, tags=None, attempt=1, previous_job_id=None, created=None, modified=None, state='pending', request=None, id_=None):
def __init__(self, name, inputs, destination=None, tags=None, attempt=1, previous_job_id=None, created=None, modified=None, state='pending', request=None, id_=None, config_=None):
"""
Creates a job.
......@@ -40,6 +40,8 @@ class Job(object):
The request that is used for the engine. Generated when job is started.
id_: string (optional)
The database identifier for this job.
config: map (optional)
The gear configuration for this job.
"""
# TODO: validate inputs against the manifest
......@@ -75,6 +77,7 @@ class Job(object):
self.state = state
self.request = request
self.id_ = id_
self.config = config_
@classmethod
def load(cls, e):
......@@ -97,7 +100,7 @@ class Job(object):
d['_id'] = str(d['_id'])
return cls(d['name'], d.get('inputs', None), destination=d.get('destination', None), tags=d['tags'], attempt=d['attempt'], previous_job_id=d.get('previous_job_id', None), created=d['created'], modified=d['modified'], state=d['state'], request=d.get('request', None), id_=d['_id'])
return cls(d['name'], d.get('inputs', None), destination=d.get('destination', None), tags=d['tags'], attempt=d['attempt'], previous_job_id=d.get('previous_job_id', None), created=d['created'], modified=d['modified'], state=d['state'], request=d.get('request', None), id_=d['_id'], config_=d.get('config', None))
@classmethod
def get(cls, _id):
......@@ -191,6 +194,18 @@ class Job(object):
# Map destination to upload URI
r['outputs'][0]['uri'] = '/engine?level=' + self.destination.type + '&id=' + self.destination.id
# Add config, if any
if self.config is not None:
if self._id is None:
raise Exception('Running a job requires an ID')
r['inputs'].append({
'type': 'scitran',
'uri': '/jobs/' + self._id + '/config.json',
'location': '/flywheel/v0',
})
# Add the files
for input_name in self.inputs.keys():
i = self.inputs[input_name]
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment