protocol

package
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 28, 2026 License: MIT Imports: 24 Imported by: 0

Documentation

Overview

Package protocol holds the wire-level helpers shared by the control plane and the agent: signed-message preimages (docs/agent-protocol.md section 2) and key fingerprints.

Index

Constants

View Source
const (
	TypeConfigurationOpen        = "configuration.open"
	TypeConfigurationResult      = "configuration.result"
	TypeConfigurationCancel      = "configuration.cancel"
	CapabilityContainerConfigure = "container.configure"
	// ConfigurationLifetime is the longest grant a configuration.open may carry. The alias below
	// shares InspectionOpen.ValidateFor, which enforces InspectionLifetime; the server issues
	// Expires = min(context deadline, now + ConfigurationLifetime) and the agent enforces this
	// bound with ValidateWithin.
	ConfigurationLifetime      = 20 * time.Second
	MaxConfigurationFrameBytes = 320 << 10

	MaxArgv, MaxArgvEntryBytes        = 64, 4096
	MaxListEntries, MaxListEntryBytes = 32, 1024
	MaxConfigurationNetworks          = 16 // the brief's MaxNetworks; that name is the inventory's 200
	MaxLogOptions                     = 16
	// Configuration carries full label values; inventory keeps its display bound.
	MaxConfigurationLabelValueBytes = 4096

	// MountTmpfs is a configuration-only mount kind; inventory reports tmpfs as "other".
	MountTmpfs = "tmpfs"
)
View Source
const (
	TypeDeploymentApply             = "deployment.apply"
	TypeDeploymentResult            = "deployment.result"
	CapabilityDeploymentApply       = "deployment.apply"
	CapabilityDeploymentPull        = "deployment.pull" // the agent runs a service's Pull step
	MaxDeploymentRequestBytes       = 320 << 10
	MaxDeploymentRequestBytesLegacy = 192 << 10 // an agent without CapabilityDeploymentPull
	MaxDeploymentResultBytes        = 160 << 10
	DeploymentLifetime              = 15 * time.Minute
	MaxDeploymentServices           = 100
	MaxDeploymentEnvEntries         = 128
	MaxDeploymentEnvValueBytes      = 16 << 10
	MaxDeploymentEnvBytes           = 64 << 10
	MaxDeploymentPorts              = 64
	MaxDeploymentStepDetailBytes    = 256
	MaxRegistryAuthHosts            = 16
	MaxRegistryAuthSecretBytes      = 4096
	MaxDeploymentVolumes            = 64
	MaxMountPathBytes               = 4096
	StepPrecondition                = "precondition"
	StepImage                       = "image"
	StepPull                        = "pull"
	StepVolume                      = "volume"
	StepStop                        = "stop"
	StepRename                      = "rename"
	StepCreate                      = "create"
	StepStart                       = "start"
	StepRemove                      = "remove"
	StepRecheck                     = "recheck"  // re-inspects the old container at the start of its replacement
	StepRollback                    = "rollback" // restores the replaced container after a failed start; also reports a failed create, rename or stop undo, or a run's container left unsettled
	StepApply                       = "apply"    // a workload apply's update of the object
	StepRollout                     = "rollout"  // a workload apply's wait for the rollout
	// ExplicitProject and ExplicitRevision are the fixed identity of a direct (edit or run) frame.
	ExplicitProject            = "direct"
	ExplicitRevision           = 1
	OutcomeSkipped             = "skipped"
	TypeDeploymentRemove       = "deployment.remove"
	CapabilityDeploymentRemove = "deployment.remove"
	MaxRemovalTargets          = 100 // three steps each fit a result's MaxDeploymentResultSteps
	// MaxClockSkew bounds the difference between the server's clock when it built a frame and
	// the agent's when it reads one, and between an inventory's observed and received times.
	MaxClockSkew = 5 * time.Minute
	// MaxDeploymentResultSteps is eight steps per service (precondition, image or pull,
	// recheck, rename, create, stop, start, remove), one per volume and one rollback: only the
	// service whose step ended the run rolls back. A ninth step per service would
	// break the MaxDeploymentResultBytes proof.
	MaxDeploymentResultSteps = 8*MaxDeploymentServices + MaxDeploymentVolumes + 1
)

Deployment frames carry one plan to the agent and one result back. The request holds resolved environment values: it exists only in memory on both sides and is never logged. See docs/agent-protocol.md, Deployment apply.

View Source
const (
	ResultStepFailed     = "step_failed"     // a step did not succeed; the steps say which
	ResultClockSkew      = "clock_skew"      // issued_at is more than MaxClockSkew from the agent's clock
	ResultInvalidRequest = "invalid_request" // the frame failed Validate
	ResultWrongEndpoint  = "wrong_endpoint"  // the frame names another endpoint
	ResultBusy           = "busy"            // the agent is already applying a deployment
	ResultRestarted      = "restarted"       // the agent restarted after replacement began
	ResultUnreadable     = "unreadable"      // the runtime returned a result the agent could not validate
	// CodeLegacy is the server's reading of a result from an agent built before codes, for a
	// step or a result; no agent emits it.
	CodeLegacy = "legacy"
)

Outcome codes: the closed vocabulary a denied or failed step, and a result that did not succeed, report in. A step's Detail is its code's parameter, never a sentence. See docs/agent-protocol.md, Outcome codes.

View Source
const (
	MaxExecChunkBytes    = 32 << 10
	MaxExecArgs          = 64
	MaxExecArgumentBytes = 8 << 10
	MaxExecDimension     = 512
	ExecIdleTimeout      = 15 * time.Minute
	ExecAbsoluteTimeout  = 8 * time.Hour
)

Runtime exec bounds implement docs/agent-protocol.md section 7. Wire grants and stream admission remain control-plane/agent responsibilities, not runtime policy.

View Source
const (
	TypeExecOpen              = "exec.open"
	TypeExecReady             = "exec.ready"
	TypeExecInput             = "exec.input"
	TypeExecOutput            = "exec.output"
	TypeExecResize            = "exec.resize"
	TypeExecCancel            = "exec.cancel"
	TypeExecClose             = "exec.close"
	MaxExecStreamsPerEndpoint = 4
	ExecGrantLifetime         = time.Minute
	MaxExecFrameBytes         = 64 << 10
)

Exec grants travel only over the authenticated agent socket. Connection is the handshake nonce, so a grant from an old socket cannot start a second process.

View Source
const (
	TypeInspectionOpen         = "inspection.open"
	TypeInspectionResult       = "inspection.result"
	TypeInspectionCancel       = "inspection.cancel"
	InspectionLifetime         = 25 * time.Second
	MaxInspectionFrameBytes    = 32 << 10
	MaxInspectionsPerEndpoint  = 2
	CapabilityContainerInspect = "container.inspect"
	// CapabilityContainerInspectVerdict marks an agent whose inspections carry the unsupported
	// codes and configuration_verified; plans need it, the inspection dialog does not.
	CapabilityContainerInspectVerdict = "container.inspect.verdict"
	// CapabilityContainerInspectHealth marks an agent whose inspections carry health and
	// restart_count; health validation needs it.
	CapabilityContainerInspectHealth = "container.inspect.health"
	// MaxRestartCount bounds a reported restart count.
	MaxRestartCount = 1_000_000
	MaxUnsupported  = 40
)
View Source
const (
	MaxContainers = 1000
	MaxImages     = 1000
	MaxNetworks   = 200
	MaxVolumes    = 500
	MaxLabels     = 32
	MaxLabelBytes = 256
	// MaxSnapshotBytes is the one limit both sides enforce on the serialized snapshot: the
	// agent shrinks to it before sending, the server refuses past it.
	MaxSnapshotBytes = 1 << 20
	MaxNameBytes     = 255
	MaxImageRefBytes = 512
	MaxStatusBytes   = 128
)

Product inventory types. Runtime SDK shapes never leave their adapter; these are the bounded summaries the control plane stores (docs/application-schema.md, retention-policy.md). Container environment is deliberately absent: it is where secrets live.

View Source
const (
	MountVolume = "volume"
	MountBind   = "bind"
	MountOther  = "other" // inventory only: tmpfs, npipe and anything else the runtime reports
)
View Source
const (
	RuntimeDocker     = "docker"
	RuntimeKubernetes = "kubernetes"
)

Runtimes an endpoint can have. The endpoint row fixes one at enrollment; nothing changes it.

View Source
const (
	CapabilityKubernetesInventory = "kubernetes.inventory"
	CapabilityPodLogs             = "pod.logs"
)

Kubernetes capabilities. A cluster agent advertises these and nothing else; a Docker agent never advertises them (CapabilitiesFit).

View Source
const (
	MaxNodes          = 500
	MaxNamespaces     = 500
	MaxWorkloads      = 2000
	MaxPods           = 2000
	MaxServices       = 2000
	MaxClaims         = 1000
	MaxPodContainers  = 32
	MaxWorkloadImages = 32
	MaxNodeRoles      = 16
	MaxServicePorts   = 32
	MaxKubeNameBytes  = 253
	MaxKubeImageBytes = 1 << 10
	MaxKubeShortBytes = 64
)

