HydraCore
API by router

Runtime images

List Runtime Images

List registered images. Defaults to current rows only; include_superseded=true returns history. Used by the admin staleness page (Patch 5).

GET
/internal/v1/runtime-images

Query Parameters

manifest_id?Manifest Id
provider?Provider
include_superseded?Include Superseded
Defaultfalse

Header Parameters

authorization?Authorization

Response Body

curl -X GET "https://loading/internal/v1/runtime-images?manifest_id=string&provider=string&include_superseded=false" \  -H "authorization: string"
{
  "images": [
    {
      "built_at": "2019-08-24T14:15:22Z",
      "bundle_hash": "string",
      "compatibility_hash": "string",
      "id": "string",
      "manifest_id": "string",
      "provider": "string",
      "registered_at": "2019-08-24T14:15:22Z",
      "registered_by": "string",
      "runtime_version": "string",
      "snapshot_id": "string",
      "superseded_at": "2019-08-24T14:15:22Z"
    }
  ]
}
{
  "detail": [
    {
      "loc": [
        "string"
      ],
      "msg": "string",
      "type": "string"
    }
  ]
}

Register Runtime Image

Insert a new row for (manifest_id, provider) and supersede the previous current row in the same transaction.

Concurrency: we acquire a transaction-scoped Postgres advisory lock keyed on (manifest_id, provider) before reading the current row. SELECT ... FOR UPDATE alone is not sufficient because:

  1. The first bake for a slot has no row to lock — two simultaneous registrations would both pass the partial- unique-index check and one would fail at INSERT.
  2. After T1 supersedes the existing current row and commits, T2's blocked SELECT FOR UPDATE re-reads, sees no current row, and proceeds to INSERT — both rows might then race the partial unique check. The advisory lock serialises every code path against the same slot, removing both windows. It auto-releases on transaction end (commit OR rollback). The lock key is a 64-bit hash of "<manifest_id>:"; collisions across unrelated slots are harmless (worst case: two unrelated bakes serialise) but identical slots always collide, which is what we want.

Idempotency: re-POST with the same snapshot_id + compatibility_hash for the same slot is a no-op — useful when a bake retries after a transient network blip. The response then reports superseded=False with the existing id.

POST
/internal/v1/runtime-images

Header Parameters

authorization?Authorization
built_atBuilt At
Formatdate-time
bundle_hash?Bundle Hash
compatibility_hashCompatibility Hash
Length10 <= length <= 80
manifest_idManifest Id
Lengthlength <= 100
providerProvider
Lengthlength <= 50
registered_by?Registered By
runtime_version?Runtime Version
snapshot_idSnapshot Id
Lengthlength <= 255

Response Body

curl -X POST "https://loading/internal/v1/runtime-images" \  -H "authorization: string" \  -H "Content-Type: application/json" \  -d '{    "built_at": "2019-08-24T14:15:22Z",    "compatibility_hash": "stringstri",    "manifest_id": "string",    "provider": "string",    "snapshot_id": "string"  }'
{
  "compatibility_hash": "string",
  "id": "string",
  "manifest_id": "string",
  "provider": "string",
  "snapshot_id": "string",
  "superseded": true,
  "superseded_id": "string"
}
{
  "detail": [
    {
      "loc": [
        "string"
      ],
      "msg": "string",
      "type": "string"
    }
  ]
}

Rollback Runtime Image

Supersede the named row and un-supersede the most recently superseded row in the same (manifest, provider) slot.

Used by the continuous-bake pipeline when a freshly registered snapshot fails its post-bake smoke or soak checks. The previous "current" row is the one most-recently superseded for the slot — typically the snapshot the just-failed bake replaced.

No-op contract: if image_id is already superseded the call is rejected (409) so a stale rollback can't accidentally re-promote a 3-versions-back snapshot. Callers should check the current row via GET first if there is any doubt.

Empty-slot guard: if the caller is rolling back the FIRST-EVER registered image for a slot (no previous row to restore), the rollback would leave the slot with no current image — silently degrading future provisions to the GOLDEN_IMAGES_JSON env or vanilla ubuntu fallback. For the automated smoke-failure path this is dangerous: it makes a single bad smoke pull the platform off baked images entirely. Default behaviour is now 409 in that case; pass ?allow_empty_slot=true for the manual operator path where empty-current is genuinely intended (e.g. decommissioning a runtime).

Concurrency: same advisory-lock key as the register path so a rollback can't race a concurrent register on the same slot.

POST
/internal/v1/runtime-images/{image_id}/rollback

Path Parameters

image_idImage Id

Query Parameters

allow_empty_slot?Allow Empty Slot
Defaultfalse

Header Parameters

authorization?Authorization

Response Body

curl -X POST "https://loading/internal/v1/runtime-images/string/rollback?allow_empty_slot=false" \  -H "authorization: string"
{
  "manifest_id": "string",
  "provider": "string",
  "restored": "string",
  "rolled_back_from": "string"
}
{
  "detail": [
    {
      "loc": [
        "string"
      ],
      "msg": "string",
      "type": "string"
    }
  ]
}