gRPC API reference¶
Generated from proto/axiom/v1/axiom.proto. Edit that file and run make docs-generate; CI fails on an uncommitted difference.
Package axiom.v1. All calls are TLS-only; credentials are never message fields.
Service GatewayService¶
GatewayService is the cluster-side service the Postgres extension talks to.
| RPC | Request | Response |
|---|---|---|
Ping |
PingRequest |
PingResponse |
Get |
GetRequest |
GetResponse |
List |
ListRequest |
ListResponse |
Create |
CreateRequest |
CreateResponse |
Update |
UpdateRequest |
UpdateResponse |
Delete |
DeleteRequest |
DeleteResponse |
Subscribe |
SubscribeRequest |
stream of SubscribeResponse |
DiscoverSchema |
DiscoverSchemaRequest |
DiscoverSchemaResponse |
ListKinds |
ListKindsRequest |
ListKindsResponse |
Stats |
StatsRequest |
StatsResponse |
Ping¶
rpc Ping(PingRequest) returns (PingResponse);
Ping is a liveness round-trip used by the extension's background worker to verify connectivity and TLS setup. The gateway echoes the caller's nonce so the caller can detect a mismatched/out-of-order reply, and reports its own version and clock for diagnostics.
Errors: INVALID_ARGUMENT if the request nonce is zero (zero is reserved as "unset" so accidental default-constructed requests are rejected loudly).
Get¶
rpc Get(GetRequest) returns (GetResponse);
Get fetches a single object by kind, namespace and name, straight from the API server (never from a cache).
Errors: INVALID_ARGUMENT for an unsupported/malformed gvk or an invalid namespace/name; NOT_FOUND if the object does not exist; PERMISSION_DENIED if the gateway's own RBAC identity may not read it; FAILED_PRECONDITION if the gateway has no cluster configured; UNAVAILABLE if the API server cannot be reached.
List¶
rpc List(ListRequest) returns (ListResponse);
List fetches objects of one kind, optionally narrowed to a namespace and/or a single name. Filters are applied server-side (namespace scoping and a metadata.name field selector), never by fetching everything and filtering in the gateway.
Errors: as for Get, except that a filter matching nothing is an empty response, not NOT_FOUND.
Create¶
rpc Create(CreateRequest) returns (CreateResponse);
Create creates one object from its JSON body. The gateway forces apiVersion/kind from gvk and requires body metadata.name/namespace (if present) to equal the request fields.
Errors: INVALID_ARGUMENT for an unsupported gvk, invalid names, a body that is not a JSON object or whose identity disagrees with the request, or a body the API server rejects as invalid; ALREADY_EXISTS if an object with that name exists; PERMISSION_DENIED / FAILED_PRECONDITION / UNAVAILABLE as for Get.
Update¶
rpc Update(UpdateRequest) returns (UpdateResponse);
Update replaces one object (HTTP PUT) with optimistic concurrency: the request must carry the resource_version the caller last read, and the API server rejects the write if the object has changed since.
Errors: INVALID_ARGUMENT if resource_version is empty or the body/identity is invalid (as for Create); ABORTED if the resource_version is stale (HTTP 409 Conflict) so callers can distinguish "retry after re-read" from every other failure; NOT_FOUND if the object no longer exists; PERMISSION_DENIED / FAILED_PRECONDITION / UNAVAILABLE as for Get.
Delete¶
rpc Delete(DeleteRequest) returns (DeleteResponse);
Delete deletes one object by name.
Errors: INVALID_ARGUMENT for unsupported gvk / invalid names; NOT_FOUND if it does not exist; PERMISSION_DENIED / FAILED_PRECONDITION / UNAVAILABLE as for Get.
Subscribe¶
rpc Subscribe(SubscribeRequest) returns (stream SubscribeResponse);
Subscribe streams the current state and then live changes of one kind, optionally narrowed to a namespace. This is the feed behind the extension's shared-memory cache; one stream per (cluster, kind, namespace) is held open by the extension's background worker.
Without resource_version the gateway performs a full LIST and emits every object as ADDED with an EMPTY resource_version (a partial listing is not a valid resume point), then a SYNCED event carrying the list's resourceVersion, then live ADDED/MODIFIED/DELETED events and BOOKMARK events. With a resource_version the gateway resumes the watch from that point and sends no initial listing and no SYNCED: the backlog since the bookmark is delivered as ordinary events, and the API server's first BOOKMARK (which it only sends once the watcher is caught up) is the caller's signal that the cache is current again. If the API server no longer has that history (HTTP 410 Gone) the gateway emits RESYNC_REQUIRED and ends the stream, and the caller must resubscribe without a resource_version and rebuild its cache.
Errors: INVALID_ARGUMENT for unsupported gvk / invalid namespace; PERMISSION_DENIED / FAILED_PRECONDITION / UNAVAILABLE as for Get. Once streaming, transient watch drops are handled inside the gateway by re-watching from the last seen resourceVersion; the stream only ends on RESYNC_REQUIRED, a non-retryable error, or client cancellation.
DiscoverSchema¶
rpc DiscoverSchema(DiscoverSchemaRequest) returns (DiscoverSchemaResponse);
DiscoverSchema resolves one kind against the cluster's discovery and OpenAPI documents and returns the foreign-table shape the extension should use for it. It is called at IMPORT FOREIGN SCHEMA time, never on the scan path: the generated DDL carries the resolved identity in table options, so a scan needs no discovery round-trip.
The columns returned are the promoted metadata scalars, the kind's own top-level object fields (spec/status/data/...), and raw — see docs/DESIGN.md §5.4. The gateway only decides which columns exist; how a column is read out of an object is fixed by the extension's projection rule, so the two sides cannot disagree about a column's value.
Errors: INVALID_ARGUMENT for a malformed gvk; NOT_FOUND if the cluster has no such kind; PERMISSION_DENIED if serving it is outside the gateway's configured allowlist or its own RBAC; FAILED_PRECONDITION if the gateway has no cluster configured; UNAVAILABLE if the API server cannot be reached.
ListKinds¶
rpc ListKinds(ListKindsRequest) returns (ListKindsResponse);
ListKinds enumerates the kinds this gateway is configured to serve, optionally narrowed to one API group and/or an explicit set of plural names. It backs IMPORT FOREIGN SCHEMA, which needs every kind's shape in one round-trip rather than one DiscoverSchema call per table.
The result is bounded by the gateway's serve allowlist, so it describes what this deployment offers, not everything the cluster has. A kind the allowlist permits but the API server does not have is omitted rather than reported as an error.
Errors: INVALID_ARGUMENT for a malformed filter; FAILED_PRECONDITION if the gateway has no cluster configured; UNAVAILABLE if the API server cannot be reached.
Stats¶
rpc Stats(StatsRequest) returns (StatsResponse);
Stats reports monotonic counters for the work this gateway process has done since it started, plus when that was.
It exists because counting is the only honest way to assert things like "the cache served that scan without touching the API server" or "the resumed watch did not relist". Those were asserted by grepping the gateway's stdout, which does not survive the process being restarted -- and a restart mid-watch is exactly the scenario worth testing. Counters reset with the process, which makes "since you came back, how many listings have you done" directly expressible.
Operationally it answers "what is this gateway actually doing", which is otherwise only visible by reading logs.
Errors: none beyond transport. Deliberately cheap and side-effect free, so it is safe to poll.
Enums¶
SqlType¶
SqlType is the Postgres type a discovered column is declared with.
A field is typed only when its OpenAPI schema names exactly one scalar type (docs/DESIGN.md §5.4, #79); anything structured or ambiguous is jsonb. The declared type is what the extension converts each value to and from.
BIGINT, BOOLEAN and TIMESTAMPTZ are sent only to a caller that sets typed_columns on its request. An extension that predates them maps an unknown value to "no column" and would silently drop the column from the table it generates, so it gets TEXT and JSONB as before.
| Value | Number | Description |
|---|---|---|
SQL_TYPE_UNSPECIFIED |
0 | — |
SQL_TYPE_TEXT |
1 | — |
SQL_TYPE_JSONB |
2 | — |
SQL_TYPE_BIGINT |
3 | — |
SQL_TYPE_BOOLEAN |
4 | — |
SQL_TYPE_TIMESTAMPTZ |
5 | — |
SubscribeResponse.Type¶
| Value | Number | Description |
|---|---|---|
TYPE_UNSPECIFIED |
0 | — |
TYPE_ADDED |
1 | Object exists (initial listing) or was created. |
TYPE_MODIFIED |
2 | Object changed. |
TYPE_DELETED |
3 | Object was deleted; object carries its last known state. |
TYPE_SYNCED |
4 | The initial listing is complete and the cache is current; resource_version is the list's. |
TYPE_BOOKMARK |
5 | No change; resource_version advances the resume point. The API server emits bookmarks only for a caught-up watcher, so on a resumed stream the first BOOKMARK also means "current again". |
TYPE_RESYNC_REQUIRED |
6 | The requested resource_version is too old (410 Gone). The stream ends after this event; resubscribe without a resource_version. |
Messages¶
ColumnSchema¶
ColumnSchema is one column of a kind's foreign table.
| Field | Type | Description |
|---|---|---|
name |
string |
SQL column name. Always a lowercase identifier that needs no quoting; the extension quotes it anyway when generating DDL (docs/RULES.md §3). |
sql_type |
SqlType |
— |
source |
string |
Origin of the column, e.g. "metadata.name" or "spec". For a column the extension maps to a top-level field, it is that field's exact name, e.g. "stringData": IMPORT FOREIGN SCHEMA records it as the column's field option, which an INSERT needs to write the field under its real spelling (#97). For any other column it is diagnostics only. |
CreateRequest¶
| Field | Type | Description |
|---|---|---|
gvk |
GroupVersionKind |
— |
namespace |
string |
— |
name |
string |
— |
json |
bytes |
Full object as JSON. apiVersion/kind are overwritten from gvk. |
CreateResponse¶
| Field | Type | Description |
|---|---|---|
object |
Object |
The object as stored by the API server (with uid, resourceVersion, defaults). |
DeleteRequest¶
| Field | Type | Description |
|---|---|---|
gvk |
GroupVersionKind |
— |
namespace |
string |
— |
name |
string |
— |
DeleteResponse¶
No fields.
DiscoverSchemaRequest¶
| Field | Type | Description |
|---|---|---|
gvk |
GroupVersionKind |
— |
typed_columns |
bool |
The caller understands SQL_TYPE_BIGINT, SQL_TYPE_BOOLEAN and SQL_TYPE_TIMESTAMPTZ. Unset, every column is TEXT or JSONB, as it was before those existed. |
DiscoverSchemaResponse¶
| Field | Type | Description |
|---|---|---|
schema |
KindSchema |
— |
GetRequest¶
| Field | Type | Description |
|---|---|---|
gvk |
GroupVersionKind |
— |
namespace |
string |
Required for namespaced kinds, must be empty for cluster-scoped kinds. |
name |
string |
— |
GetResponse¶
| Field | Type | Description |
|---|---|---|
object |
Object |
— |
GroupVersionKind¶
GroupVersionKind identifies a Kubernetes resource kind. Group is empty for the core API group.
| Field | Type | Description |
|---|---|---|
group |
string |
— |
version |
string |
— |
kind |
string |
— |
KindSchema¶
KindSchema is everything the extension needs to define and serve a foreign table for one kind.
| Field | Type | Description |
|---|---|---|
gvk |
GroupVersionKind |
— |
plural |
string |
Plural resource name as it appears in the REST path, e.g. "pods", "widgets". This is the resource table option. |
namespaced |
bool |
False for cluster-scoped kinds, whose objects have no namespace. |
columns |
repeated ColumnSchema |
— |
writable |
bool |
True when the API server advertises create/update/delete verbs for the kind. This reflects what the API supports, not what the gateway's RBAC identity is permitted to do: a write may still be denied at execution. |
watchable |
bool |
True when the API server advertises the watch verb, so a cache_mode 'watch' table is possible for this kind. |
ListKindsRequest¶
| Field | Type | Description |
|---|---|---|
plurals |
repeated string |
If non-empty, only kinds whose plural name appears here. Names that match nothing are silently absent from the response rather than an error, so a caller can pass a speculative list. |
typed_columns |
bool |
As DiscoverSchemaRequest.typed_columns. |
ListKindsResponse¶
| Field | Type | Description |
|---|---|---|
kinds |
repeated KindSchema |
— |
ListRequest¶
| Field | Type | Description |
|---|---|---|
gvk |
GroupVersionKind |
— |
namespace |
string |
Empty means all namespaces. |
name |
string |
If non-empty, only the object with exactly this name is returned (server-side metadata.name field selector). |
limit |
int32 |
Maximum objects in one response. Zero asks the gateway to choose. The gateway clamps this to its own maximum, so a caller cannot use it to demand a response too large to send. A page is bounded by bytes as well as by count, because objects vary by three orders of magnitude: a count that is comfortable for Pods can exceed the message limit for ConfigMaps holding a megabyte each. |
continue_token |
string |
Continues a previous List. Pass back the continue_token from the last response; empty starts a new listing. The token is the gateway's, not the API server's: it wraps the Kubernetes continuation together with the page size settled for this walk, and is not usable against Kubernetes directly. Treat it as opaque. It carries a snapshot, so it expires when that snapshot is compacted. Resuming an expired one fails with ABORTED rather than silently restarting, because earlier pages have already been returned to the caller and restarting would duplicate them. |
ListResponse¶
| Field | Type | Description |
|---|---|---|
objects |
repeated Object |
— |
resource_version |
string |
resourceVersion of the list itself, usable as a watch start point. |
continue_token |
string |
Non-empty when more objects remain: pass it as the next request's continue_token, unchanged. Empty means this was the last page. Opaque, and issued by the gateway rather than by Kubernetes. |
Object¶
Object is one Kubernetes object as returned by the API server.
| Field | Type | Description |
|---|---|---|
namespace |
string |
metadata.namespace; empty for cluster-scoped kinds. |
name |
string |
metadata.name. |
resource_version |
string |
metadata.resourceVersion, opaque; carried for Phase 2 optimistic concurrency and Phase 3 watch bookmarks. |
json |
bytes |
The full object as JSON, exactly as serialised by the API server. The receiver must treat this as untrusted input and bounds-check it. |
PingRequest¶
| Field | Type | Description |
|---|---|---|
nonce |
uint64 |
Caller-chosen, non-zero. Echoed back verbatim in PingResponse.nonce. |
PingResponse¶
| Field | Type | Description |
|---|---|---|
nonce |
uint64 |
Echo of PingRequest.nonce. |
gateway_version |
string |
Gateway build version string (e.g. "0.1.0" or a git describe). |
server_time |
google.protobuf.Timestamp |
Gateway wall-clock time at the moment the reply was built. |
StatsRequest¶
No fields.
StatsResponse¶
StatsResponse carries counters for one gateway process. Every counter is monotonic within a process lifetime and resets when it restarts; started_at_unix_seconds is how a caller tells a restart from a quiet period.
| Field | Type | Description |
|---|---|---|
started_at_unix_seconds |
int64 |
Wall-clock time the process started, for detecting a restart. |
get_calls |
uint64 |
Unary RPCs served, by kind of call. |
list_calls |
uint64 |
— |
create_calls |
uint64 |
— |
update_calls |
uint64 |
— |
delete_calls |
uint64 |
— |
subscribe_calls |
uint64 |
Subscribe streams opened, and how many of those performed a full initial listing rather than resuming from a bookmark. A resume that relists shows up here as an increment the caller did not expect. |
subscribe_list_calls |
uint64 |
— |
openapi_fetches |
uint64 |
Discovery: OpenAPI documents fetched and parsed, and how many distinct group-versions those covered. Serving a whole cluster should fetch one document per group-version, not one per kind. |
openapi_group_versions |
uint64 |
— |
access_reviews |
uint64 |
Access reviews issued against the authorization API while deciding which kinds this gateway may serve. |
SubscribeRequest¶
| Field | Type | Description |
|---|---|---|
gvk |
GroupVersionKind |
— |
namespace |
string |
Empty means all namespaces. |
resource_version |
string |
Empty means "list everything first"; otherwise resume the watch from here. |
SubscribeResponse¶
SubscribeResponse is one watch event.
| Field | Type | Description |
|---|---|---|
type |
Type |
— |
object |
Object |
Present for TYPE_ADDED/TYPE_MODIFIED/TYPE_DELETED. |
resource_version |
string |
Present for TYPE_SYNCED/TYPE_BOOKMARK and, when known, for TYPE_RESYNC_REQUIRED, and for live TYPE_ADDED/MODIFIED/DELETED events. Empty on initial-listing TYPE_ADDED events: never resume from those. |
UpdateRequest¶
| Field | Type | Description |
|---|---|---|
gvk |
GroupVersionKind |
— |
namespace |
string |
— |
name |
string |
— |
resource_version |
string |
Required. The metadata.resourceVersion the caller last read. |
json |
bytes |
Full replacement object as JSON. metadata.resourceVersion inside the body, if present, must equal resource_version. |
UpdateResponse¶
| Field | Type | Description |
|---|---|---|
object |
Object |
— |