Documentation
¶
Overview ¶
Package agentbackend defines the implementation-neutral contract between Obot's hosted-agent controllers and an agent runtime provider.
Index ¶
- Constants
- Variables
- type Backend
- type DeleteResult
- type DesiredInstance
- type DesiredPool
- type Disabled
- func (Disabled) DeleteInstance(context.Context, InstanceRef) (DeleteResult, error)
- func (Disabled) DeletePool(context.Context, PoolRef) (DeleteResult, error)
- func (Disabled) GetPoolUtilization(context.Context, PoolRef) (UtilizationSnapshot, error)
- func (Disabled) ObserveInstance(context.Context, InstanceRef) (InstanceObservation, error)
- func (Disabled) ObservePool(context.Context, PoolRef) (PoolObservation, error)
- func (Disabled) ReconcileInstance(context.Context, DesiredInstance) (InstanceObservation, error)
- func (Disabled) ReconcilePool(context.Context, DesiredPool) (PoolObservation, error)
- type Event
- type File
- type Harness
- type InstanceBackend
- type InstanceObservation
- type InstanceRef
- type InstanceResources
- type InstanceUtilization
- type Model
- type PoolBackend
- type PoolObservation
- type PoolRef
- type Pressure
- type ResourceKind
- type ResourceQuantity
- type ResourceUtilization
- type SecretRef
- type Source
- type State
- type Subscriber
- type TerminalBackend
- type TerminalSession
- type TerminalSize
- type UtilizationReader
- type UtilizationSnapshot
Constants ¶
const ( // MinSandboxMemoryBytes is the smallest memory reservation a sandbox may be // given. Dividing a pool between many sandboxes can produce a share below // what any real agent image needs to start, and such a sandbox schedules // successfully and then dies immediately, which reads as a broken agent // rather than an over-subscribed pool. MinSandboxMemoryBytes int64 = 200 << 20 // 200MB // MinSandboxCPUVCPUs keeps a reservation from rounding to zero. CPU is // compressible, so a small share only means a slow sandbox, but a zero // request means no guarantee at all. MinSandboxCPUVCPUs = 0.01 // DefaultMaxSandboxes applies when a pool does not say. It is a capacity // planning decision, so there is no good universal answer; this only keeps // an unconfigured pool usable. DefaultMaxSandboxes = 10 )
Variables ¶
var ErrDisabled = errors.New("agent runtime backend is disabled")
Functions ¶
This section is empty.
Types ¶
type Backend ¶
type Backend interface {
InstanceBackend
PoolBackend
UtilizationReader
}
Backend is the complete desired-state and observation contract required by hosted agents. Implementations must make every operation idempotent.
type DeleteResult ¶
type DeleteResult struct {
Complete bool
}
type DesiredInstance ¶
type DesiredInstance struct {
Ref InstanceRef
Pool PoolRef
Revision string
Name string
Description string
Harness Harness
Image string
Source Source
Model Model
Env map[string]string
Files []File
Secrets []SecretRef
// Requests is what this sandbox is guaranteed, and Limits is what it may
// burst to. Both are derived from the pool rather than declared by the
// agent: a pool is a shared bucket, and an agent has no inherent size.
//
// They are carried here, rather than computed by a backend, so that they
// participate in the desired revision. Resizing a pool therefore changes
// every sandbox's revision and restarts it, which is the only way a running
// sandbox picks up new limits.
Requests InstanceResources
Limits InstanceResources
// Port is the HTTP port the agent serves on. Zero means it serves nothing,
// and a backend should publish no address for it.
Port int
// Terminal asks the backend to keep the sandbox attachable for an
// interactive session.
Terminal bool
}
func (DesiredInstance) Redacted ¶
func (d DesiredInstance) Redacted() DesiredInstance
Redacted returns a copy with every secret value cleared, for hashing into the desired revision or for logging. Version still varies with the value, so a rotation changes the revision without the revision ever containing a secret.
type DesiredPool ¶
type DesiredPool struct {
Ref PoolRef
Revision string
Capacity ResourceQuantity
// MaxSandboxes bounds how many sandboxes share the pool, and so determines
// each one's guaranteed share.
MaxSandboxes int
Suspended bool
}
type Disabled ¶
type Disabled struct{}
Disabled is a Backend that consistently reports that hosted-agent runtime management is unavailable. It lets service wiring inject a non-nil backend without giving disabled mode any synthetic behavior.
func (Disabled) DeleteInstance ¶
func (Disabled) DeleteInstance(context.Context, InstanceRef) (DeleteResult, error)
func (Disabled) DeletePool ¶
func (Disabled) GetPoolUtilization ¶
func (Disabled) ObserveInstance ¶
func (Disabled) ObserveInstance(context.Context, InstanceRef) (InstanceObservation, error)
func (Disabled) ObservePool ¶
func (Disabled) ReconcileInstance ¶
func (Disabled) ReconcileInstance(context.Context, DesiredInstance) (InstanceObservation, error)
func (Disabled) ReconcilePool ¶
func (Disabled) ReconcilePool(context.Context, DesiredPool) (PoolObservation, error)
type Event ¶
type Event struct {
Kind ResourceKind
Instance InstanceRef
Pool PoolRef
}
type InstanceBackend ¶
type InstanceBackend interface {
ReconcileInstance(context.Context, DesiredInstance) (InstanceObservation, error)
ObserveInstance(context.Context, InstanceRef) (InstanceObservation, error)
DeleteInstance(context.Context, InstanceRef) (DeleteResult, error)
}
type InstanceObservation ¶
type InstanceRef ¶
type InstanceResources ¶
InstanceResources is a sandbox's share of its pool, in plain units so the contract stays independent of any backend's resource model.
These are plain numbers on purpose. Quantity-style types serialize equal values to different strings ("1" and "1000m"), which would make the desired revision hash unstable and trigger redeploys that change nothing.
func SandboxShare ¶
func SandboxShare(capacity ResourceQuantity, maxSandboxes int) (requests, limits InstanceResources, effectiveMax int)
SandboxShare divides a pool between its sandboxes.
A pool is a shared bucket. Each sandbox reserves an equal fraction of it, so that it can always be scheduled, and may burst to the whole pool when its neighbours are idle. Agents therefore have no size of their own: raising a pool's sandbox count shrinks everyone's guaranteed share and nothing else.
This is an approximation of a single shared cgroup, which Kubernetes cannot express across pods. The difference that remains is that reservations are summed against the node, so a pool cannot be oversubscribed as freely as one cgroup would allow.
The floors mean effectiveMax can be lower than the configured maximum: once a share would fall below a floor, the pool holds fewer sandboxes than asked for. Returning that, rather than silently admitting sandboxes that cannot run, lets the caller bound the pool by a number that is actually true.
func (InstanceResources) IsZero ¶
func (r InstanceResources) IsZero() bool
type InstanceUtilization ¶
type InstanceUtilization struct {
Ref InstanceRef
State State
Utilization ResourceUtilization
}
type PoolBackend ¶
type PoolBackend interface {
ReconcilePool(context.Context, DesiredPool) (PoolObservation, error)
ObservePool(context.Context, PoolRef) (PoolObservation, error)
DeletePool(context.Context, PoolRef) (DeleteResult, error)
}
type PoolObservation ¶
type ResourceKind ¶
type ResourceKind string
const ( ResourceKindInstance ResourceKind = "instance" ResourceKindPool ResourceKind = "pool" )
type ResourceQuantity ¶
type ResourceUtilization ¶
ResourceUtilization is live usage. StorageBytes is only ever set on a pool: sandboxes share one volume separated by subPath, which the kubelet does not measure per directory, so a sandbox's own disk usage is not observable without a node agent.
type SecretRef ¶
type SecretRef struct {
ID string
EnvName string
FilePath string
// Version changes whenever the value behind ID changes. It participates in
// the desired revision so that a rotated secret restarts the sandbox.
//
// Agents read their credentials once at startup and cannot reload them, so
// a sandbox left running across a rotation would hold a credential that no
// longer works. Versioning the reference propagates the rotation while
// keeping the value itself out of desired state, status and the revision.
Version string
// Value is the secret itself, passed transiently so a backend can write it
// wherever that backend keeps secrets. It is excluded from the desired
// revision by DesiredInstance.Redacted, and must never be persisted to
// instance spec or status, or logged.
Value string
}
SecretRef contains routing metadata only. Secret values are managed through the provider's secret channel and must never enter this persisted contract.
type Subscriber ¶
Subscriber is an optional fast path for lifecycle changes. Events are hints; callers must observe the referenced resource before persisting status.
type TerminalBackend ¶
type TerminalBackend interface {
// AttachTerminal connects to a sandbox's existing console. It attaches to
// the process the sandbox is already running rather than starting a new
// one, so an operator sees the same session the agent is driving.
//
// This requires the sandbox to have been started with a TTY, which is what
// a harness marks by being interactive. Attaching to one that was not is an
// error rather than a silently empty session.
AttachTerminal(ctx context.Context, ref InstanceRef, size TerminalSize) (TerminalSession, error)
}
TerminalBackend is an optional capability: a backend that can attach an interactive session to a running sandbox.
It is separate from Backend so that a runtime without a console -- or one that has not implemented it yet -- simply does not satisfy it, and callers discover that with a type assertion rather than through a method that returns "unsupported" at runtime.
type TerminalSession ¶
type TerminalSession interface {
io.ReadWriteCloser
// Resize tells the sandbox its terminal changed shape. Without it a program
// drawing a full-screen interface keeps using the size it saw at startup.
Resize(size TerminalSize) error
}
TerminalSession is a live console.
Read yields console output and Write sends input. A console multiplexes what would otherwise be stdout and stderr onto one stream, because that is what a TTY does: the terminal is the process's controlling terminal, and both descriptors point at it. Callers that distinguish the two are reporting their own errors, not the sandbox's.
type TerminalSize ¶
TerminalSize is measured in character cells.
type UtilizationReader ¶
type UtilizationReader interface {
GetPoolUtilization(context.Context, PoolRef) (UtilizationSnapshot, error)
}
type UtilizationSnapshot ¶
type UtilizationSnapshot struct {
Timestamp time.Time
Pool ResourceUtilization
Instances []InstanceUtilization
Pressure Pressure
// StorageMeasured reports whether Pool.StorageBytes is a real measurement.
// A backend that cannot attribute disk usage to this pool alone leaves it
// false, so a caller can say so rather than draw an empty disk that is
// really an unknown one.
StorageMeasured bool
}
UtilizationSnapshot is a live point-in-time sample, not desired state or historical accounting.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package fake provides a process-local agent backend for development and provider contract tests.
|
Package fake provides a process-local agent backend for development and provider contract tests. |
|
Package kubernetes implements the agent runtime backend on top of a Kubernetes cluster.
|
Package kubernetes implements the agent runtime backend on top of a Kubernetes cluster. |