Kibotos

Write operations and errors

Every program that changes state through the API follows the same rules: query the server's capabilities first, carry a command ID and an expected revision on write requests, and read errors in one format. This page describes each rule and the fields that carry it.

Querying capabilities first

Before calling business methods, call ServerInfoService/GetServerInfo. The response has two fields:

FieldMeaning
source_revisionThe source revision the server was built from, for display only
capabilitiesA list of strings such as workspace.create, workspace.filesystem, and workspace.desktop. For the full list and naming rules, see Capability names
  • There is no API version number to compare.
  • When an operation needs a capability that is not in the list, fail that one operation instead of rejecting the whole server.
  • Before each command, kibo matches the exact string and exits with code 14 when it is missing.

Write operation conventions

Two fields make write requests safe to repeat and safe to run concurrently. A command ID lets you resend a request without running it twice. An expected revision keeps a request from overwriting someone else's change.

Command IDs

Except for the two requests listed below, every write request carries a client-generated command ID:

SurfaceField locationFormat
Workspace APICommandMetadata metadata in the request, field command_id^[A-Za-z0-9][A-Za-z0-9._/-]*$, 1 to 128 bytes
Operator APIstring command_id in the requestSame as above

v0.3.x still accepts a command ID that does not match this format. From v0.4.0 it returns a non-retryable invalid_argument. For how deployers find such callers, see Upgrade from v0.2.x to v0.3.0.

These IDs have further limits:

IDLimitIf it does not comply
All write requestsCannot start with expiration/, host-memory/, or guest-shutdown/. These prefixes are reserved for commands ctrl starts itselfThe Workspace API returns invalid_argument now. The Operator API does from v0.4.0
command_id of ApplyArtifactReclamationCannot contain /invalid_argument
command_id of Template and Platform publications in BeginArtifactPublicationMatches ^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$: it cannot contain / and can contain :BeginArtifactPublication itself succeeds, and the publication fails when it writes the manifest
  • GetWorkspaceCommand and GetVolumeCommand read existing commands, so these rules do not apply to their IDs.
  • kibotos.ValidateCommandID in the Go SDK checks the format and reserved prefixes above. Your program must call it; the SDK does not check when it sends a request. kibo checks --command-id before it sends the request.

The command ID appears only in the request message; it is not an HTTP header. Save it before you submit.

The server compares the ID and the input with what it already has:

  • Submitting again with the same command ID and the same input returns the first result and does not run the command again. Failures replay too: after a command fails, the same ID returns only that failure.
  • A command ID stands for one attempt. While the result is unknown or the command is still running, keep the ID. When the error details have command_settled, the failure is final, so a new attempt takes a new ID.
  • When you derive a command ID from an object, for example to avoid creating it twice, include something that changes between attempts, such as the failure count. Otherwise the command can never run again after one failure.
  • Submitting with the same command ID but a different input returns already_exists.
  • CreateWorkspace and UpdateWorkspaceNetworkPolicy ignore network_policy.revision when comparing inputs. The server assigns this value, and whatever the request contains is ignored.

RevokeEnrollment and RetainLaunchRevision have no command ID because their effects can be applied repeatedly. Revoking again does not change the result, and retaining again until the same time does not either.

When a command returns

When a command returns depends on the command:

CommandReturnsHow to get the result
CreateWorkspace, StartWorkspaceAs soon as accepted. The Workspace is CREATING or STARTING, and the executor keeps workingGetWorkspaceCommand
StopWorkspace, DeleteWorkspace, RevokeWorkspaceDataPlaneWhen the command completes, waiting at most 1 minuteA timeout returns a retryable UNAVAILABLE and the command keeps running. Query with GetWorkspaceCommand
UpdateWorkspaceNetworkPolicyOn an AVAILABLE Workspace, when the node has confirmed or failed the change, waiting at most 1 minute. On a STOPPED Workspace, at onceA timeout or an unreachable node returns a retryable TIMED_OUT or UNAVAILABLE, and the Workspace is UNKNOWN until the node reports again. See When changes take effect
ExportWorkspace, ImportTransfer, RestoreWorkspaceWhen the command completes, waiting at most 1 minuteTimeouts work the same way. The error details carry the current Transfer; call GetTransfer with its transfer_id
Volume create, resize, and delete, ResizeWorkspaceWritableLayerCompletes within the request; the response carries the resulting stateWhen the result is unknown, use GetVolumeCommand for Volume commands and GetWorkspaceCommand for writable layer resizes

