Scheduler REST API

The scheduler is a long-running service that manages access to SUT classes and dispatches queued work onto concrete SUT instances as they become available. It provides a REST API for:

  • creating scheduler users and API tokens

  • submitting plans for execution, tracking their progress, reprioritizing and cancelling them

  • acquiring and releasing manual leases on SUTs

  • querying SUT class metadata and usage

The main use cases are:

  • Plan execution: submit a plan that targets a SUT class and let the scheduler split the plan and dispatch onto available SUTs in parallel.

  • SUT leasing: request a lease on a SUT from a SUT class, wait for a SUT to become available, and release it when finished.

  • Operational reporting: inspect leases, plans, and SUT class usage.

Note

Users are expected to interact with the scheduler via the CLI commands (see Using the Scheduler). Those commands wrap the API documented here. The API is documented to enable integration with other systems.

Authentication

All endpoints require a bearer token in the Authorization header:

Authorization: Bearer <token>

Tokens are created via POST /users.

Capabilities

The scheduler enforces capabilities on each endpoint:

  • CAP_ADMIN: unrestricted administrative access

  • CAP_EXEC: submit and modify plans

  • CAP_LEASE: acquire and release manual leases

  • CAP_QUERY: query scheduler state

An admin token bypasses ownership checks. Non-admin users are restricted to operating only on their own leases and plans.

Content Types

Most requests and all responses use JSON.

Plan submission is the exception: POST /plans accepts either JSON or multipart/form-data. Multipart must be used when the plan references local files that need to be uploaded alongside the plan payload (e.g. kernel images).

Endpoints

Users

POST /users

Create a new scheduler user. Requires CAP_ADMIN.

Request body:

{
  "name": "alice",
  "capabilities": "lease,query,exec"
}

Response 201:

{
  "status": "success",
  "user_id": 3,
  "token": "<bearer-token>"
}

Plans

POST /plans

Submit a plan for scheduler execution. Requires CAP_EXEC.

The scheduler validates the plan, stores any uploaded input files under the plan storage directory, stores a normalized plan.yaml, splits the plan into plan jobs, and queues those jobs for dispatch. If the scheduler was started with a configured resultstore, plans publish results there by default; this can be disabled per-submission with publish.

JSON request body:

{
  "plan": { ... plan object ... },
  "priority": 5,
  "publish": true
}

Multipart request:

  • form field payload containing JSON with plan, priority, and optional publish

  • repeated file field files for any local files referenced by the plan

Response 201:

{
  "status": "success",
  "plan_id": 11
}
GET /plans

List plans. Requires CAP_QUERY.

Optional query parameters to filter the response. If not provided, acts as if all values were provided:

  • states=queued,running,success,failed,cancelled

  • users=alice,bob

The special user value __current__ may be used to mean the authenticated user.

GET /plans/<plan_id>

Retrieve a single plan. Requires CAP_QUERY.

PATCH /plans/<plan_id>

Modify a plan. Requires CAP_EXEC. Non-admin users may only modify their own plans.

Supported fields:

  • priority: reprioritize all non-completed child jobs

  • cancel: boolean; when true requests plan cancellation

Either field may be provided on its own, or both together.

Request body:

{
  "priority": 8,
  "cancel": false
}

Response 200:

{
  "status": "success"
}
Plan fields
plan_id

Plan id.

user

Object containing id and name.

sutclass

Object containing id and name.

priority

Plan priority.

state

Plan state. One of queued, running, success, failed, or cancelled.

total_jobs

Number of split plan jobs.

completed_jobs

Number of split plan jobs that completed successfully.

queued_at, started_at, completed_at

plan timestamps.

Leases

POST /leases

Queue a manual lease against a SUT class. Requires CAP_LEASE.

Request body:

{
  "sutclass": "myclass",
  "priority": 5
}

Response 201:

{
  "status": "success",
  "lease_id": 7
}
PATCH /leases/<lease_id>

Release a lease. Requires CAP_LEASE. Non-admin users may only release their own leases.

Response 200:

{
  "status": "success"
}
GET /leases

List leases. Requires CAP_QUERY.

Optional query parameters to filter the response. If not provided, acts as if all values were provided:

  • states=queued,acquired,released,failed,cancelled

  • users=alice,bob

The special user value __current__ may be used to mean the authenticated user.

GET /leases/<lease_id>

Retrieve a single lease. Requires CAP_QUERY.

Lease fields
lease_id

Lease id.

user

Object containing id and name.

job_id

Backing job id.

state

Lease state. One of queued, acquired, released, failed, or cancelled.

priority

Lease priority.

sutclass

Object containing id and name.

sut

The acquired SUT description, or null if not yet acquired.

queued_at, started_at, completed_at

Timestamps for the backing job lifecycle.

SUT Classes

GET /sutclasses

List SUT classes known to the scheduler. Requires CAP_QUERY.

Optional query parameters:

  • from=<iso-datetime>

  • to=<iso-datetime>

When from and/or to are provided, the server calculates usage only within that time window. When neither is provided, usage is the scheduler’s accumulated all-time usage counter.

SUT class fields
id

SUT class id.

name

SUT class name.

enabled

Boolean indicating whether the SUT class is enabled.

usage

Runtime usage in seconds.

created_at

Timestamp when the SUT class row was created.

Errors

Errors return JSON of the form {"status": "<status>"}.

The scheduler currently uses these status codes:

  • 400 invalid

  • 400 resourcebusy

  • 401 unauthorized

  • 403 forbidden

  • 404 notfound

  • 409 exists

  • 413 toobig

  • 500 internalerror

Examples

Create a scheduler user:

curl -X POST \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"alice","capabilities":"lease,query,exec"}' \
  http://localhost:5000/users

Acquire a lease:

curl -X POST \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"sutclass":"myclass","priority":5}' \
  http://localhost:5000/leases

Submit a plan using multipart upload:

curl -X POST \
  -H "Authorization: Bearer $TOKEN" \
  -F 'payload={"plan": {...}, "priority": 5}' \
  -F 'files=@Image' \
  http://localhost:5000/plans

List SUT classes for a specific window:

curl -X GET \
  -H "Authorization: Bearer $TOKEN" \
  'http://localhost:5000/sutclasses?from=2026-03-01T00:00:00+00:00&to=2026-04-01T00:00:00+00:00'