Cluster inventory bounds. Lists are cut at their cap and named in Truncated; nested lists are cut silently by Clamp, except a pod's containers, which also mark "pods".

View Source
const (
	HealthHealthy  = "healthy"
	HealthDegraded = "degraded"
	HealthUnknown  = "unknown"
)

Cluster health, derived on read from the stored inventory.

View Source
const (
	MaxKubernetesClaims = 16 // per request
	MaxKubernetesMounts = 8  // per service
	MaxStorageClasses   = 100
	AccessReadWriteOnce = "ReadWriteOnce"
	// DetailRetained is the detail of a removal's skipped volume step: the claim was kept.
	DetailRetained = "retained"
)

Claims a cluster deployment mounts: a PersistentVolumeClaim per chosen named volume, created once and never updated or deleted by the agent. See docs/agent-protocol.md, Claims.

View Source
const (
	CapabilityKubernetesDeploy     = "kubernetes.deploy"
	CapabilityKubernetesClaims     = "kubernetes.claims"
	CapabilityKubernetesServiceIPs = "kubernetes.service_ips"
	CapabilityKubernetesRemove     = "kubernetes.remove"
)

Cluster deployment capabilities. A cluster agent advertises them when it can apply and remove an application's objects; it never advertises deployment.pull, because the kubelet pulls. kubernetes.claims says it applies KubernetesTarget.Claims and service volumes: an agent without it decodes a frame leniently and would run the pod with no claim.

View Source
const (
	// CapabilityKubernetesWorkloads marks a cluster agent that runs the workload and pod
	// actions, reads a workload's configuration and applies it.
	CapabilityKubernetesWorkloads = "kubernetes.workloads"
	// CapabilityKubernetesWorkloadsRun marks a cluster agent whose workload apply honours
	// Create: agents from before it advertise kubernetes.workloads and refuse a run.
	CapabilityKubernetesWorkloadsRun = "kubernetes.workloads.run"
	CapabilityKubernetesManifestsRun = "kubernetes.manifests.run"
	// CapabilityPodExec marks a cluster agent that opens an exec session in a pod container.
	CapabilityPodExec = "pod.exec"

	TypeWorkloadApply     = "workload.apply"
	MaxWorkloadApplyBytes = 128 << 10
	// WorkloadApplyService is the one service a workload apply's DeploymentResult names.
	WorkloadApplyService = "workload"

	MaxWorkloadReplicas     = 1000
	MaxWorkloadContainers   = 16
	MaxWorkloadEnv          = 128 // per container
	MaxQuantityBytes        = 32
	MaxResourceVersionBytes = 64
	MaxWorkloadEnvFrom      = MaxListEntries
	MaxWorkloadUnsupported  = 16
)

Cluster workload operations: commands on workloads and pods, the configuration read of a workload's pod template, its apply, and pod exec.

View Source
const (
	WorkloadDeployment  = "deployment"
	WorkloadStatefulSet = "statefulset"
	WorkloadDaemonSet   = "daemonset"
	WorkloadPod         = "pod"
)

Kinds a WorkloadRef names, lower-case as they travel.

View Source
const (
	TypeLogOpen   = "log.open"   // server → agent: start reading one container's log
	TypeLogChunk  = "log.chunk"  // agent → server: the next piece of it
	TypeLogClose  = "log.close"  // agent → server: this stream is over, and why
	TypeLogCancel = "log.cancel" // server → agent: the reader went away, stop reading
)

Log frame types. A log stream is a conversation inside the one socket: the server opens it, the agent sends chunks until it ends or is cancelled, and either side can end it.

View Source
const (
	// MaxLogChunkBytes is one chunk on the wire. Small enough that a slow reader costs little
	// to hold and that a chunk fits well inside the control-frame limit.
	MaxLogChunkBytes = 32 << 10
	// MaxLogFrameBytes bounds a log chunk frame. It is larger than the control-frame limit
	// because JSON escaping can multiply a byte by six, and a log carries whatever the
	// application printed; the log text inside it is still bounded by MaxLogChunkBytes.
	MaxLogFrameBytes = 256 << 10
	// MaxLogLines and MaxLogBytes bound one request: whichever comes first ends it, and the
	// answer says it was truncated rather than pretending it was the whole log.
	MaxLogLines = 10000
	MaxLogBytes = 4 << 20
	// MaxLogTail is the most history one request may ask the runtime for.
	MaxLogTail = MaxLogLines
	// MaxLogStreamsPerEndpoint is how many log streams one endpoint serves at once. Both
	// sides read it from here: if the agent's limit were the lower of the two it would be the
	// real ceiling, and the control plane's per-reader split -- which exists so that members
	// holding nothing but container.logs cannot deny an administrator the logs of a host --
	// would hand out places the agent then refuses.
	MaxLogStreamsPerEndpoint = 4
	// LogFollowBuffer is what one following stream may hold for a reader that is not keeping
	// up. Past it, bytes are dropped and the gap is reported: a reader watching a chatty
	// container must not be able to grow the control plane's memory without limit.
	LogFollowBuffer = 1 << 20
)

Log bounds, from docs/retention-policy.md. Log bodies are never stored, so these bound memory and work rather than disk: what an operator asked for must not be able to cost the control plane or the agent more than this, however much the container has written.

View Source
const (
	TypeChallenge        = "challenge"
	TypeAuth             = "auth"
	TypeHello            = "hello"
	TypeHeartbeat        = "heartbeat"
	TypeInventory        = "inventory"
	TypeInventoryRefresh = "inventory.refresh"
	TypeMetrics          = "metrics"
	TypeApproved         = "enrollment.approved"
	TypeRotate           = "identity.rotate"  // agent → server: a new key signed by the current one
	TypeRotated          = "identity.rotated" // server → agent: the operator acknowledged that key
	TypeCommand          = "command"          // server → agent: do one thing to one named resource
	TypeResult           = "result"           // agent → server: what became of it
	TypeError            = "error"
)

Frame types used by the connection lifecycle.

View Source
const (
	OutcomeSucceeded = "succeeded"
	OutcomeFailed    = "failed"
	OutcomeDenied    = "denied"    // the agent refused: wrong tenant, unmet precondition
	OutcomeTimedOut  = "timed_out" // the deadline passed before the runtime answered
	OutcomeUnknown   = "unknown"   // the socket went before a result came back
)

Command outcomes. Every dispatched command ends in exactly one of these, and the set is closed: an outcome the server has not heard is Unknown, never a missing row.

View Source
const (
	ActionStart   = "container.start"
	ActionStop    = "container.stop"
	ActionRestart = "container.restart"
	ActionRemove  = "container.remove"
	// Image actions name a reference rather than a container, and travel in Reference.
	ActionImagePull   = "image.pull"
	ActionImageRemove = "image.remove"
	// Cluster actions name a WorkloadRef ("<namespace>/<kind>/<name>") in Reference.
	ActionWorkloadRestart = "workload.restart"
	ActionWorkloadScale   = "workload.scale" // Expects.Replicas is the new count
	ActionWorkloadDelete  = "workload.delete"
	ActionPodDelete       = "pod.delete"
)

Container actions on a container that already exists. Removal is here because it travels the same path as the others, but it is not one of them: it carries a different permission and a confirmation the server checks against its own state before any frame is built.

View Source
const (
	CloseRevoked      = "identity_revoked"
	CloseDuplicate    = "duplicate_connection"
	CloseIncompatible = "incompatible_version"
	CloseRejected     = "enrollment_rejected"
	CloseShutdown     = "server_shutdown"
	CloseTimeout      = "heartbeat_timeout"
	CloseProtocol     = "protocol_error"
	CloseKeyRetired   = "key_retired"        // switch to the acknowledged key
	CloseKeyPending   = "key_pending_review" // keep using the approved key
)

Close reasons the server sends in the WebSocket close frame.

View Source
const (
	ContextEnroll = "kyyard-agent-enroll-v1"
	ContextAuth   = "kyyard-agent-auth-v1"
	ContextRotate = "kyyard-agent-rotate-v1"
	// ContextServer is signed by the control plane's instance key, never by an agent key.
	ContextServer = "kyyard-server-challenge-v2"
	TokenSize     = 32
)
View Source
const (
	// CapabilityKubernetesInspect marks a cluster agent that answers a WorkloadRef inspection;
	// health validation of a cluster needs it.
	CapabilityKubernetesInspect = "kubernetes.inspect"
	// MaxWorkloadConditions bounds a status's conditions; MaxWorkloadPods its pods.
	MaxWorkloadConditions = 8
	MaxWorkloadPods       = MaxPodContainers * 4
)

Kubernetes inspection: the inspection frames carry a Deployment target and its status. See agent-protocol.md, Container inspection.

View Source
const AgentNonceParam = "agent_nonce"

AgentNonceParam is the dial query parameter carrying the agent's fresh nonce, unpadded base64url, so the server's proof covers a value the server could not have seen before.

View Source
const CapabilityInventoryRefresh = "inventory.refresh"