Important

On a timeout or an unknown result, you can also resend with the original command ID. Do not switch to a new one.

Expected revisions

Requests that modify an existing object carry an expected revision. When the object's current revision does not match, the server rejects the request so it does not overwrite someone else's change.

Requests of the Workspace API:

RequestExpected revision fieldObject revision it matches
UpdateWorkspaceExpirationexpected_revisionexpiration.revision
StopWorkspace, StartWorkspace, DeleteWorkspaceexpected_expiration_revisionexpiration.revision. There is a revision number even when no expiration is set
UpdateWorkspaceMemory, UpdateWorkspaceCpuexpected_revisionThe resources revision resources_revision, shared by both
UpdateWorkspaceVolumeBindingexpected_revisionThe Volume binding revision binding_revision, independent of the resources revision
UpdateWorkspaceNetworkPolicyexpected_revision, optionalnetwork_policy.revision. When it is 0, no check is made. When it is not 0, a mismatched revision is rejected even if the content is the same as the current content
UpdateEgress, UpdateResolverexpected_revisionThe revision of the Egress or Resolver
Label and annotation updates of Workspaces, Volumes, Egresses, and Resolvers, such as UpdateWorkspaceLabels and UpdateVolumeAnnotationsexpected_revisionThe object's labels_revision or annotations_revision

Requests of the Operator API:

RequestExpected revision fieldObject revision it matches
DrainNode, CancelNodeDrain, IsolateNode, RetireNode, SetNodeOvercommitexpected_registration_versionThe node's registration_version
SetOvercommitDefaultsexpected_versionThe version of the overcommit defaults
SetStoragePoolCapacityexpected_versionThe storage pool's version
SetPlatformDefaultexpected_revision and expected_default_versionThe current default revision and its pointer version
SetTemplateDefaultexpected_revision, or expect_no_defaultThe current default revision

ResizeWorkspaceWritableLayer and ResizeVolume have no expected revision, only a command ID and a target capacity.

The error for a mismatch depends on the revision:

Mismatched revisionError
The expiration revision: expected_revision of UpdateWorkspaceExpiration, or expected_expiration_revision of stop, start, or deletefailed_precondition
Any other expected revisionaborted

Changing the expiration time also returns failed_precondition when the Workspace state does not allow it. Use observed_workspace in the error details to tell the two cases apart. See Expiration.

A label or annotation update of a deleted object also returns failed_precondition.

After either error, read the object's state again before deciding what to do next. Do not automatically replay the old request with the new revision.

Error format

Errors use the standard Connect error codes. The error details include a kibotos.ctrl.v1.ErrorDetail. Base your handling on these fields:

FieldHow to use it
reasonA finer-grained reason from the FailureReason enum, such as SESSION_EXPIRED, CAPABILITY_UNAVAILABLE, or CONFLICT. Check it before the standard code
retryableWhether trying again may succeed. When it is false, change the request or the object first. command_settled decides which command ID to use
command_settledThis is the command's recorded result: the same command ID only replays it, so retry with a new ID. A retryable failure without this field has no result yet, so resend with the same ID
accepted_bytesOnly on the resource_exhausted that SendInput returns: the bytes the guest accepted before refusing
observed_workspace, observed_volume, observed_transferThe object as it was when the request failed. Use it to decide the next step, for example to tell a revision conflict from a state that does not allow the change

For the other fields, such as stage and message, and for every reason, see ErrorDetail and FailureReason in the API reference.

The exit code of kibo is chosen from reason first and the standard error code second. For the exit codes, see kibo exit codes.

Next steps

On this page