better/compute
API

nodes

Nodes are machines that joined the control plane, as their tenant sees them: a tenant sees the nodes the authorization projection holds for it. Every method except `list` is decided on `compute-node/{nodeId}`. Mutations take an optional `version`; when the node has moved past it, the call is `CONFLICT`. See [Operating nodes](/docs/guides/nodes/operating-nodes).

Nodes are machines that joined the control plane, as their tenant sees them: a tenant sees the nodes the authorization projection holds for it. Every method except list is decided on compute-node/{nodeId}. Mutations take an optional version; when the node has moved past it, the call is CONFLICT. See Operating nodes.

All 14 methods are served by this release.

MethodKindAuthorizationPhaseStatus
listreadcompute:nodes:read @ compute-tenant + itemsv0.1registered
getreadcompute:nodes:read @ compute-nodev0.1registered
eventsreadcompute:nodes:read @ compute-nodev0.1registered
cordonmutationcompute:nodes:cordon @ compute-nodev0.1registered
uncordonmutationcompute:nodes:cordon @ compute-nodev0.1registered
drainmutationcompute:nodes:drain @ compute-nodev0.1registered
labelmutationcompute:nodes:update @ compute-nodev0.1registered
taintmutationcompute:nodes:update @ compute-nodev0.1registered
adoptmutationcompute:nodes:provision @ compute-nodev0.1registered
revokeIdentitymutationcompute:nodes:revoke-identity @ compute-nodev0.1registered
deletemutationcompute:nodes:delete @ compute-nodev0.2registered
issueSshCertmutationcompute:nodes:ssh-root @ compute-nodev0.3registered
revokeSshCertmutationcompute:nodes:ssh-root @ compute-nodev0.3registered
listSshCertsreadcompute:nodes:read—registered

list

POST /api/compute/nodes/list

Lists the nodes visible to the tenant in id order, filtered by pool, site, cordoned or provisionState.

The call is decided once on compute-tenant/{tenantId}, then each node is checked for compute:nodes:read; nodes the caller may not read are left out, so a page can hold fewer than limit items. Pages hold up to 50 nodes.

  • Kind: read
  • Authorization: compute:nodes:read @ compute-tenant + items
  • Module: server
  • Phase: v0.1 (registered)

Input

FieldTypeRequiredConstraints
tenantIdstringyesat most 128 characters; matches ^[A-Za-z0-9._:-]{1,128}$
poolIdstringat most 128 characters; matches ^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$
siteIdstringat most 64 characters; matches ^site_[0-9a-hjkmnp-tv-z]{26,52}$
cordonedboolean
provisionStateone of adopting, adopted, enrolling, inspecting, commissioning, ready, deploying, deployed, releasing, rescue, failed, retiring, retired
limitinteger1-50; default 50
cursorstringat most 256 characters; matches ^[A-Za-z0-9._:-]{1,256}$

get

POST /api/compute/nodes/get

Returns one node with its labels, conditions and session (epoch, gateway and connection times).

A node the tenant cannot see is NOT_FOUND.

  • Kind: read
  • Authorization: compute:nodes:read @ compute-node
  • Module: server
  • Phase: v0.1 (registered)

Input

FieldTypeRequiredConstraints
tenantIdstringyesat most 128 characters; matches ^[A-Za-z0-9._:-]{1,128}$
nodeIdstringyesat most 64 characters; matches ^node_[0-9a-hjkmnp-tv-z]{26,52}$

events

POST /api/compute/nodes/events

Returns a node's events from the event outbox, oldest first.

type keeps only events whose type starts with the given prefix, such as node. or security.. Pages hold up to 200 events (100 by default). A node the tenant cannot see is NOT_FOUND.

  • Kind: read
  • Authorization: compute:nodes:read @ compute-node
  • Module: server
  • Phase: v0.1 (registered)

Input

FieldTypeRequiredConstraints
tenantIdstringyesat most 128 characters; matches ^[A-Za-z0-9._:-]{1,128}$
nodeIdstringyesat most 64 characters; matches ^node_[0-9a-hjkmnp-tv-z]{26,52}$
typestringat most 64 characters; matches ^[a-z][a-z0-9.-]{0,63}$
limitinteger1-200; default 100
cursorstringat most 41 characters; matches ^\d{1,20}:\d{1,20}$

cordon

POST /api/compute/nodes/cordon

Marks the node cordoned so placement puts no new work on it; existing allocations stay.

Cordoning a cordoned node returns it unchanged and publishes nothing. Otherwise the node's version goes up, its reconciler is queued, and node.cordoned is published.

  • Kind: mutation
  • Authorization: compute:nodes:cordon @ compute-node
  • Module: server
  • Phase: v0.1 (registered)

Input

FieldTypeRequiredConstraints
tenantIdstringyesat most 128 characters; matches ^[A-Za-z0-9._:-]{1,128}$
nodeIdstringyesat most 64 characters; matches ^node_[0-9a-hjkmnp-tv-z]{26,52}$
versionintegerat least 1
reasonstringat most 256 characters; matches ^[^\u0000-\u001f\u007f]*$