CapabilityInventoryRefresh supports an on-demand report on either runtime.

View Source
const KindDeployment = "Deployment"

KindDeployment is the one object kind a Kubernetes identity names.

View Source
const MaxImageReferenceBytes = 512

MaxImageReferenceBytes bounds a reference. Docker's own limit is far larger, but a reference becomes part of a URL addressed to the host's root-equivalent socket, and nothing legitimate comes close to this.

View Source
const MaxInspectionEntries = 64
View Source
const MaxKubeObjectName = 63

MaxKubeObjectName bounds a Deployment's and a Service's name: a DNS-1123 label.

View Source
const MaxMetricsBytes = 64 << 10

MaxMetricsBytes matches the server's control-payload limit. Metrics are shrunk on the agent before they enter the wire, so a large but valid container set cannot reconnect-loop.

View Source
const MaxMounts = 32

MaxMounts bounds a container's reported mounts and a deployed service's mounts alike.

View Source
const MaxNetworkAttachments = 32

MaxNetworkAttachments bounds a container's reported networks and attachments alike.

View Source
const MaxResultDetailBytes = 4 << 10

MaxResultDetailBytes bounds the text an agent may attach to a result.

View Source
const MaxSamples = 1000

MaxSamples bounds one metrics frame; the adapter reports running containers only.

View Source
const Version = 1

Version is the protocol major version both sides negotiate in hello.

Variables

View Source
var (
	// ErrExecForbidden: the agent's own grant lacks the exec (create pods/exec).
	ErrExecForbidden = errors.New("forbidden")
	// ErrExecPodSecurity: the pod's namespace does not enforce Pod Security baseline or
	// restricted, or the pod itself does not meet baseline.
	ErrExecPodSecurity = errors.New("pod_security")
)

A runtime refuses an exec start with one of these fixed errors when the operator can act on the cause. The agent sends its text as the exec.close reason, and the server passes exactly these through to the browser; every other start failure keeps a fixed generic reason.

View Source
var ConfigurationOnlyCodes = []string{"volumes_from", "volume_driver", "mount_options", "ulimits", "sysctls", "device_requests", "pid_mode", "ipc_mode", "userns_mode", "cgroup_parent", "group_add", "links", "runtime", "anonymous_volume"}

ConfigurationOnlyCodes are the UnsupportedCodes naming settings an ExplicitService cannot express: a configuration read lists them, and an explicit recreate of a container that has any is refused.

View Source
var ErrClockSkew = errors.New("clock skew exceeds 5 minutes")

ErrClockSkew is a frame whose issue time is more than MaxClockSkew from the reader's clock.

View Source
var ErrSnapshotShape = errors.New("the snapshot does not match the endpoint's runtime")

ErrSnapshotShape is a snapshot whose lists do not match the endpoint's runtime.

View Source
var HealthStates = map[string]bool{"none": true, "starting": true, "healthy": true, "unhealthy": true}

HealthStates is the closed vocabulary of Container.Health and ContainerInspection.Health.

View Source
var UnsupportedCodes = []string{"mount_type", "anonymous_volume", "volumes_from", "volume_driver", "mount_options", "tmpfs", "auto_remove", "read_only_rootfs", "privileged", "capabilities", "security_opt", "devices", "pid_mode", "ipc_mode", "user", "runtime", "resource_limits", "ulimits", "sysctls", "device_requests", "init", "userns_mode", "cgroup_parent", "group_add", "extra_hosts", "dns", "links", "network", "image_config", "k8s_volume", "k8s_host_ip", "k8s_restart", "k8s_name", "k8s_namespace", "k8s_volume_shared", "k8s_name_taken", "k8s_service_renamed"}

UnsupportedCodes is the closed vocabulary of ContainerInspection.Unsupported, in the order the Docker adapter reports them, then the k8s_ codes a plan for a Kubernetes endpoint refuses. Each is configuration the target runtime cannot take from the definition.

View Source
var WorkloadUnsupportedCodes = []string{"env_field_ref", "resources_extended", "containers_truncated", "env_truncated", "argv_truncated", "env_from_truncated"}

WorkloadUnsupportedCodes names what a workload read carries that an apply would drop.

Functions

func AdmitLongWait

func AdmitLongWait(ctx context.Context) bool

AdmitLongWait asks for room for one; false means refuse the action rather than wait. Without an admission in ctx the wait is admitted.

func AgentNonce

func AgentNonce(q url.Values) ([]byte, error)

AgentNonce reads the agent's nonce from the dial query: nil when absent, an error unless it is exactly one value decoding to 32 bytes.

func AuthPreimage

func AuthPreimage(endpointID string, nonce []byte, serverHost string, version int) []byte

AuthPreimage binds the signature to this endpoint, this nonce, the host the agent dialed and the version it speaks, so a capture cannot be replayed elsewhere or later.

func CapabilitiesFit

func CapabilitiesFit(runtime string, capabilities []string) bool

CapabilitiesFit reports whether a hello's capabilities belong to the endpoint's runtime: apart from runtime-neutral inventory refresh, a cluster names cluster capabilities and a Docker agent names none of them.

func ChallengePreimage

func ChallengePreimage(nonce, agentNonce []byte, serverHost, instanceFingerprint string) []byte

ChallengePreimage binds the instance key's signature to both nonces, the host the agent dialed and the fingerprint it pins, so a signature cannot be replayed for another socket, a later handshake or another name.

func CheckRuntimeShape

func CheckRuntimeShape(runtime string, s *Snapshot) error

CheckRuntimeShape holds a Kubernetes endpoint to a cluster inventory and no Docker lists, and a Docker endpoint to no cluster inventory.

func Clamp

func Clamp(s *Snapshot)

Clamp rewrites a snapshot so it conforms to the declared schema by construction: list caps, string bounds, label caps and text safety, whatever the sender did. Truncated lists are named.

func CleanText

func CleanText(s string, max int) string

CleanText makes agent-supplied text safe to show next to other text: control characters, line and paragraph separators and bidi controls are removed, and the result is cut on a rune boundary at max bytes. The server applies it to every string it stores; the adapter applies it before sending so honest agents never trip the limits.

func ClusterHealth

func ClusterHealth(active bool, s *Snapshot) string

ClusterHealth is degraded when a reported node is not Ready, healthy when every node is reported and Ready, and unknown when the endpoint is not active, has no cluster inventory, reports no node, or reports only part of its nodes.

func ExecRefusal

func ExecRefusal(err error) string

ExecRefusal is err's fixed close reason, or "" when err is not one of the fixed refusals.

func Fingerprint

func Fingerprint(publicKey []byte) string

Fingerprint identifies a public key: hex SHA-256 of its raw bytes.

func IsExecRefusal

func IsExecRefusal(reason string) bool

IsExecRefusal reports whether reason is a fixed refusal's close reason.

func IsImageAction

func IsImageAction(action string) bool

IsImageAction reports whether an action names an image rather than a container.

func KubernetesNames

func KubernetesNames(project string, services []string) map[string]string

KubernetesNames maps each service to the name of its Deployment and Service: <project>-<service> lower-cased, '_' and '.' read as '-', prefixed "ky-" when it would not start with a letter (a Service name must). A name longer than 63 characters, or one two services share, is cut and suffixed with six hex characters of a digest of project and service, so every name is distinct.

func NamespaceNetwork

func NamespaceNetwork(name string) bool

NamespaceNetwork reports a name that is a network namespace mode rather than a network: the host's, or another container's. Only network_mode may name one; an attachment may not.

func Preimage

func Preimage(context string, fields ...[]byte) []byte

Preimage is the context string and every field, each as a 4-byte big-endian length followed by the bytes, so a signature under one context can never verify under another or split differently. The prefix is total for any field a message can carry.

func RawFingerprint

func RawFingerprint(publicKey []byte) []byte

RawFingerprint is the 32-byte digest the rotation preimage carries; Fingerprint is its hex.

func RunDeployment

func RunDeployment(raw json.RawMessage, target WorkloadRef) (*appsv1.Deployment, error)

RunDeployment decodes an exact new Deployment, retaining native selectors, ports, probes, volume references and security settings. Namespace Pod Security remains the admission gate. Identity/service-account fields are constrained because this is a namespace-scoped run.

func Shrink

func Shrink(s *Snapshot) []byte

