Opsmaru.Incus.Gateway.Plug (opsmaru_incus v0.1.0)

Copy Markdown View Source

Mountable Plug relaying native Incus HTTP and optional WebSockets through host policy.

Mount it for the canonical native routes, before any body parser:

# Phoenix router: one root discovery route plus the /1.0 tree.
get "/", Opsmaru.Incus.Gateway.Plug, gateway: {MyHost.Gateway, :fetch, []}
forward "/1.0", Opsmaru.Incus.Gateway.Plug, gateway: {MyHost.Gateway, :fetch, []}

:gateway is either an Opsmaru.Incus.Gateway or an {module, function, args} returning one at request time; prefer the MFA so runtime configuration and the admission pid are never compiled into the router.

Routing uses the original encoded request_path and raw query_string, so forward does not change what the backend receives. Only /, /1.0 and /1.0/* are relayed; other paths fail with a native 404 and no backend contact. If a body parser already consumed the request, the gateway refuses it with 500 rather than relaying a reconstructed body.

Every request goes through Opsmaru.Incus.Gateway.Policy (admission, readiness, authorization, expiry/revocation) before a backend socket opens. Discovery and certificate trust use bounded host callbacks; authenticated GET /1.0 buffers/replaces public identity. WebSockets use the optional native WebSocket adapter when available; raw SFTP/NBD requires the host's same-listener Cowboy gateway handler. Missing adapters fail with 501. See docs/gateway.md for the verified protocol and mounting contract.

Response streaming is tested with Plug.Cowboy. When a response that has already started cannot be completed (backend loss, deadline, budget, revocation), the gateway ends the caller's HTTP/1.x connection without a final chunk, so the caller sees a truncated response rather than a complete one. On HTTP/2 it resets the stream.