HTTP REST API v1

Authentication

Authentication is based on secret tokens. In order to use the A||GO HTTP API, you need to copy your private token from your profile page. All requests must be include an Authorization header:

Authorization: Token token=<your_private_token>

Post a job

POST /api/v1/jobs

Submit a new job

form job[webapp]:

(required) the short name of the webapp (as it appears in urls)

form job[version]:

the version of the webapp to be used

form job[queue]:

job queue (for the scheduler)

form job[param]:

command-line arguments for the job

form files[0]:

a first file

form files[1]:

a second file, etc …

reqheader Authorization:

Token token=<your_private_token>

reqheader Content-Type:

multipart/form-data

Example response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "id":40155,
  "url":"https://allgo18.inria.fr/api/v1/jobs/40155"
  "avg_time": 0
}

Here is a example with curl

curl -H 'Authorization: Token token=<your_private_token>' \
     -X POST -F job[webapp]='<name>' -F job[param]='arg1 arg2' \
     -F files[0]='@<path_to_file0>' -F files[1]='@<path_to_file1>' \
     https://allgo18.inria.fr/api/v1/jobs

and with python requests:

requests.post("https://allgo18.inria.fr/api/v1/jobs",
      headers={"Authorization": "Token token=<your_private_token>"},
      data={"job[webapp]": "<name>", "job[param]": "arg1 arg2"},
      files={"files[0]": open("<path_to_file0>", "rb"), "files[1]": open("<path_to_file1>", "rb")})

This request will return you, either the errors, or if it’s ok, your job id and job url

Monitor a job

GET /api/v1/jobs/(int: job_id)/events
query offset:

optional starting offset (in bytes) for streaming the logs (default is 0). Use -1 to disable the logs.

reqheader Authorization:

Token token=<your_private_token>

This endpoint streams a sequence of line-delimited json objects to report the progress of the job.

The current implementation produces four kind of messages:

  • Status: reports the new state of the job

    {"status":  "<NEW_STATUS>"}
    
  • Logs: streams the console output of the job (allgo.log)

    {"logs": "<CONTENT>"}
    

    EOF on the console is signaled with an empty logs message:

    {"logs": ""}
    
  • EOF: sent at the end of the stream

    {"eof": null}
    
  • Keepalive: empty messages sent periodically to ensure that the connection is alive

    {}
    

Notes

  • The API may be extended in the future. Any unknown kind of message should be ignored by the client.

  • The stream ends when the job is terminated and the end of logs is reached. An eof message is sent to mark the end of the stream. If the stream terminates without the eof message, then you should assume that it was prematurely terminated. You may consider making a new request to resume the stream (possibly with a positive offset value to resume the logs where it was interrupted), but please wait at least a few seconds before making the new request (to avoid overloading the server in case your app enters an infinite loop).

  • States changes and logs are streamed independently of each other, therefore you may receive logs even after the job is reported as terminated. Only the eof message guarantees that the stream is terminated.

  • If your need is only to be notified when the job terminates (you are not interested in processing a stream of json object), then you should just make a minimal request (without the logs) GET /api/v1/jobs/<ID>/events?offset=-1 and ignore the content of the response. The request will finish when the job terminates.

Example response:

HTTP/1.1 200 OK
Content-Type: application/json

{ "status": "waiting" }
{}
{}
{ "status": "running" }
{ "logs": "some output\n" }
{}
{ "logs": "some other output\n" }
{ "status": "done" }
{ "logs": "end of the output\n" }
( "logs": "" }
{ "eof": null }

Get the results

Get the result of the job and the output files with:

GET /api/v1/jobs/(int: job_id)

Retrieve job informations

reqheader Authorization:

Token token=<your_private_token>

Example:

http

GET /api/v1/jobs/40155 HTTP/1.1
Host: allgo18.inria.fr
Accept: application/json
Authorization: Token token=<your_private_token>

curl

curl -i -X GET https://allgo18.inria.fr/api/v1/jobs/40155 -H "Accept: application/json" -H "Authorization: Token token=<your_private_token>"

python-requests

requests.get('https://allgo18.inria.fr/api/v1/jobs/40155', headers={'Accept': 'application/json', 'Authorization': 'Token token=<your_private_token>'})
HTTP/1.1 200 OK
Content-Type: application/json