Shrink drops labels, then mounts (marking each container's list truncated), then the tails of the largest lists, until the serialized snapshot fits MaxSnapshotBytes, naming what it dropped. It returns the final encoding.

func SplitImageReference

func SplitImageReference(s string) (name, tag string)

SplitImageReference separates a reference into the image name and the tag or digest that pins it to one image. An empty tag means the reference named neither, which is not a thing this product sends to a runtime: the Engine API reads an empty tag as "every tag in the repository", so "pull nginx" would fetch the whole repository onto the host.

func StorageSizeBytes

func StorageSizeBytes(s string) (int64, bool)

StorageSizeBytes reads a claim size: a whole number of Mi, Gi or Ti from 1Mi to 16Ti, the one quantity form KyYard writes. ok is false for anything else.

func UnmarshalHelloBounded

func UnmarshalHelloBounded(data []byte, h *Hello) error

UnmarshalHelloBounded limits capability count and total decoded text before the caller hands it to the store.

func UnmarshalSnapshotBounded

func UnmarshalSnapshotBounded(data []byte, s *Snapshot) error

UnmarshalSnapshotBounded decodes list fields one element at a time. A byte cap alone is not enough: a small JSON object can expand into a much larger Go value.

func ValidClusterIP

func ValidClusterIP(s string) bool

ValidClusterIP checks a canonical unicast address. The Kubernetes API server owns service-range and allocation checks; neither inventory nor a local pool is authoritative.

func ValidConfigurationEnvName

func ValidConfigurationEnvName(name string) bool

ValidConfigurationEnvName is the name rule Validate applies to a container's environment.

func ValidContainerHexID

func ValidContainerHexID(s string) bool

ValidContainerHexID reports whether s is a full 64-hex container ID, not a name.

func ValidContainerID

func ValidContainerID(s string) bool

ValidContainerID reports whether s can name a container.

func ValidDNSLabel

func ValidDNSLabel(s string) bool

ValidDNSLabel is RFC 1123 label syntax as Kubernetes applies it: namespaces, containers.

func ValidDNSSubdomain

func ValidDNSSubdomain(s string) bool

ValidDNSSubdomain is RFC 1123 subdomain syntax as Kubernetes applies it: pod names.

func ValidDeploymentID

func ValidDeploymentID(id string) bool

ValidDeploymentID is the grammar Validate requires of Deployment: a lowercase UUID. A frame failing this cannot be attributed to any deployment and so cannot be answered at all.

func ValidExecID

func ValidExecID(id string) bool

ValidExecID constrains daemon-returned identifiers before they enter another API path.

func ValidImageReference

func ValidImageReference(s string) bool

ValidImageReference reports whether s can name an image. Both the control plane and the agent check it: the agent is the last thing between a request body and the socket, and the repository's rule is that neither check may be the only one.

func ValidLabelValue

func ValidLabelValue(s string) bool

ValidLabelValue is Kubernetes label value syntax: at most 63 characters, alphanumeric at both ends, '-', '_' and '.' between.

func ValidRequestID

func ValidRequestID(id string) bool

ValidRequestID is the grammar of a frame's request_id, the audit correlation ID: the API's 32 hex characters or the store's UUID fallback, safe to log.

func ValidServiceName

func ValidServiceName(s string) bool

ValidServiceName is the grammar of a service name on the wire: a cluster agent reads it back from its objects' labels.

func ValidStorageClass

func ValidStorageClass(s string) bool

ValidStorageClass is "" (the cluster default) or a DNS-1123 subdomain.

func VerifyAuth

func VerifyAuth(publicKey []byte, endpointID string, nonce []byte, serverHost string, version int, signature []byte) bool

func VerifyEnrollment

func VerifyEnrollment(publicKey, token, proof []byte) bool

VerifyEnrollment checks the agent's proof of possession over the raw token.

func VerifyRotation

func VerifyRotation(currentKey, currentRawFingerprint, newKey, signature []byte) bool

VerifyRotation checks that the current key signed the new one under the rotation context.

func WithLongWait

func WithLongWait(ctx context.Context, admit func() bool) context.Context

WithLongWait carries the agent's admission for a wait that would hold a command slot far past the usual budget, which only the runtime can recognise once it has read the target.

Types

type Auth

type Auth struct {
	EndpointID  string `json:"endpoint_id"`
	Fingerprint string `json:"fingerprint"` // which of the endpoint's keys signed
	Version     int    `json:"version"`
	Signature   []byte `json:"signature"`
}

Auth is the agent's reply, signed under ContextAuth by its endpoint key.

type Challenge

type Challenge struct {
	Nonce               []byte `json:"nonce"`
	InstanceFingerprint string `json:"instance_fingerprint"`
	Versions            []int  `json:"versions"`
	InstanceKey         []byte `json:"instance_key,omitempty"`
	Signature           []byte `json:"signature,omitempty"`
}

Challenge is the server's first frame: a fresh nonce and its pinned identity, proven by the instance key's signature (SignChallenge). Servers before the proof, and any server answering a dial without an agent nonce, omit both fields.

func SignChallenge

func SignChallenge(instance ed25519.PrivateKey, nonce, agentNonce []byte, serverHost string) Challenge

SignChallenge is the server's challenge for nonce, signed by its instance key over the agent's nonce.

func (Challenge) Proven

func (c Challenge) Proven(agentNonce []byte, serverHost, pinned string) bool

Proven reports whether the challenge was signed, for serverHost and the agent's outstanding nonce, by the instance key whose fingerprint the agent pinned.

type Claim

type Claim struct {
	Namespace    string `json:"namespace"`
	Name         string `json:"name"`
	Phase        string `json:"phase"`
	StorageClass string `json:"storage_class"`
	Capacity     string `json:"capacity"`
}

Claim is a PersistentVolumeClaim.

type Command

type Command struct {
	ID        string    `json:"id"`
	RequestID string    `json:"request_id"`
	Org       string    `json:"org"`
	Env       string    `json:"env"`
	Endpoint  string    `json:"endpoint"`
	Deadline  time.Time `json:"deadline"`
	Action    string    `json:"action"`
	Container string    `json:"container,omitempty"`
	// Reference is the image an image action names, in Docker's own reference grammar. A
	// command names a container or a reference, never both.
	Reference  string `json:"reference,omitempty"`
	Capability string `json:"capability,omitempty"`
	// Expects is what the actor saw when they asked. Docker has no universal resource
	// version, so this is operation-specific identity the agent re-checks immediately before
	// acting: the same container, in the state the decision was made about.
	Expects Expectation `json:"expects"`
}

Command is one instruction for one endpoint. ID is a ULID minted by the server and is the dedupe key: an agent that has already run this ID returns its stored result rather than acting twice. RequestID is the audit correlation ID, so an agent's logs join the audit trail. The actor is never sent; who asked is recorded server-side only.

type ConfigurationCancel

type ConfigurationCancel = InspectionCancel

ConfigurationOpen and ConfigurationCancel carry the inspection grant shape: request, endpoint, actor, connection nonce, expiry and immutable target.

type ConfigurationOpen

type ConfigurationOpen = InspectionOpen

ConfigurationOpen and ConfigurationCancel carry the inspection grant shape: request, endpoint, actor, connection nonce, expiry and immutable target.

type ConfigurationResult

type ConfigurationResult struct {
	Request  string                  `json:"request"`
	Status   string                  `json:"status"`
	Result   *ContainerConfiguration `json:"result,omitempty"`
	Workload *WorkloadConfiguration  `json:"workload,omitempty"`
}

ConfigurationResult answers a ConfigurationOpen. Status is ok, unavailable or busy; only ok carries an answer, a Result for a container or a Workload for a cluster object, and never runtime error text.

func (ConfigurationResult) Validate

func (r ConfigurationResult) Validate() error

Validate checks the frame's shape; a present Result or Workload is validated against the grant's target by the caller with its own Validate.

type Container

type Container struct {
	ID        string    `json:"id"`
	Name      string    `json:"name"`
	Image     string    `json:"image"`
	ImageID   string    `json:"image_id"`
	State     string    `json:"state"`  // created, running, paused, restarting, exited, dead
	Status    string    `json:"status"` // human text from the runtime, bounded
	CreatedAt time.Time `json:"created_at"`
	// StartedAt is zero when the container is not running or the agent could not read it in
	// budget; the UI derives uptime from it and never parses Status.
	StartedAt     time.Time         `json:"started_at,omitzero"`
	Health        string            `json:"health,omitempty"` // HealthStates, "" when not reported
	RestartPolicy string            `json:"restart_policy,omitempty"`
	Ports         []Port            `json:"ports"`
	Labels        map[string]string `json:"labels"`
	Networks      []string          `json:"networks"`
	// NetworkAttachments repeats Networks with addresses; nil from an agent older than it.
	NetworkAttachments []NetworkAttachment `json:"network_attachments,omitempty"`
	// Managed is the Compose project label when present; ownership arrives with M6.
	ComposeProject string `json:"compose_project,omitempty"`
	// Mounts is nil when the agent did not report them (older than mounts), empty when there
	// are none; MountsTruncated says entries past MaxMounts were dropped.
	Mounts          []Mount `json:"mounts"`
	MountsTruncated bool    `json:"mounts_truncated,omitempty"`
}

func (*Container) UnmarshalJSON

func (c *Container) UnmarshalJSON(data []byte) error

UnmarshalJSON caps mounts and network attachments while decoding, like the snapshot's own lists.

type ContainerConfiguration

type ContainerConfiguration struct {
	Target     InspectionTarget `json:"target"`
	ObservedAt time.Time        `json:"observed_at"`
	Name       string           `json:"name"`
	Image      ImagePull        `json:"image"`
	ImageID    string           `json:"image_id"`
	Command    []string         `json:"command"`
	Entrypoint []string         `json:"entrypoint"`
	User       string           `json:"user"`
	WorkingDir string           `json:"working_dir"`
	Hostname   string           `json:"hostname"`
	Env        []EnvEntry       `json:"env"`
	// Labels are cleaned (CleanText) by the agent before sending; Validate refuses any that are not.
	Labels         map[string]string       `json:"labels"`
	Restart        string                  `json:"restart"`
	RestartRetries int                     `json:"restart_retries"`
	Ports          []Port                  `json:"ports"` // Host 0 is exposed but unpublished
	Mounts         []Mount                 `json:"mounts"`
	NetworkMode    string                  `json:"network_mode"`
	Networks       []NetworkAttachmentSpec `json:"networks"`
	Resources      Resources               `json:"resources"`
	Healthcheck    *Healthcheck            `json:"healthcheck,omitempty"`
	Privileged     bool                    `json:"privileged"`
	ReadOnlyRootfs bool                    `json:"read_only_rootfs"`
	Init           bool                    `json:"init"`
	TTY            bool                    `json:"tty"`
	StdinOpen      bool                    `json:"stdin_open"`
	CapAdd         []string                `json:"cap_add"`
	CapDrop        []string                `json:"cap_drop"`
	SecurityOpt    []string                `json:"security_opt"`
	ExtraHosts     []string                `json:"extra_hosts"`
	DNS            []string                `json:"dns"`
	Devices        []Device                `json:"devices"`
	Log            LogConfig               `json:"log"`
	StopSignal     string                  `json:"stop_signal"`
	StopTimeout    *int                    `json:"stop_timeout,omitempty"`
	Unsupported    []string                `json:"unsupported"`
}

ContainerConfiguration is the editable configuration of one container, read for the edit form. Unlike ContainerInspection it carries values (env, labels, argv). Unsupported names configuration the agent cannot express in a service spec.

func (*ContainerConfiguration) Validate

func (c *ContainerConfiguration) Validate(target InspectionTarget, now time.Time) error

Validate bounds an untrusted agent's configuration before it reaches an HTTP response.

type ContainerInspection

type ContainerInspection struct {
	Target     InspectionTarget `json:"target"`
	ObservedAt time.Time        `json:"observed_at"`
	State      string           `json:"state"`
	// Health is Docker's State.Health.Status, "none" without a healthcheck; RestartCount is the
	// runtime's restart count. Both are set exactly when the agent advertises
	// CapabilityContainerInspectHealth. The healthcheck's command and log never enter this type.
	Health                string        `json:"health"`
	RestartCount          int           `json:"restart_count"`
	ImagePlatform         ImagePlatform `json:"image_platform"`
	RestartPolicy         string        `json:"restart_policy"`
	RestartRetries        int           `json:"restart_retries"`
	Ports                 []Port        `json:"ports"`
	Mounts                MountCounts   `json:"mounts"`
	NetworkMode           string        `json:"network_mode"`
	NetworkCount          int           `json:"network_count"`
	Privileged            bool          `json:"privileged"`
	ReadOnlyRootFS        bool          `json:"read_only_rootfs"`
	AutoRemove            bool          `json:"auto_remove"`
	Unsupported           []string      `json:"unsupported"`
	ConfigurationVerified bool          `json:"configuration_verified"`
	// Workload is a cluster agent's answer, set exactly for a Kubernetes target; every Docker
	// field is then empty.
	Workload *WorkloadStatus `json:"workload,omitempty"`
}

ContainerInspection is an allowlisted observation, not a recreation spec. Counts omit mount paths/network names. Environment, labels, argv, healthcheck commands, raw configuration and hashes of those values never enter this type. Unsupported names, as codes from UnsupportedCodes, configuration a recreate from the definition would drop; ConfigurationVerified is true exactly when it is empty.

func (ContainerInspection) Validate

func (r ContainerInspection) Validate(target InspectionTarget, now time.Time, health bool) error

Validate bounds an untrusted agent result before it reaches an HTTP response. The target's shape decides the runtime: a Workload target takes a WorkloadStatus answer and nothing else. For a container, health says the answering agent advertised CapabilityContainerInspectHealth: health and restart_count are then required and bounded, and otherwise absent.

type DeploymentIdentity

type DeploymentIdentity struct {
	Service     string `json:"service"`
	ContainerID string `json:"container_id"`
	ImageID     string `json:"image_id"`
	CreatedUnix int64  `json:"created_unix"`
	ImageDigest string `json:"image_digest,omitempty"`
	Kind        string `json:"kind,omitempty"`
	Namespace   string `json:"namespace,omitempty"`
	Name        string `json:"name,omitempty"`
	UID         string `json:"uid,omitempty"`
	Generation  int64  `json:"generation,omitempty"`
}

DeploymentIdentity is what a service now runs as: a Docker container, or on a cluster (Kind set) the Deployment's namespace, name, UID and generation. ImageDigest is the pulled repository digest, always set for a Deployment.

type DeploymentRequest

type DeploymentRequest struct {
	Deployment string `json:"deployment"`
	// RequestID is the plan's audit correlation ID; the agent logs and echoes it.
	RequestID string `json:"request_id"`
	Endpoint  string `json:"endpoint"`
	Project   string `json:"project"`
	Revision  int    `json:"revision"`
	// IssuedAt is the server's clock when it built the frame; Deadline is measured from it too.
	IssuedAt time.Time           `json:"issued_at"`
	Deadline time.Time           `json:"deadline"`
	Services []DeploymentService `json:"services"`
	// Registries holds a credential per registry host some service pulls from; never logged.
	Registries map[string]RegistryAuth `json:"registries,omitempty"`
	// Volumes are the named volumes the agent ensures before any replacement, each one some
	// service mounts.
	Volumes []string `json:"volumes,omitempty"`
	// Kubernetes is set exactly for a cluster endpoint: the namespace and labels of its objects.
	Kubernetes *KubernetesTarget `json:"kubernetes,omitempty"`
	// Explicit is set when the operator saw and kept every setting: each service then carries
	// its Explicit configuration and the adapter inherits nothing from the replaced container.
	Explicit bool `json:"explicit,omitempty"`
}

func (DeploymentRequest) Validate

func (r DeploymentRequest) Validate(now time.Time) error

Validate refuses anything the adapter would have to guess about. Every bound here is a wire bound as well: PR B rejects a frame that fails it before touching the runtime.

func (DeploymentRequest) ValidateFor

func (r DeploymentRequest) ValidateFor(runtime string, now time.Time) error

ValidateFor is Validate holding the frame to the agent's runtime: a Kubernetes target exactly when the runtime is kubernetes.

type DeploymentResult

type DeploymentResult struct {
	Deployment string `json:"deployment"`
	// RequestID echoes the frame's request_id; empty only from a binary built before it.
	RequestID string `json:"request_id"`
	Outcome   string `json:"outcome"`
	// Code is a result code, set exactly when Outcome is not succeeded.
	Code     string               `json:"code"`
	Steps    []DeploymentStep     `json:"steps"`
	Services []DeploymentIdentity `json:"services"`
}

func (DeploymentResult) Validate

func (r DeploymentResult) Validate() error

type DeploymentService

type DeploymentService struct {
	Name          string            `json:"name"`
	ContainerName string            `json:"container_name"`
	ImageID       string            `json:"image_id"`
	Replaces      InspectionTarget  `json:"replaces"`
	Restart       string            `json:"restart"`
	Ports         []Port            `json:"ports"`
	Env           map[string]string `json:"env"`
	// Pull, when set, has the agent pull the image first; ImageID is then empty.
	Pull *ImagePull `json:"pull,omitempty"`
	// Mounts are MountVolume or MountBind only; a bind must already be on the replaced container.
	// Always sent: a nil list is invalid.
	Mounts []Mount `json:"mounts"`
	// SecretKeys are the Env keys backed by a secret reference, sorted; Kubernetes only. The
	// agent puts them in the service's Secret and the rest in its ConfigMap.
	SecretKeys []string `json:"secret_keys,omitempty"`
	// Volumes mount the request's claims; Kubernetes only.
	Volumes []KubernetesMount `json:"volumes,omitempty"`
	// ClusterIP requests a static internal Service address; Kubernetes only.
	ClusterIP string `json:"cluster_ip,omitempty"`
	// Explicit is the full configuration of an explicit request; nil otherwise.
	Explicit *ExplicitService `json:"explicit,omitempty"`
}

type DeploymentStep

type DeploymentStep struct {
	Service string `json:"service"`
	Step    string `json:"step"`
	Outcome string `json:"outcome"`
	// Code is a step code, set exactly when Outcome is denied, failed, timed_out or unknown.
	Code string `json:"code"`
	// Detail is Code's parameter: empty, unsupported codes, a container ID or a status.
	Detail string `json:"detail"`
}

type Device

type Device struct {
	Host        string `json:"host"`
	Container   string `json:"container"`
	Permissions string `json:"permissions"`
}

type Engine

type Engine struct {
	Runtime     string `json:"runtime"`
	Version     string `json:"version"`
	APIVersion  string `json:"api_version"`
	OS          string `json:"os"`
	Arch        string `json:"arch"`
	Kernel      string `json:"kernel"`
	CPUs        int    `json:"cpus"`
	MemoryBytes int64  `json:"memory_bytes"`
	Hostname    string `json:"hostname"`
}

type EnvEntry

type EnvEntry struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}

