Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Monitor API

Notes about endpoints

Some of the endpoints below require the monitor API token. Requests to these endpoints need to prove you know that token:

Authorization: Bearer <monitor API token>

Some of the endpoints below may require sequential processing in the backend. While requests to other endpoints are guaranteed to be cheap, requests to these endpoints can be a bit expensive when successful, because they’re processed one at a time in the monitor thread.

The monitor thread interacts with external resources like the GitHub API and the hypervisor, and it runs a loop that looks like the pseudocode below:

loop {
    if registrations_last_updated.elapsed()
        > MONITOR_DOT_TOML.api_cache_timeout
    {
        registrations = github_api::list_registered_runners();
        registrations_last_updated = Instant::now();
    }
    guests = hypervisor_api::list_guests();
    hypervisor_api::take_screenshots(guests);
    hypervisor_api::check_ipv4_addresses(guests);

    if let Some((request, response_tx)) = monitor_request_rx
        .recv_timeout(MONITOR_DOT_TOML.monitor_poll_interval)
    {
        response_tx.send(match request {
            // ...
        });
    }
}

Reserving runners

The recommended way to reserve runners is to use the tokenless API (POST /select-runner), which uses a temporary artifact to prove that the request is genuine and authorised. This allows self-hosted runners to be used in pull_request runs (rather than only pull_request_target), and in workflows that do not have access to secrets.

Alternatively you can use the monitor API token, which for workflows means you will need to define it as a secret like ${{ secrets.MONITOR_API_TOKEN }}.

POST /select-runner
— Reserve one runner for a job using an artifact

  • May require sequential processing in the backend
?unique_id (required; UUIDv4)
uniquely identifies this job in its friendly name, even if the same workflow is called twice in the workflow call tree
?qualified_repo (required; <user>/<repo>)
the repository running this job
?run_id (required; number)
the workflow run id of this job

POST /profile/profile_key/take
— Reserve one runner for a job using the monitor API token

  • Requires monitor API token
  • May require sequential processing in the backend
  • Response: application/json — {"id", "runner"} | null
profile_key (string)
what kind of runner to take
?unique_id (required; UUIDv4)
uniquely identifies this job in its friendly name, even if the same workflow is called twice in the workflow call tree
?qualified_repo (required; <user>/<repo>)
the repository running this job
?run_id (required; number)
the workflow run id of this job

POST /profile/profile_key/take/count
— Reserve runners for a set of jobs using the monitor API token

  • Requires monitor API token
  • May require sequential processing in the backend
  • Response: application/json — [{"id", "runner"}] | null
profile_key (string)
what kind of runners to take
count (number)
how many runners to take
?unique_id (required; UUIDv4)
uniquely identifies these jobs in their friendly names, even if the same workflow is called twice in the workflow call tree
?qualified_repo (required; <user>/<repo>)
the repository running these jobs
?run_id (required; number)
the workflow run id of these jobs

Runner internals

GET /github-jitconfig
— Get the ephemeral runner token for this runner

  • May require sequential processing in the backend
  • Response: application/json

GET /boot
— Get the boot script for this runner

  • May require sequential processing in the backend
  • Response: text/plain

Dashboard internals

GET /dashboard.html
— Get the rendered contents of the dashboard for live updates

  • Response: text/html

GET /dashboard.json
— Get a machine-readable version of the contents of the dashboard

  • Response: application/json

GET /profile/profile_key/screenshot.png
— Get the last cached screenshot of a rebuild guest

  • Response: image/png

GET /runner/runner_id/screenshot.png
— Get the last cached screenshot of a runner guest

  • Response: image/png

GET /runner/runner_id/screenshot/now
— Take a screenshot of a runner guest immediately

  • May require sequential processing in the backend
  • Response: image/png

Policy overrides (EXPERIMENTAL)

Policy overrides provide rudimentary support for autoscaling, implemented as part of Servo’s effort to self-host WPT runs (#21). The design has several unsolved problems, and should not be used.

They allow us to dynamically reconfigure a server’s runner targets to meet the needs of a workflow. This can be useful if that workflow is huge and parallel, and you want to divert as much of your concurrent runner capacity as possible to it.

GET /policy/override
— Get the current policy override

POST /policy/override
— Initiate a new policy override

  • Requires monitor API token
  • Response: application/json — {"<<profile_key>>": <count>}
?<profile_key>=count (required; string/number pairs)
how many runners to target for each profile key

DELETE /policy/override
— Cancel the current policy override

  • Requires monitor API token
  • Response: application/json — {"<<profile_key>>": <count>}