{
 "40155":
   {"conv1_samusa.txt":"https://allgo18.inria.fr/datastore/6/1/0fe2bc68b835e9a1f681e38d5e87001ef955e345/conv1_samusa.txt",
    "conv1.json":"https://allgo18.inria.fr/datastore/6/1/0fe2bc68b835e9a1f681e38d5e87001ef955e345/conv1.json",
    "conv1.mp3":"https://allgo18.inria.fr/datastore/6/1/0fe2bc68b835e9a1f681e38d5e87001ef955e345/conv1.mp3",
    "allgo.log":"https://allgo18.inria.fr/datastore/6/1/0fe2bc68b835e9a1f681e38d5e87001ef955e345/allgo.log"
    },
 "status":"done"
 }

Each file could be downloaded with the link associated.

Abort a job

POST /api/v1/jobs/(int: job_id)/abort
reqheader Authorization:

Token token=<your_private_token>

Jobs may be aborted at any time.

The abort process is asynchronous and the response is sent immediately. The app first receives a SIGTERM to let it terminate cleanly, then after a grace period (10 seconds by default) a SIGKILL is sent. You should use the events API endpoint if you need to wait until the job is terminated.

This operation is idempotent. Calling it on a job which is already terminated or aborting will return HTTP 200.

Example responses:

HTTP/1.1 200 OK

{"info": "aborting job"}
HTTP/1.1 200 OK

{"info": "job already terminated"}

Delete a job

DELETE /api/v1/jobs/(int: job_id)
reqheader Authorization:

Token token=<your_private_token>

Running jobs cannot be deleted, they first need to be aborted.

This operation is idempotent. Calling it on a job which is already deleted will return HTTP 200.

Example responses:

HTTP/1.1 200 OK

{"info": "job successfully deleted"}
HTTP/1.1 409 Conflict

{"error": "cannot delete a running job"}

Get metrics

We provide a way to get simple metrics about your applications. It allows to get for a given webapp, the number of job over a period of time.

GET /api/v1/metrics/(string: metric_type)/(int: webapp_id)

We provide 4 metrics type:

  • per_user : the number of jobs per time period and per user.

  • per_result : the number of jobs per time period and per result.

  • created : the number of jobs created per time period.

  • all : all jobs created per time period.

3 parameters can refine your request :

  • step : string [year,month,week,day], the step of aggregation. By default set to ‘day’

  • from : date, the begin (including) of the time period to interrogate. By default set to ‘first result’

  • to : date, the end (excluding) of the time period to interrogate. By default set to ‘last result’

    Note: the dates should have the format “%Y-%m-%d”, so 2019-04-01 for the first of april 2019.

reqheader Authorization:

Token token=<your_private_token>

http

GET /api/v1/metrics/per_user/151?from=2019-01-01&step=day HTTP/1.1
Host: allgo18.inria.fr
Accept: application/json
Authorization: Token token=<your_private_token>

curl

curl -i -X GET 'https://allgo18.inria.fr/api/v1/metrics/per_user/151?from=2019-01-01&step=day' -H "Accept: application/json" -H "Authorization: Token token=<your_private_token>"

wget

wget -S -O- 'https://allgo18.inria.fr/api/v1/metrics/per_user/151?from=2019-01-01&step=day' --header="Accept: application/json" --header="Authorization: Token token=<your_private_token>"

httpie

http 'https://allgo18.inria.fr/api/v1/metrics/per_user/151?from=2019-01-01&step=day' Accept:application/json Authorization:"Token token=<your_private_token>"

python-requests

requests.get('https://allgo18.inria.fr/api/v1/metrics/per_user/151?from=2019-01-01&step=day', headers={'Accept': 'application/json', 'Authorization': 'Token token=<your_private_token>'})

Example response:

{
  "GATB-Compiler": {
    "from": "01-01-2017 00:00",
    "to": "01-01-2018 00:00",
    "data": [
      {
        "time_period": "2017-01-01T00:00:00Z",
        "result": "ERROR",
        "n": 2499
      },
      {
        "time_period": "2017-01-01T00:00:00Z",
        "result": "SUCCESS",
        "n": 22
      },
      ...
    ]
  }
}