type Envelope

type Envelope struct {
	V         int             `json:"v"`
	Type      string          `json:"type"`
	ID        string          `json:"id,omitempty"`
	RequestID string          `json:"request_id,omitempty"`
	Org       string          `json:"org,omitempty"`
	Env       string          `json:"env,omitempty"`
	Endpoint  string          `json:"endpoint,omitempty"`
	Deadline  *time.Time      `json:"deadline,omitempty"`
	Payload   json.RawMessage `json:"payload,omitempty"`
}

Envelope is one frame (docs/agent-protocol.md section 4). Payload is decoded by Type.

type ExecClose

type ExecClose struct {
	Stream   string `json:"stream"`
	Reason   string `json:"reason"`
	ExitCode *int   `json:"exit_code,omitempty"`
}

type ExecData

type ExecData struct {
	Stream string `json:"stream"`
	Data   []byte `json:"data"`
}

Data uses JSON base64 encoding to preserve arbitrary PTY bytes, including UTF-8 split across reads. The decoded chunk limit applies in both directions.

type ExecOpen

type ExecOpen struct {
	Stream     string       `json:"stream"`
	Endpoint   string       `json:"endpoint"`
	Actor      string       `json:"actor"`
	Connection []byte       `json:"connection"`
	Expires    time.Time    `json:"expires"`
	Spec       ExecSpec     `json:"spec"`
	Size       TerminalSize `json:"size"`
}

