cpboot

package
v0.8.0 Latest Latest
Warning

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

Go to latest
Published: May 12, 2026 License: MIT Imports: 24 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ClawkerCPBinary []byte

ClawkerCPBinary is the pre-compiled static Linux binary for the clawker control plane daemon.

Built by: make cp-binary Target: GOOS=linux CGO_ENABLED=0 go build ./cmd/clawker-cp

This binary is embedded into every clawker release binary so the clawker-cp container image can be built on-demand without a registry or source tree. Like EBPFManagerBinary and the firewall CoreDNS binary, it must match the Docker host's architecture (arm64 or amd64).

At runtime the CP bootstrapper (B2 Task 3) writes this binary into an on-demand Alpine image and starts the clawker-cp container from that image. The daemon runs inside the container as PID 1.

Lives in the cpboot subpackage so cmd/clawker-cp can import internal/controlplane without dragging in this embed directive — the daemon would otherwise need to embed itself, which can't resolve during its own build.

View Source
var EBPFManagerBinary []byte

EBPFManagerBinary is the pre-compiled static Linux binary for the eBPF manager. Built by: make ebpf-binary Target: GOOS=linux CGO_ENABLED=0 go build ./internal/controlplane/firewall/ebpf/cmd

This binary is embedded into every clawker release binary so the eBPF manager container image can be built on-demand without a registry or source tree. The binary must match the Docker host's architecture (arm64 or amd64).

Functions

func CPRunning

func CPRunning(ctx context.Context, dc *docker.Client) (bool, error)

CPRunning reports whether the CP container exists AND is in the running state. Used by CLI commands (`firewall status`, `firewall down`) that observe or tear down the CP without wanting to trigger EnsureRunning's creation path as a side effect. Returns (false, nil) when absent; errors only on Docker API failures.

func EnsureRunning

func EnsureRunning(ctx context.Context, opts EnsureOpts) error

func Stop

func Stop(ctx context.Context, dc *docker.Client) error

Stop removes the CP container. Used by `clawker controlplane down`. Docker sends SIGTERM to PID 1 (clawker-cp), whose own shutdown path drains the firewall stack (Envoy + CoreDNS) and flushes per-container eBPF state before exiting — this call does not need to tear those down separately (INV-B2-008).

Types

type CPContainerConfig

type CPContainerConfig struct {
	// Image is the container image to use.
	Image string
	// Labels are the Docker labels applied to the container.
	Labels map[string]string
	// Mounts are the bind mounts for the container.
	Mounts []mount.Mount
	// PortBindings are the published port mappings.
	PortBindings network.PortMap
	// CapAdd are the Linux capabilities added to the container.
	CapAdd []string
	// Env are environment variables for the container.
	Env []string
	// Cmd is the command to run inside the container.
	Cmd []string
	// NetworkName is the Docker network to attach to.
	NetworkName string
	// RestartPolicy is the Docker restart policy for the container.
	RestartPolicy container.RestartPolicy
	// ExtraHosts adds /etc/hosts entries inside the CP container.
	// Used to map host.docker.internal → host-gateway so the daemon
	// can reach host-loopback-bound services (currently the OTEL
	// collector OTLP HTTP receiver). Agent containers cannot reach the
	// same address because the BPF firewall redirects gateway traffic
	// for non-hostproxy ports to Envoy; the CP is exempt because it
	// owns container_map and is never enrolled.
	ExtraHosts []string
}

CPContainerConfig holds the configuration for creating the control plane container. It is a structured representation that can be inspected and tested without requiring a Docker daemon.

func BuildCPContainerConfig

func BuildCPContainerConfig(cfg config.Config, opts CPContainerOpts) (*CPContainerConfig, error)

BuildCPContainerConfig constructs the CPContainerConfig for the control plane container. Reads all ports from cfg.Settings().ControlPlane — defaults come from struct tags via the storage layer.

Bind mounts:

  • Config dir (read-only) → CP loads config.NewConfig() inside the container
  • CLI signing JWK (public key) → for Hydra client registration (read-only)
  • Server TLS cert + key → for gRPC TLS (read-only)
  • /sys/fs/cgroup, /sys/fs/bpf → for eBPF programs
  • /var/run/docker.sock (read-only) → Docker API access for container state verification

The CLI's private signing key NEVER enters the container.

type CPContainerOpts

type CPContainerOpts struct {
	HostDirs HostDirs
}

CPContainerOpts bundles the host-side inputs BuildCPContainerConfig needs that cannot be derived from config.Config alone.

type CPHealthTimeoutError

type CPHealthTimeoutError struct {
	Timeout    time.Duration
	URL        string
	LastStatus int
	LastBody   string
	Err        error
}

CPHealthTimeoutError is returned when /healthz does not return 200 within cpReadyTimeout. Separate from firewall.HealthTimeoutError so callers can distinguish "CP never came up" from "Envoy/CoreDNS unhealthy" via errors.As. Carries the last observed probe outcome.

func (*CPHealthTimeoutError) Error

func (e *CPHealthTimeoutError) Error() string

func (*CPHealthTimeoutError) Unwrap

func (e *CPHealthTimeoutError) Unwrap() error

type EnsureOpts

type EnsureOpts struct {
	Docker   *docker.Client
	Config   config.Config
	Logger   *logger.Logger
	HostDirs HostDirs
}

EnsureRunning is the host-side entry point for bringing up the control plane. Idempotent and concurrency-safe. Returns nil when the CP container is running and /healthz is green.

Steps (in order):

  1. Ensure CLI auth material (CA, signing key, server cert).
  2. Ensure CP image present (build from embedded binaries if missing).
  3. If an existing CP container is found, start it (if stopped) and return once /healthz is green. Mount spec is NOT inspected: CP mounts are a function of install-level XDG env vars + compile- time constants, never of clawker.yaml or settings.yaml, so legitimate in-process divergence cannot happen. A host-level attacker who can mutate the CP container spec already has privileges that trivially bypass anything a mount-inspection guard could protect. (Spec INV-B2-006 originally defended the B1→B2 RO→RW upgrade — now vestigial and retired.)
  4. Ensure clawker-net exists (defensive guard — CLI bootstrap is normally the primary owner).
  5. Discover the network to compute the CP's static IP.
  6. Create and start the CP container with static IP + clawker-net attachment (INV-B2-014).
  7. Poll /healthz on 127.0.0.1:<HealthPort> until 200 or timeout.

On partial failure (container created but /healthz timed out) the next call observes the stopped/unhealthy container and reconciles. EnsureOpts bundles the inputs EnsureRunning needs. HostDirs is required; callers resolve it host-side from consts.{ConfigDir,DataDir,StateDir, CacheDir} before invoking. The CP container reads the host paths back from the CLAWKER_HOST_*_DIR env vars injected by BuildCPContainerConfig so it can compute sibling container bind mount sources via Docker-outside-of-Docker.

type HostDirs

type HostDirs struct {
	Config string
	Data   string
	State  string
	Cache  string
}

HostDirs carries the host-FS XDG-shaped directory roots the CP needs to compute sibling container bind mount sources when it creates Envoy / CoreDNS / future containers via Docker-outside-of-Docker. All four fields are REQUIRED — host-side callers resolve them via consts.ConfigDir() / DataDir() / StateDir() / CacheDir(). Missing any field fails fast at BuildCPContainerConfig and EnsureRunning rather than silently producing a bad bind source that only surfaces when Docker rejects the container-create request.

func (HostDirs) Validate

func (h HostDirs) Validate() error

Validate returns an error naming the first empty field, or nil when all four are populated.

type Manager

type Manager interface {
	// EnsureRunning is idempotent: it builds the CP image if missing,
	// creates/starts the container on clawker-net, and blocks until the
	// aggregate /healthz endpoint returns 200. Returns nil when the CP
	// is running and healthy.
	EnsureRunning(ctx context.Context) error

	// Stop removes the CP container. SIGTERM reaches PID 1 (clawker-cp),
	// which drains the firewall stack and flushes per-container eBPF
	// state before exiting, so this leaves no orphans behind
	// (INV-B2-008). No-op when the CP container is absent.
	Stop(ctx context.Context) error

	// IsRunning reports whether a managed CP container exists AND is in
	// Docker's `running` state. Never triggers EnsureRunning — safe for
	// status commands that must not bootstrap as a side effect.
	IsRunning(ctx context.Context) (bool, error)

	// ProbeHealthz performs a single short-deadline GET against the CP's
	// /healthz endpoint on the configured HealthPort. Returns the HTTP
	// status on any response (caller decides if 200 is required), or
	// (0, err) on transport failure.
	ProbeHealthz(ctx context.Context) (int, error)
}

Manager is the CLI-facing noun for the host-side clawker control plane lifecycle. CLI commands that need to bring the CP up, tear it down, or observe its health go through this interface rather than importing the package-level functions directly — that keeps the Factory the single place where Docker/Config/Logger resolution is wired and lets tests inject a fake without reaching into package-level seams.

func NewManager

func NewManager(
	client func(context.Context) (*docker.Client, error),
	cfg func() (config.Config, error),
	log func() (*logger.Logger, error),
) Manager

NewManager constructs a Manager from lazy Factory accessors. Callers are expected to hand in the same closures that live on *cmdutil.Factory so the manager and direct `f.Client/Config/Logger` callers observe the same cached singletons.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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