Documentation
¶
Overview ¶
Package guestplane is the guest-side half of the GuestPodPlane bidi stream defined in weft-proto/guestv1. The host serves GuestPodPlane on AF_VSOCK ; this client dials CID_HOST (=2) on the agent's configured port, sends the mandatory GuestHello, receives a GuestHelloAck (carrying the operator's PodSpec when known), and stays connected to :
- emit a PodStatus heartbeat every interval (uptime, container summary stub for now — containers aren't reconciled in-guest yet beyond the on-NATS reconciler) ;
- read ControlRequest frames from the host and ack them via ControlResponse so the host's dispatcher doesn't stall.
The client is intentionally minimal — the wire contract here is what protects against pod-id impersonation (the host's strict- when-known peer-CID check refuses any Hello announcing the wrong pod_id). Any future per-container state machine lives in pkg/containers ; this file just owns the wire layer.
Index ¶
Constants ¶
const ( DefaultDialAttempts = 60 // ~1 minute of retries DefaultDialDelay = 1 * time.Second // between attempts DefaultHeartbeatTick = 10 * time.Second // PodStatus cadence DefaultReconnectGap = 5 * time.Second // after Recv error )
Default reconnect / heartbeat cadences. Tuned for "fast enough the operator notices a flapping link, slow enough that an idle VM doesn't fill weft-agent's stderr with reconnect noise".
const DefaultPort uint32 = 7777
Default port the host-side weft-agent binds its AF_VSOCK listener on. Operators can override via the agent flag ; the guest side has to agree, so this constant is the wire contract. 7777 chosen to match cmd/weft/main.go's --vsock-port default.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Config ¶
type Config struct {
// HostCID is the AF_VSOCK CID to dial. Always 2 (CID_HOST) in
// production ; the field exists so a unit test can dial a
// loopback listener via VsockCIDLocal=1 if it ever gets one.
HostCID uint32
// Port is the host's GuestPodPlane vsock port.
Port uint32
// PodID announced via GuestHello. Must match the pod_id the
// host has on record (= VM name, the strict-when-known guard
// rejects a Hello where peer.CID() != adapter.PodCID(pod_id)).
PodID string
// KernelInfo / InitVersion go into the Hello so the host's
// logs carry the booted kernel + guest agent build.
KernelInfo string
InitVersion string
// HeartbeatTick is how often a PodStatus frame is sent. 0 →
// DefaultHeartbeatTick. Set negative to disable heartbeats
// entirely (the Hello/Ack handshake still runs).
HeartbeatTick time.Duration
// ReconnectGap is the pause before redialing after a Recv
// error. 0 → DefaultReconnectGap.
ReconnectGap time.Duration
// DialAttempts is how many times we retry the initial dial
// before giving up. 0 → DefaultDialAttempts.
DialAttempts int
// DialDelay is the per-attempt delay during the initial dial
// retry loop. 0 → DefaultDialDelay.
DialDelay time.Duration
Logger *log.Logger
// Dispatcher routes incoming ControlRequest frames into the
// in-guest reconcilers. nil = the legacy "not yet routed" stub
// reply is returned to the host (every ACK still carries the
// matching CallId so the host's correlator doesn't stall).
Dispatcher *Dispatcher
}
Config carries the knobs the agent's main() wires up. Empty fields fall back to the Default* constants — letting the caller build a Config{Host: ..., Logger: ...} and ship reasonable defaults.
type Dispatcher ¶ added in v0.4.1
type Dispatcher struct {
// StopPod is invoked on a ControlRequest_StopPod. graceSeconds is
// the StopPod.GraceSeconds value (0 = caller-chosen default).
StopPod func(ctx context.Context, graceSeconds uint32) error
// Kill is invoked on a ControlRequest_Kill. signal defaults to
// "SIGTERM" when empty.
Kill func(ctx context.Context, containerID, signal string) error
// Exec is invoked on a ControlRequest_Exec. The dispatcher
// receives the proto value verbatim so it can decide whether to
// open a pty (tty=true) or a one-shot exec.
Exec func(ctx context.Context, e *guestv1.ExecInContainer) error
// Update is invoked on a ControlRequest_Update. UpdateContainer
// carries the new command + merged env for one container.
Update func(ctx context.Context, u *guestv1.UpdateContainer) error
}
Dispatcher is the action layer behind dispatchControl : a ControlRequest frame arrives over the AF_VSOCK GuestPodPlane, the wire layer (this file) ACKs it, and routes it through these callbacks so the in-guest reconcilers (pkg/containers, pkg/execsession) actually do the work.
All fields are optional. A nil callback resolves to the legacy "not yet routed" Error so the host's operator sees a clear signal the dispatch slot hasn't been wired locally — preserving the dispatchControl-as-stub behaviour for callers that don't pass one.
Each callback returns the *string the host should surface as the ControlResponse.Error : empty / "" = success. Errors are stringified by the caller, not the dispatcher, so the wire shape stays simple.