func (ExecOpen) Validate

func (r ExecOpen) Validate(now time.Time) error

type ExecResize

type ExecResize struct {
	Stream string       `json:"stream"`
	Size   TerminalSize `json:"size"`
}

type ExecSpec

type ExecSpec struct {
	Container string     `json:"container"`
	ImageID   string     `json:"image_id"`
	User      string     `json:"user"`
	Argv      []string   `json:"argv"`
	Pod       *PodTarget `json:"pod,omitempty"`
}

ExecSpec carries the exact target approved by the caller: a Docker container and image with an explicit user, or a pod container pinned by the pod's UID. Argv is passed directly to the runtime: no adapter parses a command line or inserts a shell.

func (ExecSpec) Validate

func (s ExecSpec) Validate() error

func (ExecSpec) ValidateFor

func (s ExecSpec) ValidateFor(runtime string) error

ValidateFor is Validate holding the target to the runtime: a pod exactly on a cluster.

type ExecStatus

type ExecStatus struct {
	Running  bool `json:"running"`
	ExitCode *int `json:"exit_code,omitempty"`
}

ExitCode is absent until Docker confirms that the process is no longer running.

type ExecStream

type ExecStream struct {
	Stream string `json:"stream"`
}

type Expectation

type Expectation struct {
	ImageDigest string `json:"image_digest,omitempty"`
	State       string `json:"state,omitempty"`
	// Replicas is a scale's target count, 0..MaxWorkloadReplicas.
	Replicas *int32 `json:"replicas,omitempty"`
}

Expectation is the precondition a command is contingent on. An empty field is not checked, so a caller says only what its decision actually depended on.

type ExplicitService

type ExplicitService struct {
	Command           []string                `json:"command"`
	Entrypoint        []string                `json:"entrypoint"`
	User              string                  `json:"user"`
	WorkingDir        string                  `json:"working_dir"`
	Hostname          string                  `json:"hostname"`
	Labels            map[string]string       `json:"labels"` // sent as-is; no Compose labels added
	NetworkMode       string                  `json:"network_mode"`
	Networks          []NetworkAttachmentSpec `json:"networks"`
	Resources         Resources               `json:"resources"`
	Healthcheck       *Healthcheck            `json:"healthcheck,omitempty"`
	Privileged        bool                    `json:"privileged"`
	ReadOnlyRootfs    bool                    `json:"read_only_rootfs"`
	Init              bool                    `json:"init"`
	TTY               bool                    `json:"tty"`
	StdinOpen         bool                    `json:"stdin_open"`
	CapAdd            []string                `json:"cap_add"`
	CapDrop           []string                `json:"cap_drop"`
	SecurityOpt       []string                `json:"security_opt"`
	ExtraHosts        []string                `json:"extra_hosts"`
	DNS               []string                `json:"dns"`
	Devices           []Device                `json:"devices"`
	Log               LogConfig               `json:"log"`
	StopSignal        string                  `json:"stop_signal"`
	StopTimeout       *int                    `json:"stop_timeout,omitempty"`
	RestartRetries    int                     `json:"restart_retries"`
	AcknowledgedBinds []string                `json:"acknowledged_binds"` // host paths the operator confirmed
}

ExplicitService is every setting of one container that a direct edit or run sets. Replaces may be zero (a run).

type FieldError

type FieldError struct{ Field, Message string }

FieldError is a refused configuration; Field names what was refused.

func (*FieldError) Error

func (e *FieldError) Error() string

type Healthcheck

type Healthcheck struct {
	Test               []string `json:"test"`
	IntervalSeconds    float64  `json:"interval_seconds"`
	TimeoutSeconds     float64  `json:"timeout_seconds"`
	StartPeriodSeconds float64  `json:"start_period_seconds"`
	Retries            int      `json:"retries"`
}

type Hello

type Hello struct {
	State            string   `json:"state,omitempty"`
	HeartbeatSeconds int      `json:"heartbeat_seconds,omitempty"`
	Capabilities     []string `json:"capabilities,omitempty"`
	AgentVersion     string   `json:"agent_version,omitempty"`
}

Hello is exchanged after authentication. The server's copy states the endpoint state and the heartbeat it expects; the agent's copy states what it can do.

type Image

type Image struct {
	ID        string    `json:"id"`
	Tags      []string  `json:"tags"`
	Digests   []string  `json:"digests"`
	SizeBytes int64     `json:"size_bytes"`
	CreatedAt time.Time `json:"created_at"`
}

type ImagePlatform

type ImagePlatform struct {
	OS           string `json:"os"`
	Architecture string `json:"architecture"`
	Variant      string `json:"variant,omitempty"`
}

type ImagePull

type ImagePull struct {
	Reference string `json:"reference"`
	Digest    string `json:"digest"`
	Tag       string `json:"tag,omitempty"`
}

ImagePull names an image by host, repository and the digest it must resolve to. Tag, when set, is the service's tag reference (same host and repository) the pulled image is tagged with, so the host's tag follows the update; empty for a digest-pinned spec reference.

func (ImagePull) Host

func (p ImagePull) Host() string

Host is the registry host Reference names, or "" when it names none or is invalid. It is read as written, not canonicalised; the server sends the canonical host.

type InspectionCancel

type InspectionCancel struct {
	Request string `json:"request"`
}

type InspectionOpen

type InspectionOpen struct {
	Request    string           `json:"request"`
	Endpoint   string           `json:"endpoint"`
	Actor      string           `json:"actor"`
	Connection []byte           `json:"connection"`
	Expires    time.Time        `json:"expires"`
	Target     InspectionTarget `json:"target"`
}

func (InspectionOpen) ValidateFor

func (r InspectionOpen) ValidateFor(now time.Time, runtime string) error

ValidateFor checks a grant for an agent of the runtime, with the inspection lifetime.

func (InspectionOpen) ValidateWithin

func (r InspectionOpen) ValidateWithin(now time.Time, lifetime time.Duration, runtime string) error

ValidateWithin is ValidateFor for a frame with its own grant lifetime.

type InspectionResult

type InspectionResult struct {
	Request string               `json:"request"`
	Status  string               `json:"status"` // ok, unavailable or busy; never runtime error text.
	Result  *ContainerInspection `json:"result,omitempty"`
}

type InspectionTarget

type InspectionTarget struct {
	ContainerID string      `json:"container_id"`
	ImageID     string      `json:"image_id"`
	CreatedUnix int64       `json:"created_unix"`
	Workload    WorkloadRef `json:"workload,omitzero"`
}

InspectionTarget pins the identity already authorized by the caller. Docker inventory exposes creation time in whole seconds. See application-schema.md, Runtime inspection foundation. This is not a wire grant or deployment approval. A Kubernetes target names a Deployment (Workload) and no container.

func (InspectionTarget) Validate

func (t InspectionTarget) Validate() error

Validate holds a target to the Docker shape.

func (InspectionTarget) ValidateFor

func (t InspectionTarget) ValidateFor(runtime string) error

ValidateFor holds a target to the one shape the runtime reads: a container for Docker, a Deployment for Kubernetes.

type KubernetesClaim

type KubernetesClaim struct {
	Name         string `json:"name"`
	StorageClass string `json:"storage_class"`
	Size         string `json:"size"`
	AccessMode   string `json:"access_mode"`
}

KubernetesClaim is one PersistentVolumeClaim of the instance: its name, the StorageClass ("" is the cluster default), the requested size and the access mode.