uncordon

POST /api/compute/nodes/uncordon

Clears cordoned and ends a drain in progress, so the node is placeable again.

Decided as compute:nodes:cordon. A node that is neither cordoned nor draining is returned unchanged. Otherwise the draining reason is removed and node.uncordoned is published.

  • Kind: mutation
  • Authorization: compute:nodes:cordon @ compute-node
  • Module: server
  • Phase: v0.1 (registered)

Input

FieldTypeRequiredConstraints
tenantIdstringyesat most 128 characters; matches ^[A-Za-z0-9._:-]{1,128}$
nodeIdstringyesat most 64 characters; matches ^node_[0-9a-hjkmnp-tv-z]{26,52}$
versionintegerat least 1
reasonstringat most 256 characters; matches ^[^\u0000-\u001f\u007f]*$

drain

POST /api/compute/nodes/drain

Cordons the node, adds the draining NoSchedule reason and hands the node to the Drain controller.

The Drain controller releases nothing in this release: it waits until the node holds no live allocation, then removes draining and publishes node.drained. The node stays cordoned until uncordon. Draining a node that is already draining returns it unchanged. A new drain publishes node.draining.

  • Kind: mutation
  • Authorization: compute:nodes:drain @ compute-node
  • Module: server
  • Phase: v0.1 (registered)

Input

FieldTypeRequiredConstraints
tenantIdstringyesat most 128 characters; matches ^[A-Za-z0-9._:-]{1,128}$
nodeIdstringyesat most 64 characters; matches ^node_[0-9a-hjkmnp-tv-z]{26,52}$
versionintegerat least 1
reasonstringat most 256 characters; matches ^[^\u0000-\u001f\u007f]*$

label

POST /api/compute/nodes/label

Sets and removes operator labels on the node and returns the node with its labels.

set takes up to 64 labels and remove up to 64 keys. The call is INVALID_INPUT when it names nothing, names a key in both set and remove, or sets a key that inventory or the system owns. remove removes only operator labels. The node's version goes up and node.labeled is published.

  • Kind: mutation
  • Authorization: compute:nodes:update @ compute-node
  • Module: server
  • Phase: v0.1 (registered)

Input

FieldTypeRequiredConstraints
tenantIdstringyesat most 128 characters; matches ^[A-Za-z0-9._:-]{1,128}$
nodeIdstringyesat most 64 characters; matches ^node_[0-9a-hjkmnp-tv-z]{26,52}$
setmap of stringat most 64 entries; keys match ^[A-Za-z0-9](?:[A-Za-z0-9._/-]{0,126}[A-Za-z0-9])?$
removelist of string0-64 items; no repeats
versionintegerat least 1

taint

POST /api/compute/nodes/taint

Adds and removes operator NoSchedule taints, stored in noScheduleReasons as taint:<key>.

add and remove take up to 32 keys each. The call is INVALID_INPUT when it names nothing or names a key in both lists. Only operator taints change; conditions, unreachable and draining belong to their controllers. When the result equals the current reasons the node is returned unchanged; otherwise node.tainted is published.

  • Kind: mutation
  • Authorization: compute:nodes:update @ compute-node
  • Module: server
  • Phase: v0.1 (registered)

Input

FieldTypeRequiredConstraints
tenantIdstringyesat most 128 characters; matches ^[A-Za-z0-9._:-]{1,128}$
nodeIdstringyesat most 64 characters; matches ^node_[0-9a-hjkmnp-tv-z]{26,52}$
addlist of string0-32 items; no repeats
removelist of string0-32 items; no repeats
versionintegerat least 1

adopt

POST /api/compute/nodes/adopt

Re-runs acceptance checks on a node in adopting or adopted, moving it to adopting.

Decided as compute:nodes:provision. Any other provision state is INVALID_STATE. The node leaves placement until acceptance passes. Publishes node.adopting.

  • Kind: mutation
  • Authorization: compute:nodes:provision @ compute-node
  • Module: server
  • Phase: v0.1 (registered)

Input

FieldTypeRequiredConstraints
tenantIdstringyesat most 128 characters; matches ^[A-Za-z0-9._:-]{1,128}$
nodeIdstringyesat most 64 characters; matches ^node_[0-9a-hjkmnp-tv-z]{26,52}$
versionintegerat least 1
reasonstringat most 256 characters; matches ^[^\u0000-\u001f\u007f]*$

revokeIdentity

POST /api/compute/nodes/revokeIdentity

Revokes every live certificate of the node and raises its identity generation, so no certificate of the old generation can renew.

Returns the node and revokedCertificates, the number of certificates revoked; the revocation reason is reason, or identity revoked. Each call raises the generation again. The machine comes back only by joining again. Publishes security.node.identity-revoked.

  • Kind: mutation
  • Authorization: compute:nodes:revoke-identity @ compute-node
  • Module: server
  • Phase: v0.1 (registered)

Input

FieldTypeRequiredConstraints
tenantIdstringyesat most 128 characters; matches ^[A-Za-z0-9._:-]{1,128}$
nodeIdstringyesat most 64 characters; matches ^node_[0-9a-hjkmnp-tv-z]{26,52}$
versionintegerat least 1
reasonstringat most 256 characters; matches ^[^\u0000-\u001f\u007f]*$

delete

POST /api/compute/nodes/delete

Tombstones a node that is retired, adopting or enrolling (or failed from adopting or enrolling), or an adopted node that is cordoned, and has no open allocation. An adopted host has no retire workflow: cordon it, wait until it holds nothing, then delete it. For example, after its TPM or disk was replaced, deleting it lets the machine join again under a new identity.

Any other state, or an open allocation, is INVALID_STATE; a node that changed pools during the call is CONFLICT. The node's devices stop being bookable, its scalar resources are removed, its certificates are revoked, its hardware key and attestor bindings are freed so the machine can join again as a new node, and its pending commands are cancelled. The node leaves its pool and the projection, so nobody sees it; audit rows and past allocations keep referencing it.

A retry after the delete returns deleted: false. Publishes node.deleted.

  • Kind: mutation
  • Authorization: compute:nodes:delete @ compute-node
  • Module: server
  • Phase: v0.2 (registered)

Input

FieldTypeRequiredConstraints
tenantIdstringyesat most 128 characters; matches ^[A-Za-z0-9._:-]{1,128}$
nodeIdstringyesat most 64 characters; matches ^node_[0-9a-hjkmnp-tv-z]{26,52}$
versionintegerat least 1
reasonstringat most 256 characters; matches ^[^\u0000-\u001f\u007f]*$

issueSshCert

POST /api/compute/nodes/issueSshCert

Issues a short-lived break-glass OpenSSH user certificate for one node, bound to the principal <account>@<nodeId>.

Decided as compute:nodes:ssh-root. The method comes from the tunnels module (v0.3) and is UNSUPPORTED when no compute SSH CA is configured. It needs an MFA session by default (ACCESS_DENIED with reason mfa-required), and a session that ends within a minute is ACCESS_DENIED. publicKey must be an Ed25519 or ECDSA P-256 key, and principal (default root) one of the configured accounts; otherwise INVALID_INPUT.

The lifetime is ttlSeconds (60 to 3,600, default 900), never past the caller's session. Issuance is rate-limited per identity (20 per hour by default, then RATE_LIMITED). Every certificate is recorded and node.ssh-cert.issued is published.

  • Kind: mutation
  • Authorization: compute:nodes:ssh-root @ compute-node
  • Module: tunnels
  • Phase: v0.3 (registered)

Input

FieldTypeRequiredConstraints
tenantIdstringyesat most 128 characters; matches ^[A-Za-z0-9._:-]{1,128}$
nodeIdstringyesat most 57 characters; matches ^node_[0-9a-z]{26,52}$
publicKeystringyesat most 4096 characters
principalstringmatches ^[a-z_][a-z0-9_-]{0,31}$; default "root"
ttlSecondsinteger60-3600; default 900

revokeSshCert

POST /api/compute/nodes/revokeSshCert

Revokes a break-glass SSH certificate before it expires; the node's revocation list carries it from the next NodeSpec on.

Decided as compute:nodes:ssh-root and hosted by the tunnels module (v0.3). Revoking again returns the same revocation. A serial not issued for this node is NOT_FOUND. Publishes node.ssh-cert.revoked.

  • Kind: mutation
  • Authorization: compute:nodes:ssh-root @ compute-node
  • Module: tunnels
  • Phase: v0.3 (registered)

Input

FieldTypeRequiredConstraints
tenantIdstringyesat most 128 characters; matches ^[A-Za-z0-9._:-]{1,128}$
nodeIdstringyesat most 57 characters; matches ^node_[0-9a-z]{26,52}$
serialstringyesmatches ^[0-9]{1,20}$
reasonstringat most 500 characters

listSshCerts

POST /api/compute/nodes/listSshCerts

Lists the break-glass SSH certificates the tenant issued for one node, newest first, with each one's principal, issuer, lifetime and state; never the certificate itself.

Decided as compute:nodes:read on compute-node/{nodeId} and hosted by the tunnels module. state is active, expired or revoked; a revoked certificate also carries revokedAt, revokedBy (an identity, or iam when re-authorization revoked it) and revokeReason when one was given.

Only unexpired certificates are listed unless includeExpired is true; expired certificates are kept for one day, then removed by an hourly clean-up. Pages hold 1 to 500 certificates (100 by default), and nextCursor is set while more remain. A node the tenant cannot see is NOT_FOUND, and a malformed cursor is INVALID_INPUT.

  • Kind: read
  • Authorization: compute:nodes:read
  • Module: tunnels
  • Phase: not in PLAN.md §9.2 (registered)

Input

FieldTypeRequiredConstraints
tenantIdstringyesat most 128 characters; matches ^[A-Za-z0-9._:-]{1,128}$
nodeIdstringyesat most 57 characters; matches ^node_[0-9a-z]{26,52}$
includeExpiredbooleandefault false
limitinteger1-500; default 100
cursorstringat most 128 characters

Was this page helpful?

Better Compute is created by Sean Filimon

Last updated

On this page