Documentation
¶
Index ¶
- Constants
- Variables
- type Client
- type Container
- type ContainerStats
- type DiskUsage
- type ExecResult
- type HostInfo
- type LogLine
- type LogOptions
- type Pod
- type PortMapping
- type PruneReport
- type Real
- func (r *Real) BuildCachePrune(ctx context.Context, id string) (PruneReport, error)
- func (r *Real) ContainerExec(ctx context.Context, id, container string, cmd []string) (ExecResult, error)
- func (r *Real) ContainerLogs(ctx context.Context, id, container string, opts LogOptions) (<-chan LogLine, error)
- func (r *Real) ContainerPrune(ctx context.Context, id string) (PruneReport, error)
- func (r *Real) ContainerStats(ctx context.Context, id string) ([]ContainerStats, error)
- func (r *Real) CopyToContainer(ctx context.Context, id, container, destDir, name string, content []byte) error
- func (r *Real) HostInfo(ctx context.Context, id string) (HostInfo, error)
- func (r *Real) ImagePrune(ctx context.Context, id string, all bool) (PruneReport, error)
- func (r *Real) ImagePull(ctx context.Context, id, ref string) error
- func (r *Real) Knows(id string) bool
- func (r *Real) NetworkEnsure(ctx context.Context, id, name string) error
- func (r *Real) Ping(ctx context.Context, id string) error
- func (r *Real) PlayKube(ctx context.Context, id, raw string, replace bool, networks ...string) error
- func (r *Real) PodInspect(ctx context.Context, id, name string) (Pod, error)
- func (r *Real) PodList(ctx context.Context, id string, filters map[string]string) ([]Pod, error)
- func (r *Real) PodRemove(ctx context.Context, id, name string, force bool) error
- func (r *Real) PodRestart(ctx context.Context, id, name string) error
- func (r *Real) PodStart(ctx context.Context, id, name string) error
- func (r *Real) PodStop(ctx context.Context, id, name string) error
- func (r *Real) Preflight(ctx context.Context) error
- func (r *Real) SecretCreate(ctx context.Context, id, name string, value []byte) error
- func (r *Real) SecretInspect(ctx context.Context, id, name string) (Secret, error)
- func (r *Real) SecretList(ctx context.Context, id string) ([]Secret, error)
- func (r *Real) SecretRemove(ctx context.Context, id, name string) error
- func (r *Real) SetHosts(hosts []config.Host)
- func (r *Real) URIFor(id string) (string, error)
- func (r *Real) UsedHostPorts(ctx context.Context, id string) ([]PortMapping, error)
- func (r *Real) Version(ctx context.Context, id string) (string, error)
- func (r *Real) VolumeCreate(ctx context.Context, id, name string) error
- func (r *Real) VolumeExport(ctx context.Context, id, name string) (io.ReadCloser, error)
- func (r *Real) VolumeImport(ctx context.Context, id, name string, src io.Reader) error
- func (r *Real) VolumeInspect(ctx context.Context, id, name string) (Volume, error)
- func (r *Real) VolumePrune(ctx context.Context, id string, filters map[string][]string) (PruneReport, error)
- func (r *Real) VolumeRemove(ctx context.Context, id, name string, force bool) error
- func (r *Real) VolumeUsage(ctx context.Context, id string) (map[string]int64, error)
- func (r *Real) WaitForPodCompletion(ctx context.Context, id, podName string, timeout time.Duration) (int, error)
- type Secret
- type Volume
Constants ¶
const MinPodmanVersion = "5.6.0"
MinPodmanVersion is the floor for managed hosts. Cold-copy migrate streams volumes through libpod's GET /volumes/{name}/export and volumes.Import, which first shipped in podman 5.6.0 — on older hosts the export 404s mid-migration. The preflight turns that into a clear setup error (#85).
Variables ¶
var ErrHostVersionUnsupported = errors.New("host podman version unsupported")
ErrHostVersionUnsupported marks a host whose podman is below MinPodmanVersion (or whose version cannot be parsed, which fails closed).
var ErrNotFound = errors.New("podman: not found")
ErrNotFound is returned when a pod, container, secret, or volume isn't present.
var ErrWaitTimeout = errors.New("podman: timed out waiting for pod completion")
ErrWaitTimeout is returned by WaitForPodCompletion when timeout elapses before every container in the pod has exited. It is distinct from a successful wait (which always returns a nil error, even for a non-zero exit code) so callers cannot mistake "we gave up waiting" for "it ran and finished".
Functions ¶
This section is empty.
Types ¶
type Client ¶
type Client interface {
// Pods
PlayKube(ctx context.Context, hostID, yaml string, replace bool, networks ...string) error
PodInspect(ctx context.Context, hostID, name string) (Pod, error)
// WaitForPodCompletion polls every container in the named pod until each
// has exited or timeout elapses. Returns the first non-zero exit code
// found (in container order), else 0 if every container exited 0. A
// timeout returns a non-nil error (ErrWaitTimeout) — never a zero exit
// code, which would misread as success.
WaitForPodCompletion(ctx context.Context, hostID, podName string, timeout time.Duration) (exitCode int, err error)
PodList(ctx context.Context, hostID string, labelFilters map[string]string) ([]Pod, error)
PodStart(ctx context.Context, hostID, name string) error
PodStop(ctx context.Context, hostID, name string) error
PodRestart(ctx context.Context, hostID, name string) error
PodRemove(ctx context.Context, hostID, name string, force bool) error
// Secrets
SecretCreate(ctx context.Context, hostID, name string, value []byte) error
SecretList(ctx context.Context, hostID string) ([]Secret, error)
SecretInspect(ctx context.Context, hostID, name string) (Secret, error)
SecretRemove(ctx context.Context, hostID, name string) error
// Volumes
VolumeInspect(ctx context.Context, hostID, name string) (Volume, error)
VolumeRemove(ctx context.Context, hostID, name string, force bool) error
// VolumeExport streams the named volume's contents from host as an
// uncompressed tar. The caller must Close the returned reader.
VolumeExport(ctx context.Context, hostID, name string) (io.ReadCloser, error)
// VolumeImport unpacks an uncompressed tar (as produced by VolumeExport)
// into the named volume on host. The volume must already exist.
VolumeImport(ctx context.Context, hostID, name string, r io.Reader) error
// VolumeCreate creates an empty named volume on host. Creating a volume that
// already exists is a no-op (no error).
VolumeCreate(ctx context.Context, hostID, name string) error
// Stats
// ContainerStats returns a single non-streaming resource sample for every
// container on the host. It is one call per host; the caller attributes
// samples to instances by container name.
ContainerStats(ctx context.Context, hostID string) ([]ContainerStats, error)
// VolumeUsage returns each volume's on-disk size in bytes, keyed by volume
// name, from one `system df` call. Podman walks images, containers and
// volumes to answer this, so it can take minutes on a large store — callers
// must run it on a slow cadence with its own timeout, never on a hot path.
VolumeUsage(ctx context.Context, hostID string) (map[string]int64, error)
// Networks
// NetworkEnsure creates the named network if absent; creating one that
// already exists is a no-op (no error).
NetworkEnsure(ctx context.Context, hostID, name string) error
// Exec
// ContainerExec runs cmd in the named running container and returns its
// exit code and combined stdout+stderr. A non-zero exit code is NOT an
// error; only a transport/podman failure returns a non-nil error.
ContainerExec(ctx context.Context, hostID, container string, cmd []string) (ExecResult, error)
// CopyToContainer writes content as a single file `name` into directory
// `destDir` inside the running container (e.g. destDir="/etc/caddy",
// name="Caddyfile"). destDir must already exist in the container.
CopyToContainer(ctx context.Context, hostID, container, destDir, name string, content []byte) error
// Logs
ContainerLogs(ctx context.Context, hostID, container string, opts LogOptions) (<-chan LogLine, error)
// Images
ImagePull(ctx context.Context, hostID, ref string) error
// Prune
// ImagePrune removes unused images. all=false removes only dangling layers;
// all=true also removes tagged images not used by any container.
ImagePrune(ctx context.Context, hostID string, all bool) (PruneReport, error)
// ContainerPrune removes stopped (exited) containers.
ContainerPrune(ctx context.Context, hostID string) (PruneReport, error)
// BuildCachePrune removes dangling build cache.
BuildCachePrune(ctx context.Context, hostID string) (PruneReport, error)
// VolumePrune removes unused (unattached) volumes. filters are libpod volume
// prune filters (e.g. {"label!": {"podman-api.protect=true"}}) so callers can
// protect volumes; never removes in-use volumes.
VolumePrune(ctx context.Context, hostID string, filters map[string][]string) (PruneReport, error)
// Health
Ping(ctx context.Context, hostID string) error
Version(ctx context.Context, hostID string) (string, error)
UsedHostPorts(ctx context.Context, hostID string) ([]PortMapping, error)
// Host
HostInfo(ctx context.Context, hostID string) (HostInfo, error)
// Knows reports whether hostID is a registered host this client can reach.
// The host set is updated at construction and whenever SetHosts is called
// (e.g. after a SIGHUP host-config reload).
Knows(hostID string) bool
// SetHosts replaces the client's host map at runtime. New hosts become
// connectable; removed hosts are dropped (and their cached connections
// cleaned up); changed connection params (addr/socket/ssh_key) invalidate
// the cached context so the next call reopens the connection.
SetHosts(hosts []config.Host)
}
Client is the contract every consumer of podman speaks. The real implementation calls libpod via SSH-tunnelled or unix-socket connections; tests use the in-memory fake under ./fake.
type Container ¶
type Container struct {
ID string
Name string
// Image is InspectContainerData.ImageDigest, which is
// image.Digest().String(): a BARE digest with no repository, e.g.
// "sha256:42283567cae4…". It is NOT the "repo@sha256:…" shape — measured
// across 34 non-infra containers on engine-1 (podman 5.8.2, 2026-08-07),
// 34/34. When podman has no digest, enrichContainer falls back to
// InspectContainerData.Image, a bare 64-hex image ID that is not a manifest
// digest at all; a consumer that must resolve against a registry has to
// distinguish the two.
Image string
// ImageTag is InspectContainerData.ImageName, the full reference:
// "host/repo:tag" (18/34 in the same survey) or "host/repo@sha256:…" (16/34).
ImageTag string
Status string
// Health is the container's healthcheck status: "" when the container
// declares no healthcheck, otherwise "healthy" / "unhealthy" / "starting".
Health string
// HealthStartPeriod and HealthInterval are the container's *declared*
// healthcheck timings, both zero when it declares no healthcheck. They are
// the grace the container was promised, so readiness waits can bound
// themselves by the spec they are verifying rather than by a fixed constant
// that may be shorter than the first check can possibly run (#196).
HealthStartPeriod time.Duration
HealthInterval time.Duration
StartedAt time.Time
RestartCount int
Ports []PortMapping
Env map[string]string
// ExitCode is the container's last exit code, as libpod reports it. It is
// meaningful only when Exited is true; a running container has ExitCode 0
// (never populated) alongside Exited false.
ExitCode int
// Exited reports whether the container has stopped running (libpod's
// State.Running == false). Distinguishes "never ran" / "still running"
// from "ran and produced ExitCode".
Exited bool
}
type ContainerStats ¶ added in v1.0.28
type ContainerStats struct {
Name string
CPUNano uint64 // cumulative CPU time, nanoseconds
MemUsageBytes uint64
MemLimitBytes uint64 // 0 when the container declares no limit
NetRxBytes uint64 // summed across interfaces
NetTxBytes uint64
BlockReadBytes uint64
BlockWriteBytes uint64
PIDs uint64
}
ContainerStats is a point-in-time resource sample for one container, mapped from libpod's define.ContainerStats.
The cumulative fields (CPUNano, the byte counters) reset to zero when the container is recreated, exactly as RestartCount does — a redeploy reads as a counter reset, which Prometheus rate()/increase() handle.
Podman's own CPU/AvgCPU/MemPerc percentages are deliberately NOT carried: for a non-streaming call they are averaged against container start time, so a container busy at boot and idle since reads as permanently hot. Export the counters and let PromQL derive rates.
type DiskUsage ¶
type DiskUsage struct {
Total int64 // bytes (graphroot partition size)
Used int64 // bytes
Free int64 // bytes (Total-Used)
Reclaimable int64 // bytes reclaimable from dangling volumes (system df)
}
DiskUsage describes the host's container-storage partition (graphroot).
type ExecResult ¶
ExecResult is the outcome of ContainerExec.
type HostInfo ¶
type HostInfo struct {
CPUs int // logical CPUs
MemTotal int64 // bytes
MemFree int64 // bytes
MemUsedPct float64 // derived: (MemTotal-MemFree)/MemTotal*100, 0 if MemTotal==0
CPUPct *float64 // average CPU utilization since boot (user+system %); nil when libpod omits CPUUtilization
LoadAvg *[3]float64 // 1/5/15-min; nil when unavailable
Disk DiskUsage
}
HostInfo is a point-in-time resource snapshot for a host, sourced from libpod `info` + `system df` plus a best-effort read of /proc/loadavg. Pointer fields are nil when the underlying source does not report them, so an absent metric serializes as null rather than a misleading zero.
type LogOptions ¶
type LogOptions struct {
Tail int // 0 = all
Since string // RFC3339 or duration like "5m"; "" = beginning
Follow bool
}
LogOptions are the knobs for ContainerLogs.
type Pod ¶
type Pod struct {
ID string
Name string
Status string // "Running", "Created", "Exited", etc.
Created time.Time
Containers []Container
Labels map[string]string
// InfraID is the ID of the pod's infra container, empty when the pod has
// none. It is the only reliable way to tell an infra container from an app
// container: names collide (`podman kube play` names containers
// <pod>-<containerName>) and an infra container reports no image at all,
// which is indistinguishable from an app container whose inspect failed.
InfraID string
}
Pod is the libpod-shaped pod summary the rest of the API consumes.
type PortMapping ¶
type PruneReport ¶
PruneReport summarizes one prune operation: the ids/names removed and the bytes reclaimed (sum of per-item sizes).
type Real ¶
type Real struct {
// contains filtered or unexported fields
}
Real is the production podman.Client implementation backed by libpod over SSH (production) or a local unix socket (dev).
Per-host context.Contexts are created lazily and cached. The bindings library stores the underlying connection on the context, so callers must pass the cached context (returned by ctxFor) to every libpod call.
Uses github.com/containers/podman/v5 v5.8.2. bindings.NewConnection signature: func(ctx context.Context, uri string) (context.Context, error)
func NewReal ¶
NewReal validates host configs and registers them. Connections are not opened here; first use opens them.
func (*Real) BuildCachePrune ¶
func (*Real) ContainerExec ¶
func (*Real) ContainerLogs ¶
func (r *Real) ContainerLogs(ctx context.Context, id, container string, opts LogOptions) (<-chan LogLine, error)
ContainerLogs streams log lines from a container. Cancellation propagates bidirectionally: if the caller's ctx is cancelled the underlying containers.Logs call is cancelled (via mergedCtx), and if the producer finishes naturally the bridge goroutine exits cleanly.
The connection context (c) is long-lived and must not be cancelled per request; mergedCtx derives from c but can be independently cancelled so the streaming call is torn down without killing the cached connection.
func (*Real) ContainerPrune ¶
func (*Real) ContainerStats ¶ added in v1.0.28
ContainerStats issues one non-streaming stats call and returns the first (and only) report. Passing nil containers asks podman for every container on the host, so a fleet sample costs one round trip per host.
All is deliberately left unset. With an empty name list podman's abi selects GetRunningContainers when All is false and GetAllContainers when it is true — but computeStats then skips every non-running container regardless, swallowing ErrCtrStopped/ErrCtrStateInvalid/ErrNoCgroups because the query was for all. So All:true yields no extra samples; it only enumerates and lock-touches every exited container on the host, once per tick.
func (*Real) CopyToContainer ¶
func (*Real) HostInfo ¶
HostInfo returns a point-in-time resource snapshot for a host. CPU/mem/disk come from libpod `info`; reclaimable from `system df`; loadavg is a best-effort read of /proc/loadavg (the one metric libpod does not expose). Any sub-metric that cannot be obtained is left at its zero/nil value rather than failing the whole call; only a failed `info` call (host unreachable) returns an error.
func (*Real) ImagePrune ¶
func (*Real) NetworkEnsure ¶
NetworkEnsure creates the named network if absent, with aardvark DNS enabled.
DNS must be on: the `podman network create` CLI defaults it true, but the REST API does not, and ingress backend routing resolves pods by name on this network — without DNS the proxy can't reach the backend (502).
An existing network is only accepted if its DNS is already on. A network left by a pre-DNS build has it off, and DNS can't be flipped on an existing network via the API, so we fail with the one-time fix instead of silently keeping it disabled (which IgnoreIfExists would do).
func (*Real) PodInspect ¶
func (*Real) Preflight ¶
Preflight enforces MinPodmanVersion at boot. ALL reachable hosts are checked and any below the floor are collected; the returned error aggregates every offender via errors.Join so operators see every problem in a single boot attempt (main treats it as fatal — the daemon refuses to start). An unreachable or slow host is logged and left unverified; the check re-runs on its first successful connect (opCtxFor), so a down-at-boot old host still cannot sneak in. See #85.
func (*Real) SecretCreate ¶
func (*Real) SecretInspect ¶
func (*Real) SecretList ¶
func (*Real) SetHosts ¶
SetHosts replaces the client's host map at runtime, diff-invalidating cached connections so that:
- newly added hosts become connectable on first use (lazy ctxFor);
- removed hosts are dropped (cached context garbage-collected);
- hosts whose addr/socket/ssh_key changed get their cached connection and verified flag cleared so the next call reopens with the new params;
- unchanged hosts keep their live cached connection.
func (*Real) UsedHostPorts ¶
func (*Real) VolumeCreate ¶
VolumeCreate creates an empty named volume. An already-existing name is treated as success so migrate's create-then-copy step is idempotent on retry.
func (*Real) VolumeExport ¶
VolumeExport streams a volume's contents as an uncompressed tar. The returned reader is the live HTTP response body; the caller must Close it. We issue the REST request directly rather than using the high-level volumes.Export binding because that binding copies into an io.Writer, whereas our contract must hand back a live io.ReadCloser for pipe streaming.
func (*Real) VolumeImport ¶
VolumeImport unpacks an uncompressed tar into an existing volume on the host.
func (*Real) VolumeInspect ¶
func (*Real) VolumePrune ¶
func (*Real) VolumeRemove ¶
func (*Real) VolumeUsage ¶ added in v1.0.28
VolumeUsage returns each volume's on-disk size in bytes, keyed by volume name, via one `system df` call.
func (*Real) WaitForPodCompletion ¶ added in v1.0.35
func (r *Real) WaitForPodCompletion(ctx context.Context, id, podName string, timeout time.Duration) (int, error)
WaitForPodCompletion polls the named pod's containers until every one has exited or timeout elapses. It returns the first non-zero exit code found (in container order), else 0. Timing out returns ErrWaitTimeout, never a zero exit code — a caller must not be able to mistake "gave up waiting" for "ran and exited 0".
The caller's timeout, not the fixed opCtxFor callTimeout, bounds the wait: opCtxFor's 10-minute cap is meant for a single libpod call, but a blob GC over a large registry can legitimately run far longer. This method builds its own context off the verified connection instead of going through opCtxFor, so a 30-minute caller timeout is honoured rather than silently truncated to 10 minutes.