type KubernetesInventory

type KubernetesInventory struct {
	Nodes      []Node     `json:"nodes"`
	Namespaces []string   `json:"namespaces"`
	Workloads  []Workload `json:"workloads"`
	Pods       []Pod      `json:"pods"`
	Services   []Service  `json:"services"`
	Claims     []Claim    `json:"claims"`
	// StorageClasses are what a migration's volume choices pick from.
	StorageClasses []StorageClass `json:"storage_classes"`
}

KubernetesInventory is what a cluster agent reports in place of the Docker lists.

type KubernetesMount

type KubernetesMount struct {
	Claim     string `json:"claim"`
	MountPath string `json:"mount_path"`
	ReadOnly  bool   `json:"read_only,omitempty"`
}

KubernetesMount mounts a claim the request names at MountPath.

type KubernetesTarget

type KubernetesTarget struct {
	Namespace     string `json:"namespace"`
	ApplicationID string `json:"application_id"`
	InstanceID    string `json:"instance_id"`
	SpecDigest    string `json:"spec_digest"`
	// Claims are the PersistentVolumeClaims an apply ensures; a removal carries none.
	Claims []KubernetesClaim `json:"claims,omitempty"`
}

KubernetesTarget is where a cluster agent applies or removes an instance's objects, and what it labels and annotates them with. A request carries it exactly when the endpoint's runtime is kubernetes (ValidateFor).

func (KubernetesTarget) Validate

func (k KubernetesTarget) Validate() error

type LogCancel

type LogCancel struct {
	Stream string `json:"stream"`
}

LogCancel stops a stream the reader has abandoned.

type LogChunk

type LogChunk struct {
	Stream  string `json:"stream"`
	Data    string `json:"data"`
	Dropped int64  `json:"dropped,omitempty"`
}

LogChunk is log text as the container wrote it. Dropped is what an older agent lost before it when its queue was full; the control plane still reports it as a gap. The current agent waits instead of dropping and never sets it.

type LogClose

type LogClose struct {
	Stream string `json:"stream"`
	Reason string `json:"reason"`
	// Failed says the stream ended because something went wrong rather than because the log
	// ended or the reader left, so the reader can tell an empty log from a broken one.
	Failed bool `json:"failed,omitempty"`
}

LogClose ends a stream. Reason is short and operator-facing.

type LogConfig

type LogConfig struct {
	Driver  string            `json:"driver"`
	Options map[string]string `json:"options,omitempty"`
}

type LogRequest

type LogRequest struct {
	Stream     string     `json:"stream"`
	Container  string     `json:"container"`
	Pod        *PodTarget `json:"pod,omitempty"`
	Tail       int        `json:"tail"`
	Since      time.Time  `json:"since,omitempty"`
	Timestamps bool       `json:"timestamps"`
	Follow     bool       `json:"follow"`
}

LogRequest opens one stream. Container is the ID the control plane resolved, never a name: a name is a label the runtime reassigns, and a stream must not follow it to another container mid-read. A Kubernetes endpoint is asked for a Pod instead (ValidateFor).

func (LogRequest) ValidateFor

func (r LogRequest) ValidateFor(runtime string) error

ValidateFor holds a log request to the one target the runtime reads: a container ID for Docker, a pod for Kubernetes, never both.

type Metrics

type Metrics struct {
	ObservedAt time.Time `json:"observed_at"`
	Samples    []Sample  `json:"samples"`
}

Metrics is a bounded observation of running containers taken at one instant.

func ShrinkMetrics

func ShrinkMetrics(m Metrics) Metrics

ShrinkMetrics keeps the largest prefix that fits the wire limit. The server applies the same limit, and a prefix search avoids repeatedly marshaling one sample at a time.

type Mount

type Mount struct {
	Kind     string `json:"kind"`
	Source   string `json:"source"`
	Target   string `json:"target"`
	ReadOnly bool   `json:"read_only,omitempty"`
}

Mount is a volume (Source is its name) or a bind (Source is the host path) at Target.

type MountCounts

type MountCounts struct {
	Bind     int `json:"bind"`
	Volume   int `json:"volume"`
	Tmpfs    int `json:"tmpfs"`
	Other    int `json:"other"`
	ReadOnly int `json:"read_only"`
}

type Network

type Network struct {
	ID     string `json:"id"`
	Name   string `json:"name"`
	Driver string `json:"driver"`
	Scope  string `json:"scope"`
}

type NetworkAttachment

type NetworkAttachment struct {
	Name string `json:"name"`
	IP   string `json:"ip,omitempty"`  // IPv4, "" when none
	IP6  string `json:"ip6,omitempty"` // global IPv6, "" when none
}

NetworkAttachment is one network a container is joined to, with its addresses on it.

type NetworkAttachmentSpec

type NetworkAttachmentSpec struct {
	Name    string   `json:"name"`
	Aliases []string `json:"aliases,omitempty"`
	IP      string   `json:"ip,omitempty"`
}

NetworkAttachmentSpec is a network to join; IP is the static address, "" when dynamic.

type Node

type Node struct {
	Name           string   `json:"name"`
	KubeletVersion string   `json:"kubelet_version"`
	OS             string   `json:"os"`
	Arch           string   `json:"arch"`
	Ready          bool     `json:"ready"`
	Roles          []string `json:"roles"`
	Unschedulable  bool     `json:"unschedulable"`
}

type Pod

type Pod struct {
	Namespace  string         `json:"namespace"`
	Name       string         `json:"name"`
	UID        string         `json:"uid,omitempty"`
	Phase      string         `json:"phase"`
	Node       string         `json:"node"`
	OwnerKind  string         `json:"owner_kind"`
	OwnerName  string         `json:"owner_name"`
	StartedAt  time.Time      `json:"started_at"`
	Containers []PodContainer `json:"containers"`
	// contains filtered or unexported fields
}

Pod carries its Kubernetes phase and its controller: a Deployment's pod names the Deployment, not the ReplicaSet between them.

func (*Pod) UnmarshalJSON

func (p *Pod) UnmarshalJSON(data []byte) error

UnmarshalJSON caps a pod's containers while decoding: of the nested lists it is the one a small document can expand into a large value.

type PodContainer

type PodContainer struct {
	Name         string `json:"name"`
	Image        string `json:"image"`
	ImageID      string `json:"image_id"`
	State        string `json:"state"`
	Reason       string `json:"reason"`
	Ready        bool   `json:"ready"`
	RestartCount int32  `json:"restart_count"`
}

PodContainer State is running, waiting or terminated; Reason is the runtime's word for why.

type PodStatus

type PodStatus struct {
	Name       string         `json:"name"`
	UID        string         `json:"uid"`
	Phase      string         `json:"phase"`
	Containers []PodContainer `json:"containers"`
}

PodStatus is one pod of the Deployment. Its containers carry no image: the judge reads state, reason, readiness and restarts only, and the answer must fit MaxInspectionFrameBytes.

type PodTarget

type PodTarget struct {
	Namespace string `json:"namespace"`
	Name      string `json:"name"`
	Container string `json:"container,omitempty"`
	UID       string `json:"uid,omitempty"`
}

PodTarget names one pod and, optionally, one of its containers and the pod's UID. An empty Container asks the agent to take the pod's only container; it refuses when there are several. An exec names both (ExecSpec.Validate).

func (PodTarget) Validate

func (p PodTarget) Validate() error

type Port

type Port struct {
	HostIP    string `json:"host_ip,omitempty"`
	Host      int    `json:"host,omitempty"`
	Container int    `json:"container"`
	Protocol  string `json:"protocol"`
}

type RegistryAuth

type RegistryAuth struct {
	Username string `json:"username"`
	Secret   string `json:"secret"`
}

type RemovalRequest

type RemovalRequest struct {
	Deployment string          `json:"deployment"`
	RequestID  string          `json:"request_id"`
	Endpoint   string          `json:"endpoint"`
	Project    string          `json:"project"`
	IssuedAt   time.Time       `json:"issued_at"`
	Deadline   time.Time       `json:"deadline"`
	Containers []RemovalTarget `json:"containers"`
	// Kubernetes is set exactly for a cluster endpoint; Containers is then empty and Services
	// names every service whose objects the agent deletes.
	Kubernetes *KubernetesTarget `json:"kubernetes,omitempty"`
	Services   []string          `json:"services,omitempty"`
}

RemovalRequest stops and deletes every adopted container of an application being removed, each identified by the same pinned target an inspection or replacement would use rather than a name a daemon restart could reassign.

func (RemovalRequest) Validate

func (r RemovalRequest) Validate(now time.Time) error

func (RemovalRequest) ValidateFor

func (r RemovalRequest) ValidateFor(runtime string, now time.Time) error

ValidateFor is RemovalRequest.Validate holding the frame to the agent's runtime.

type RemovalTarget

type RemovalTarget struct {
	Service string           `json:"service"`
	Target  InspectionTarget `json:"target"`
}

type Resources

