Skip to content

api: Metal HTTP server ​

For Go code, follow the repository Go anti-pattern rules.

Metal specification · Behavior: controller contract and metald

Purpose ​

This package owns request validation, the public response shape, and the error-to-status mapping. It owns no VM, image, or host state. A mutation stores desired state, wakes the reconciler, and returns without waiting for the host.

Types ​

  • New(Config, Dependencies) returns the Atlas API router.
  • NewCoordination returns the node coordination router.
  • Server holds the injected services and handlers.
  • Dependencies holds the injected services. Each is an interface declared in this package.

Request flow ​

Each request goes through these steps in order:

  1. Add the correlation IDs.
  2. Write the request log.
  3. Authenticate the route group.
  4. Decode strict JSON in the handler.
  5. Validate the request.
  6. Call the domain service.
  7. Wake the reconciler when needed.
  8. Write the response.
  • Each request gets an X-Request-ID and an X-Operation-ID. A caller value is kept only when it is safe to echo.
  • JSON decoding ignores unknown fields and rejects trailing values.
  • Request bodies are size capped.

Routes ​

The generated Metal API reference lists each route. Rules:

  • Use PUT when a request replaces desired state, so a repeat is safe.
  • Use POST only for an action that runs on each call, such as a restart, or to create a resource.
  • The network PUT requires the complete network object, including firewall.
  • Every coordination route carries the VM ID as the virtual_machine_id query value.
  • The coordination stop route is idempotent. It returns the final snapshot.
  • The coordination memory snapshot route streams one memory snapshot file for the final sequence with a SHA-256 trailer. The migration manager checks the source lock and file name.
  • The coordination kernel route streams the kernel of the locked source VM with zstd. A source without the kernel returns 404.
ListenerCallerRoutes
ControlAtlas client certificate/v1/sync, /v1/vms, /v1/snapshots, destination /v1/migrations/:id
CoordinationRegional node certificateSource routes under /v1/migrations/:id
Snapshot streamOne-shot mutual TLSOwned by vm/migration

Capacity ​

Compute and disk handlers check only the increase against host memory and storage. CPU is never checked. See the controller contract.

Authentication ​

  • Each route group names its middleware, so a route cannot inherit the wrong rule.
  • The TLS listeners verify the client certificate. This package holds no credential.
  • An unknown path or a wrong method under /v1 returns 404.

See security for the certificate that each listener accepts.

Errors ​

A domain error maps to one status and one safe message. An unknown error becomes 500 with no detail, and the log keeps its cause under the request ID.

Domain errorStatusCode
vm.ErrNotFound, storage.ErrNotFound404not_found
vm.ErrConflict, storage.ErrInUse409conflict
Compute or disk increase without host capacity409insufficient_capacity
storage.ErrImageConflict409image_content_conflict
storage.ErrImageIntegrity422image_integrity_failed
storage.ErrShuttingDown503unavailable
network.ErrInvalidPeers, storage.ErrInvalidUpload, vm.ErrMetadataServiceTooLarge400invalid_request
  • Every error body carries a retryable flag. 501 is never retryable.
  • POST /v1/sync maps a host-state not-found to 503, not 404. A 404 would stop the controller retry.
  • Responses never carry command output, signed URL values, or local error detail.
  • http.Server.Shutdown does not track WebSockets. Close each console with 1012 on shutdown so the Atlas bridge reconnects.

AGPL-3.0