runtime

package
v0.7.0 Latest Latest
Warning

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

Go to latest
Published: Sep 11, 2026 License: GPL-3.0 Imports: 20 Imported by: 0

Documentation

Overview

Package runtime abstracts a container runtime (Docker or Podman) behind the small set of operations a consumer needs: discover containers and their mounts, watch the socket for lifecycle changes, exec into a container to quiesce or dump it, and stop or start it for a cold backup.

The interface is deliberately kept free of any tool-specific type. It was shaped against exactly one real consumer before being lifted into github.com/tagwright/core, which is the discipline that keeps the abstraction honest.

The Docker adapter lands first. The Podman adapter follows behind the same interface, talking to Podman's Docker-compatible compat API and absorbing the socket-path and compose-label differences.

Index

Constants

This section is empty.

Variables

View Source
var ErrNotImplemented = errors.New("runtime: not implemented")

ErrNotImplemented is returned by adapter methods that are not wired up yet.

Functions

This section is empty.

Types

type Container

type Container struct {
	ID      string
	Name    string
	State   string // running, exited, paused, ...
	Labels  map[string]string
	Mounts  []Mount
	Project string // com.docker.compose.project, empty if not a compose service
	Service string // com.docker.compose.service, empty if not a compose service

	// Image is the container's image reference. Populated on both List and
	// Inspect.
	Image string

	// LogDriver is the effective logging driver, e.g. "json-file", "local",
	// "journald". Inspect-only (the list summary carries no HostConfig), and
	// empty when unknown.
	LogDriver string

	// Env holds the container's environment entries as KEY=VALUE strings.
	// Inspect-only. Core surfaces the raw slice: callers that only need the
	// names must split it themselves and must not log the values.
	Env []string

	// Health is the container health status when a HEALTHCHECK is defined,
	// e.g. "healthy", "unhealthy", "starting". Empty when the container has no
	// healthcheck. Inspect-only.
	Health string

	// ExitCode is the exit code of the container's main process from its last
	// run, read off Docker's inspect State.ExitCode. It is 0 for a container
	// that is still running or that exited cleanly, so a consumer treating a
	// non-zero value as a failure must pair it with the State ("exited") or a
	// die event rather than reading it in isolation. Inspect-only.
	ExitCode int

	// OOMKilled reports whether the container's last exit was the kernel OOM
	// killer reaping it, read off Docker's inspect State.OOMKilled. Inspect-only.
	OOMKilled bool

	// RestartCount is how many times the runtime has restarted this container
	// under its restart policy, read off Docker's inspect RestartCount. A
	// consumer watching for a crash loop reads this alongside the start events
	// from Watch; core surfaces the count and leaves the loop policy to the
	// consumer. Inspect-only.
	RestartCount int

	// Networks lists the container's network attachments and the IP
	// addresses it holds on each. Unlike Image/LogDriver/Env/Health, the
	// list summary carries this data at no extra cost (it is already part
	// of the same API response), so Networks is populated on both List and
	// Inspect.
	Networks []ContainerNetwork
}

Container is the normalized view of a container across runtimes.

type ContainerNetwork added in v0.3.0

type ContainerNetwork struct {
	Name string
	ID   string
	IPs  []netip.Addr
}

ContainerNetwork is one network a container is attached to, along with the IP addresses it holds on that network.

type ContainerSpec added in v0.4.0

type ContainerSpec struct {
	// Name is the container name. Empty lets the engine assign one.
	Name string
	// Image is the image reference to create from. Call PullImage first if it
	// may not be present locally.
	Image string
	// Cmd overrides the image's default command when non-empty.
	Cmd []string
	// Entrypoint overrides the image's default entrypoint when non-empty.
	Entrypoint []string
	// Env holds environment entries as KEY=VALUE strings.
	Env []string
	// Labels are stamped on the container for identification and cleanup.
	Labels map[string]string
	// Mounts attaches named volumes into the container.
	Mounts []VolumeMount
	// Network is the network name or id to attach to. Empty uses the engine's
	// default network; a verify passes the isolated network from CreateNetwork.
	Network string
	// Start starts the container immediately after creating it.
	Start bool
}

ContainerSpec describes a throwaway container to create. It is deliberately the minimal surface verify needs: an image, volume mounts, a network, env, labels, an optional command/entrypoint override, and whether to start it. It publishes no ports, so a created container is never reachable from outside the (internal) network it is placed on.

type DockerRuntime

type DockerRuntime struct {
	// contains filtered or unexported fields
}

DockerRuntime is the Docker adapter for Runtime. It talks to the Docker Engine API over the socket a consumer mounts read-only, using the request and mapping machinery in engine.go that it shares with PodmanRuntime.

The client is created lazily on first use and cached, so constructing a DockerRuntime never touches the socket: nothing fails until a method that actually needs the daemon is called.

func NewDocker

func NewDocker(socket string) *DockerRuntime

NewDocker returns a Docker adapter bound to the given API socket path. An empty socket resolves to the conventional /var/run/docker.sock, matching what a consumer means by "empty uses the runtime default" and mirroring NewPodman's own empty-socket handling. A non-empty socket is used verbatim, exactly as before, so this never builds a bare "unix://" the Docker SDK cannot parse.

func (DockerRuntime) Close

func (e DockerRuntime) Close() error

Close releases the underlying client.

func (DockerRuntime) CreateContainer added in v0.4.0

func (e DockerRuntime) CreateContainer(ctx context.Context, spec ContainerSpec) (string, error)

CreateContainer creates a container from spec and, if spec.Start, starts it.

func (DockerRuntime) CreateNetwork added in v0.4.0

func (e DockerRuntime) CreateNetwork(ctx context.Context, spec NetworkSpec) (string, error)

CreateNetwork creates an internal (isolated) network and returns its id.

func (DockerRuntime) CreateVolume added in v0.4.0

func (e DockerRuntime) CreateVolume(ctx context.Context, spec VolumeSpec) (string, error)

CreateVolume creates a fresh empty named volume and returns its name.

func (DockerRuntime) Exec

func (e DockerRuntime) Exec(ctx context.Context, id string, spec ExecSpec) (*ExecHandle, error)

Exec runs a command inside a running container and returns a handle whose Stdout streams the command's standard output as it is produced, which matters because the caller pipes a live dump into restic --stdin rather than buffering it. Standard error is captured separately and folded into the error Wait returns on a non-zero exit.

When spec.Stdin is non-nil (a stream-restore piping a dump into the restoring process) it is attached to the command's standard input and copied in a goroutine, then the write half is closed so the command sees EOF. When spec.Stdin is nil this is a no-op and Exec behaves exactly as it always has.

func (DockerRuntime) Inspect

func (e DockerRuntime) Inspect(ctx context.Context, id string) (Container, error)

Inspect returns a single container by ID or name.

func (DockerRuntime) Kill added in v0.2.0

func (e DockerRuntime) Kill(ctx context.Context, id string, signal string) error

Kill sends a signal to a running container, e.g. "SIGHUP" to prompt a collector to reload its configuration.

func (DockerRuntime) List

func (e DockerRuntime) List(ctx context.Context) ([]Container, error)

List returns every container the runtime knows about, running or not.

func (DockerRuntime) ListNetworks added in v0.3.0

func (e DockerRuntime) ListNetworks(ctx context.Context) ([]Network, error)

ListNetworks returns every network the runtime knows about, with its subnet CIDRs and internal flag. It satisfies NetworkInspector for both DockerRuntime and PodmanRuntime, which embed engineClient.

func (DockerRuntime) PullImage added in v0.4.0

func (e DockerRuntime) PullImage(ctx context.Context, ref string) error

PullImage pulls ref if it is not already present locally.

func (DockerRuntime) RemoveContainer added in v0.4.0

func (e DockerRuntime) RemoveContainer(ctx context.Context, id string, force bool) error

RemoveContainer removes a container by id or name along with its anonymous volumes. force removes a running container instead of failing.

func (DockerRuntime) RemoveNetwork added in v0.4.0

func (e DockerRuntime) RemoveNetwork(ctx context.Context, id string) error

RemoveNetwork removes a network by id or name.

func (DockerRuntime) RemoveVolume added in v0.4.0

func (e DockerRuntime) RemoveVolume(ctx context.Context, name string) error

RemoveVolume removes a named volume. It does not force: a volume still held by a container is removed only after the container is gone.

func (DockerRuntime) Restart added in v0.2.0

func (e DockerRuntime) Restart(ctx context.Context, id string) error

Restart restarts a container, using the runtime's default stop timeout.

func (DockerRuntime) Start

func (e DockerRuntime) Start(ctx context.Context, id string) error

Start starts a stopped container.

func (DockerRuntime) Stop

func (e DockerRuntime) Stop(ctx context.Context, id string, timeoutSeconds int) error

Stop stops a running container, waiting up to timeoutSeconds before a kill.

func (DockerRuntime) Watch

func (e DockerRuntime) Watch(ctx context.Context) (<-chan Event, <-chan error)

Watch streams lifecycle events until ctx is cancelled. The error channel carries a terminal error and is then closed alongside the event channel.

type Event

type Event struct {
	Type   EventType
	ID     string
	Name   string
	Labels map[string]string
}

Event is a single lifecycle change on the socket.

type EventType

type EventType string

EventType is a container lifecycle transition.

const (
	EventStart   EventType = "start"
	EventStop    EventType = "stop"
	EventDie     EventType = "die"
	EventDestroy EventType = "destroy"

	// EventOOM is the kernel OOM killer reaping a container's main process,
	// from Docker's "oom" event action. It arrives on its own, ahead of the
	// "die" the reaped process then triggers, so a consumer that wants to
	// distinguish an out-of-memory kill from an ordinary non-zero exit keys on
	// this rather than inferring it from the die alone.
	EventOOM EventType = "oom"

	// EventHealthStatusHealthy and EventHealthStatusUnhealthy are a container's
	// healthcheck transitioning, from Docker's "health_status: healthy" and
	// "health_status: unhealthy" event actions. Docker emits one only when the
	// aggregated health state changes, not on every probe, so each event is an
	// edge a consumer can act on directly. The bare "health_status" action
	// (with no healthy/unhealthy suffix) is not one of these and is not
	// surfaced.
	EventHealthStatusHealthy   EventType = "health_status: healthy"
	EventHealthStatusUnhealthy EventType = "health_status: unhealthy"
)

type ExecHandle

type ExecHandle struct {
	Stdout io.Reader
	Wait   func() (exitCode int, err error)
}

ExecHandle is a running exec. The caller reads Stdout to completion, then calls Wait to learn the exit code. Stderr is captured separately for logging.

type ExecSpec

type ExecSpec struct {
	Cmd  []string
	User string // empty means the container's default user

	// Stdin, when non-nil, is attached to the command's standard input and
	// copied to completion, after which the write side is closed so the
	// command sees EOF. It is nil for the common case (a quiesce or a
	// dump-producing command that reads nothing on stdin); a stream-restore
	// sets it to pipe a backup dump into the restoring process. When nil, Exec
	// behaves exactly as it always has, so this field is backward compatible
	// with every existing caller.
	Stdin io.Reader
}

ExecSpec describes a command to run inside a container.

type Mount

type Mount struct {
	Type        MountType
	Name        string // named-volume name, empty for binds and tmpfs
	Source      string // host-side path, empty for tmpfs
	Destination string // container-side path
	ReadOnly    bool
}

Mount is one filesystem mount attached to a container.

type MountType

type MountType string

MountType distinguishes the kinds of mount a consumer cares about.

const (
	MountVolume MountType = "volume"
	MountBind   MountType = "bind"
	MountTmpfs  MountType = "tmpfs"
)

type Network added in v0.3.0

type Network struct {
	Name     string
	ID       string
	Driver   string
	Internal bool
	Subnets  []netip.Prefix
	Labels   map[string]string
}

Network is the normalized view of a container network across runtimes.

type NetworkInspector added in v0.3.0

type NetworkInspector interface {
	// ListNetworks returns every network the runtime knows about, with its
	// subnet CIDRs and whether it is marked internal.
	ListNetworks(ctx context.Context) ([]Network, error)
}

NetworkInspector is an optional capability a Runtime implementation may satisfy in addition to Runtime. It is kept as a separate interface, rather than a new method on Runtime, so that adding it never breaks an existing consumer's mock or alternate implementation of Runtime: a consumer that wants network introspection type-asserts the value it got back from a constructor (or from Runtime) to NetworkInspector, and a consumer that does not care about networks is unaffected.

DockerRuntime and PodmanRuntime both satisfy NetworkInspector.

type NetworkSpec added in v0.4.0

type NetworkSpec struct {
	Name   string
	Labels map[string]string
}

NetworkSpec describes a throwaway network to create. The network is always created internal (see Provisioner.CreateNetwork), so the spec carries only the name and the labels a caller stamps on for later cleanup.

type PodmanRuntime

type PodmanRuntime struct {
	// contains filtered or unexported fields
}

PodmanRuntime is the Podman adapter for Runtime. Podman's REST API includes a Docker-compatible compat layer (documented against the Docker v1.40 API) on the same socket as its native libpod API, so PodmanRuntime talks to it with the exact request and mapping machinery DockerRuntime uses, in engine.go; the two adapters differ only in their default socket path and in how compose project/service identity is read off a container's labels.

The client is created lazily on first use and cached, so constructing a PodmanRuntime never touches the socket: nothing fails until a method that actually needs the daemon is called.

func NewPodman

func NewPodman(socket string) *PodmanRuntime

NewPodman returns a Podman adapter bound to the given API socket path. An empty socket resolves to a sensible default: the rootless per-user socket derived from XDG_RUNTIME_DIR (or /run/user/<uid> when that is unset, matching systemd's own convention) for a non-root caller, and the rootful system-service socket for a root caller with no XDG_RUNTIME_DIR set.

func (PodmanRuntime) Close

func (e PodmanRuntime) Close() error

Close releases the underlying client.

func (PodmanRuntime) CreateContainer added in v0.4.0

func (e PodmanRuntime) CreateContainer(ctx context.Context, spec ContainerSpec) (string, error)

CreateContainer creates a container from spec and, if spec.Start, starts it.

func (PodmanRuntime) CreateNetwork added in v0.4.0

func (e PodmanRuntime) CreateNetwork(ctx context.Context, spec NetworkSpec) (string, error)

CreateNetwork creates an internal (isolated) network and returns its id.

func (PodmanRuntime) CreateVolume added in v0.4.0

func (e PodmanRuntime) CreateVolume(ctx context.Context, spec VolumeSpec) (string, error)

CreateVolume creates a fresh empty named volume and returns its name.

func (PodmanRuntime) Exec

func (e PodmanRuntime) Exec(ctx context.Context, id string, spec ExecSpec) (*ExecHandle, error)

Exec runs a command inside a running container and returns a handle whose Stdout streams the command's standard output as it is produced, which matters because the caller pipes a live dump into restic --stdin rather than buffering it. Standard error is captured separately and folded into the error Wait returns on a non-zero exit.

When spec.Stdin is non-nil (a stream-restore piping a dump into the restoring process) it is attached to the command's standard input and copied in a goroutine, then the write half is closed so the command sees EOF. When spec.Stdin is nil this is a no-op and Exec behaves exactly as it always has.

func (PodmanRuntime) Inspect

func (e PodmanRuntime) Inspect(ctx context.Context, id string) (Container, error)

Inspect returns a single container by ID or name.

func (PodmanRuntime) Kill added in v0.2.0

func (e PodmanRuntime) Kill(ctx context.Context, id string, signal string) error

Kill sends a signal to a running container, e.g. "SIGHUP" to prompt a collector to reload its configuration.

func (PodmanRuntime) List

func (e PodmanRuntime) List(ctx context.Context) ([]Container, error)

List returns every container the runtime knows about, running or not.

func (PodmanRuntime) ListNetworks added in v0.3.0

func (e PodmanRuntime) ListNetworks(ctx context.Context) ([]Network, error)

ListNetworks returns every network the runtime knows about, with its subnet CIDRs and internal flag. It satisfies NetworkInspector for both DockerRuntime and PodmanRuntime, which embed engineClient.

func (PodmanRuntime) PullImage added in v0.4.0

func (e PodmanRuntime) PullImage(ctx context.Context, ref string) error

PullImage pulls ref if it is not already present locally.

func (PodmanRuntime) RemoveContainer added in v0.4.0

func (e PodmanRuntime) RemoveContainer(ctx context.Context, id string, force bool) error

RemoveContainer removes a container by id or name along with its anonymous volumes. force removes a running container instead of failing.

func (PodmanRuntime) RemoveNetwork added in v0.4.0

func (e PodmanRuntime) RemoveNetwork(ctx context.Context, id string) error

RemoveNetwork removes a network by id or name.

func (PodmanRuntime) RemoveVolume added in v0.4.0

func (e PodmanRuntime) RemoveVolume(ctx context.Context, name string) error

RemoveVolume removes a named volume. It does not force: a volume still held by a container is removed only after the container is gone.

func (PodmanRuntime) Restart added in v0.2.0

func (e PodmanRuntime) Restart(ctx context.Context, id string) error

Restart restarts a container, using the runtime's default stop timeout.

func (PodmanRuntime) Start

func (e PodmanRuntime) Start(ctx context.Context, id string) error

Start starts a stopped container.

func (PodmanRuntime) Stop

func (e PodmanRuntime) Stop(ctx context.Context, id string, timeoutSeconds int) error

Stop stops a running container, waiting up to timeoutSeconds before a kill.

func (PodmanRuntime) Watch

func (e PodmanRuntime) Watch(ctx context.Context) (<-chan Event, <-chan error)

Watch streams lifecycle events until ctx is cancelled. The error channel carries a terminal error and is then closed alongside the event channel.

type Provisioner added in v0.4.0

type Provisioner interface {
	// PullImage pulls ref if the runtime does not already have it locally. It
	// is a no-op when the image is already present, so a caller may call it
	// unconditionally before CreateContainer.
	PullImage(ctx context.Context, ref string) error

	// CreateNetwork creates an isolated network and returns its id. The
	// network is always internal (no external routing, no gateway to the host
	// or the internet), so a container attached to it cannot reach production
	// services or the network at large. That isolation is the entire point of
	// the capability and is not configurable: a restored copy proven on such a
	// network is a DORA-style segregation fact the caller can assert directly
	// via NetworkInspector.ListNetworks (the created network reports
	// Internal == true).
	CreateNetwork(ctx context.Context, spec NetworkSpec) (id string, err error)

	// RemoveNetwork removes a network by id or name. It fails if a container
	// is still attached, so remove containers first.
	RemoveNetwork(ctx context.Context, id string) error

	// CreateVolume creates a fresh empty named volume and returns its name. A
	// verify restores into one of these, never a real service volume.
	CreateVolume(ctx context.Context, spec VolumeSpec) (name string, err error)

	// RemoveVolume removes a named volume. It fails if a container still holds
	// it, so remove the container first (or use RemoveContainer, which also
	// drops the container's anonymous volumes).
	RemoveVolume(ctx context.Context, name string) error

	// CreateContainer creates a container from spec.Image with the spec's
	// volume mounts, on the spec's network, with its env, labels, and optional
	// command or entrypoint override. It publishes no ports. The container is
	// created but not started unless spec.Start is set (starting a
	// separately-created container otherwise uses the base Runtime.Start). It
	// returns the container id even on a start error, so the caller can still
	// tear the container down.
	CreateContainer(ctx context.Context, spec ContainerSpec) (id string, err error)

	// RemoveContainer removes a container by id or name along with its
	// anonymous volumes. force removes a running container (equivalent to a
	// stop-then-remove) rather than failing.
	RemoveContainer(ctx context.Context, id string, force bool) error
}

Provisioner is an optional capability a Runtime implementation may satisfy in addition to Runtime, for standing up and tearing down throwaway objects: a fresh isolated network, empty volumes, and a container created from an image with those volumes mounted. It is the surface a consumer's verify flow drives to prove a restore in a sandbox that has no path to production.

Like NetworkInspector, it is kept as a separate interface rather than a set of new methods on Runtime, so adding it never breaks an existing consumer's mock or alternate Runtime implementation. A consumer that wants to provision type-asserts the value it got back from a constructor (or from Runtime) to Provisioner; a consumer that does not care is unaffected.

DockerRuntime and PodmanRuntime both satisfy Provisioner, implemented once on the shared engineClient (both embed it) against the Docker Engine API-compatible surface Podman also exposes.

Lifecycle ownership. Provisioner does NOT own cleanup: it hands back the id or name of each object it creates and the caller is responsible for tearing them down, in reverse order, with RemoveContainer, RemoveVolume, and RemoveNetwork (a container must go before the volumes and network it holds). To make orphan cleanup possible after a crash, every create spec carries a Labels map: a caller should stamp its own label on every object so a later sweep can find and remove anything a killed run left behind. Starting a created container uses the base Runtime.Start; a restore that pipes a dump into a container's stdin uses the base Runtime.Exec with ExecSpec.Stdin set.

type Runtime

type Runtime interface {
	// List returns every container the runtime knows about, running or not.
	List(ctx context.Context) ([]Container, error)

	// Inspect returns a single container by ID or name.
	Inspect(ctx context.Context, id string) (Container, error)

	// Watch streams lifecycle events until ctx is cancelled. The error channel
	// carries a terminal error and is then closed alongside the event channel.
	Watch(ctx context.Context) (<-chan Event, <-chan error)

	// Exec runs a command inside a running container and returns a handle whose
	// Stdout the caller reads (for stream backups it is piped straight into the
	// engine's stdin) before calling Wait for the exit code.
	Exec(ctx context.Context, id string, spec ExecSpec) (*ExecHandle, error)

	// Stop stops a running container, waiting up to timeoutSeconds before a kill.
	Stop(ctx context.Context, id string, timeoutSeconds int) error

	// Start starts a stopped container.
	Start(ctx context.Context, id string) error

	// Kill sends a signal to a running container, e.g. "SIGHUP" to prompt a
	// collector to reload its configuration.
	Kill(ctx context.Context, id string, signal string) error

	// Restart restarts a container, using the runtime's default stop timeout.
	Restart(ctx context.Context, id string) error

	// Close releases the underlying client.
	Close() error
}

Runtime is a container runtime a consumer can drive. Implementations must be safe for concurrent use by multiple goroutines.

type VolumeMount added in v0.4.0

type VolumeMount struct {
	// Volume is the named volume to mount, as returned by CreateVolume.
	Volume string
	// Destination is the container-side path to mount it at.
	Destination string
	// ReadOnly mounts the volume read-only when true.
	ReadOnly bool
}

VolumeMount attaches a named volume into a container at a path. It is the create-side counterpart to the read-side Mount type: verify mounts the fresh volume it restored into at the path the real service expects.

type VolumeSpec added in v0.4.0

type VolumeSpec struct {
	Name   string
	Labels map[string]string
}

VolumeSpec describes a fresh empty named volume to create.

Directories

Path Synopsis
Package runtimetest provides Runtime, the canonical fake core.Runtime for the tagwright suite's wiring (Level 2) tests.
Package runtimetest provides Runtime, the canonical fake core.Runtime for the tagwright suite's wiring (Level 2) tests.

Jump to

Keyboard shortcuts

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