type Resources struct {
	NanoCPUs        int64 `json:"nano_cpus"`
	MemoryBytes     int64 `json:"memory_bytes"`
	MemorySwapBytes int64 `json:"memory_swap_bytes"`
	PidsLimit       int64 `json:"pids_limit"`
}

type Result

type Result struct {
	ID      string `json:"id"`
	Outcome string `json:"outcome"`
	Detail  string `json:"detail,omitempty"`
}

Result is what became of a command. Detail is bounded: an agent cannot make the control plane store an arbitrary amount of text by failing loudly.

type Rotate

type Rotate struct {
	PublicKey []byte `json:"public_key"`
	Signature []byte `json:"signature"`
}

Rotate carries a freshly minted public key and the current key's signature over it.

type Rotated

type Rotated struct {
	Fingerprint string `json:"fingerprint"`
	Code        string `json:"code,omitempty"`
}

Rotated names the key that now authenticates (server → agent) or was recorded (ack of Rotate).

type Sample

type Sample struct {
	ContainerID  string  `json:"container_id"`
	CPUPercent   float64 `json:"cpu_percent"`
	MemoryBytes  int64   `json:"memory_bytes"`
	MemoryLimit  int64   `json:"memory_limit"`
	RxBytes      int64   `json:"rx_bytes"`
	TxBytes      int64   `json:"tx_bytes"`
	Pids         int64   `json:"pids"`
	RestartCount int64   `json:"restart_count"`
}

Sample is one container's usage at ObservedAt. CPUPercent is the share of one core over the interval since the previous sample (100 = one core busy); the first sample after a restart has no interval and reports -1, which the UI shows as "no data" rather than zero. RestartCount is the runtime's own counter for the container, cumulative since it was created, so a rising series across samples is a container restarting. It is -1 when the runtime did not answer, which is not the same as a container that has never restarted.

type Service

type Service struct {
	Namespace string   `json:"namespace"`
	Name      string   `json:"name"`
	Type      string   `json:"type"`
	ClusterIP string   `json:"cluster_ip"`
	Ports     []string `json:"ports"`
	Instance  string   `json:"instance,omitempty"`
	Service   string   `json:"service,omitempty"`
}

type Snapshot

type Snapshot struct {
	Generation uint64      `json:"generation"`
	ObservedAt time.Time   `json:"observed_at"`
	Engine     Engine      `json:"engine"`
	Containers []Container `json:"containers"`
	Images     []Image     `json:"images"`
	Networks   []Network   `json:"networks"`
	Volumes    []Volume    `json:"volumes"`
	// Kubernetes is a cluster agent's inventory; nil from a Docker agent (CheckRuntimeShape).
	Kubernetes *KubernetesInventory `json:"kubernetes,omitempty"`
	// Truncated names the lists that hit their cap; the UI shows the gap.
	Truncated []string `json:"truncated,omitempty"`
}

type StorageClass

type StorageClass struct {
	Name    string `json:"name"`
	Default bool   `json:"default"`
}

StorageClass is a cluster StorageClass as the inventory reports it; Default is the is-default-class annotation.

type TerminalSize

type TerminalSize struct {
	Rows    int `json:"rows"`
	Columns int `json:"columns"`
}

func (TerminalSize) Validate

func (s TerminalSize) Validate() error

type Volume

type Volume struct {
	Name       string    `json:"name"`
	Driver     string    `json:"driver"`
	Mountpoint string    `json:"mountpoint"`
	CreatedAt  time.Time `json:"created_at"`
	// Plain is a local volume without driver options, so no host path backs it; false from an
	// agent too old to say.
	Plain bool `json:"plain,omitempty"`
}

type Workload

type Workload struct {
	Kind      string   `json:"kind"`
	Namespace string   `json:"namespace"`
	Name      string   `json:"name"`
	Desired   int32    `json:"desired"`
	Ready     int32    `json:"ready"`
	Updated   int32    `json:"updated"`
	Images    []string `json:"images"`
	Paused    bool     `json:"paused"`
	// Application and Instance are the KyYard labels of a workload KyYard deployed, else empty.
	Application string `json:"application,omitempty"`
	Instance    string `json:"instance,omitempty"`
}

Workload is a Deployment, StatefulSet or DaemonSet.

type WorkloadApply

type WorkloadApply struct {
	Request         string                `json:"request"`
	Endpoint        string                `json:"endpoint"`
	IssuedAt        time.Time             `json:"issued_at"`
	Deadline        time.Time             `json:"deadline"`
	Target          WorkloadRef           `json:"target"`
	ResourceVersion string                `json:"resource_version"`
	Spec            WorkloadConfiguration `json:"spec"`
	Create          bool                  `json:"create,omitempty"`
}

WorkloadApply sets a workload's pod template (image, command, args, env, resources) and replicas and paused from Spec, on the object at ResourceVersion only. With Create it instead creates a Deployment that must not exist, from containers, replicas and strategy only, with no ResourceVersion. It is answered by a DeploymentResult whose Deployment is Request and whose one service is WorkloadApplyService.

func (WorkloadApply) Validate

func (a WorkloadApply) Validate(now time.Time) error

Validate holds the spec to the target and version it was read at: desired state, so no observation time, not managed and nothing unsupported.

type WorkloadCondition

type WorkloadCondition struct {
	Type   string `json:"type"`
	Status string `json:"status"`
	Reason string `json:"reason"`
}

type WorkloadConfiguration

type WorkloadConfiguration struct {
	RunManifest     json.RawMessage     `json:"run_manifest,omitempty"`
	Target          WorkloadRef         `json:"target"`
	ObservedAt      time.Time           `json:"observed_at"`
	ResourceVersion string              `json:"resource_version"`
	Replicas        *int32              `json:"replicas,omitempty"`
	Paused          bool                `json:"paused"`
	Strategy        string              `json:"strategy"`
	Containers      []WorkloadContainer `json:"containers"`
	InitContainers  []WorkloadContainer `json:"init_containers"`
	EnvFrom         []string            `json:"env_from"`
	Managed         bool                `json:"managed"`
	Unsupported     []string            `json:"unsupported"`
}

WorkloadConfiguration is the editable pod template of a Deployment, StatefulSet or DaemonSet. Replicas is nil exactly for a DaemonSet; Paused is a Deployment's only. EnvFrom entries are "secret/<name>" or "configmap/<name>". Managed is a workload KyYard deployed, edited through its application. Unsupported names, from WorkloadUnsupportedCodes, what an apply would drop.

func (*WorkloadConfiguration) Validate

func (c *WorkloadConfiguration) Validate(target WorkloadRef, now time.Time) error

Validate bounds an untrusted agent's read before it reaches an HTTP response.

type WorkloadContainer

type WorkloadContainer struct {
	Name      string            `json:"name"`
	Image     string            `json:"image"`
	ImageID   string            `json:"image_id"`
	Command   []string          `json:"command"`
	Args      []string          `json:"args"`
	Env       []WorkloadEnv     `json:"env"`
	Resources WorkloadResources `json:"resources"`
}

WorkloadContainer is one container of a pod template. ImageID is what a running pod reports, "" when none does.

type WorkloadEnv

type WorkloadEnv struct {
	Name         string `json:"name"`
	Value        string `json:"value"`
	SecretRef    string `json:"secret_ref,omitempty"`
	ConfigMapRef string `json:"config_map_ref,omitempty"`
}

WorkloadEnv is a literal Value or a reference ("<name>/<key>") to a Secret or ConfigMap key, never both: a referenced value is never read.

type WorkloadRef

type WorkloadRef struct {
	Namespace string `json:"namespace"`
	Kind      string `json:"kind,omitempty"`
	Name      string `json:"name"`
	UID       string `json:"uid,omitempty"`
}

WorkloadRef has two shapes. An inspection names a Deployment by UID and no Kind (valid); a configuration read, an apply or a command names an object by Kind and no UID (validObject, ParseWorkloadRef).

func ParseWorkloadRef

func ParseWorkloadRef(reference string) (WorkloadRef, error)

ParseWorkloadRef reads "<namespace>/<kind>/<name>", the form a command's Reference carries.

func (WorkloadRef) String

func (r WorkloadRef) String() string

type WorkloadResources

type WorkloadResources struct {
	CPURequest    string `json:"cpu_request"`
	CPULimit      string `json:"cpu_limit"`
	MemoryRequest string `json:"memory_request"`
	MemoryLimit   string `json:"memory_limit"`
}

WorkloadResources are Kubernetes quantity strings, "" when unset.

type WorkloadStatus

type WorkloadStatus struct {
	UID                string              `json:"uid"`
	Generation         int64               `json:"generation"`
	ObservedGeneration int64               `json:"observed_generation"`
	Desired            int32               `json:"desired"`
	Updated            int32               `json:"updated"`
	Ready              int32               `json:"ready"`
	Available          int32               `json:"available"`
	Conditions         []WorkloadCondition `json:"conditions"`
	Pods               []PodStatus         `json:"pods"`
	Missing            bool                `json:"missing"`
}

WorkloadStatus is a Deployment's rollout state and its pods. Missing: the Deployment is gone, and nothing else is set. A UID other than the target's is a Deployment recreated under the name.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL