dockerexec

package
v0.14.2 Latest Latest
Warning

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

Go to latest
Published: Aug 20, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

Documentation

Overview

Package dockerexec is the write-plane exec wrapper: it shells out to `docker compose` with STATIC ARGV only — never a shell, never string interpolation, always a `--` terminator before service names (plan §3, §5.6). It enforces the global one-docker-child semaphore and the ≥1 GB write-plane gate, and reaps the whole process group on context cancellation.

Index

Constants

This section is empty.

Variables

View Source
var ErrBusy = errors.New("dockerexec: another docker operation is in progress")

ErrBusy is returned when the one-docker-child semaphore could not be acquired.

View Source
var ErrWritePlaneDisabled = errors.New("dockerexec: write plane disabled (host below the 1 GB resource gate)")

ErrWritePlaneDisabled is returned when the host is below the §0 resource gate.

Functions

func WritePlaneGate

func WritePlaneGate(memTotal uint64) (bool, string)

WritePlaneGate decides whether the write plane is armed from the host's total RAM. memTotal==0 means unknown (non-Linux dev) → armed, with a caveat note.

Types

type Job

type Job struct {
	Project     string
	Dir         string
	ConfigFiles []string
	EnvFile     string   // optional 0600 --env-file rendered from the env store
	Action      []string // e.g. ["up","-d","--force-recreate"]
	Service     string   // optional; appended after a "--" terminator
}

Job is one `docker compose` invocation. Project/Dir/ConfigFiles come from the app's compose labels; they are passed as discrete argv elements (no shell), so they cannot inject commands.

type Runner

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

Runner executes Jobs under the gate + semaphore.

func NewRunner

func NewRunner(sem *Semaphore, writeAllowed bool, writeReason string) *Runner

NewRunner builds a Runner. writeAllowed/writeReason come from the §0 gate.

func (*Runner) PruneBuildCache added in v0.4.16

func (r *Runner) PruneBuildCache(ctx context.Context, keep string, onLine func(string)) error

PruneBuildCache reclaims BuildKit build cache, keeping at most `keep` of the most-recently-used cache (LRU eviction): `docker builder prune -a -f --keep-storage <keep>`. It runs under the §0 write gate + the one-docker-child semaphore, exactly like a deploy. `keep` is a validated size (e.g. "5GB") passed as a discrete argv element (no shell). Best-effort by design — callers log the outcome and never fail a deploy on error.

func (*Runner) PruneBuildCacheHeld added in v0.6.0

func (r *Runner) PruneBuildCacheHeld(ctx context.Context, keep string, onLine func(string)) error

PruneBuildCacheHeld is PruneBuildCache for a caller that ALREADY HOLDS the one-docker-child semaphore (the disk-pressure auto-GC, which holds the slot across the image + cache prune — calling the non-Held PruneBuildCache there would self-deadlock re-acquiring the one slot).

func (*Runner) PruneImages added in v0.6.0

func (r *Runner) PruneImages(ctx context.Context, onLine func(string)) error

PruneImages reclaims DANGLING (untagged, unreferenced) images — the superseded builds that pile up as apps redeploy and are the usual disk hog. `docker image prune -f` NEVER removes an image referenced by a container (running OR stopped) or a tagged image, so it frees only genuine garbage; and since a Mooring rollback rebuilds its image, this can't break rollback. Runs under the §0 write gate + the one-docker-child semaphore. Output (incl. "Total reclaimed space") streams to onLine.

func (*Runner) PruneImagesHeld added in v0.6.0

func (r *Runner) PruneImagesHeld(ctx context.Context, onLine func(string)) error

PruneImagesHeld is PruneImages for a caller that ALREADY HOLDS the one-docker-child semaphore (the disk-pressure auto-GC, which TryAcquires so it never queues a docker child).

func (*Runner) ReapOneOffHeld added in v0.6.0

func (r *Runner) ReapOneOffHeld(ctx context.Context, project string)

ReapOneOffHeld force-removes any orphaned ONE-SHOT (`compose run`) containers of a project — the leftovers a KILLED `run --rm` CLI (timeout/shutdown) couldn't remove itself. Best-effort: all errors are ignored. The CALLER must hold the one-docker-child semaphore (the cron scheduler, which runs one task at a time, so no live one-shot is being reaped).

func (*Runner) RemoveContainers added in v0.9.0

func (r *Runner) RemoveContainers(ctx context.Context, ids []string, onLine func(string)) error

RemoveContainers force-removes containers by id (`docker rm -f <id>...`) — write-plane, §0 resource-gated, acquiring the one-docker-child semaphore. It does NO scoping of its own: the CALLER must pass only ids it has already verified belong to the intended project (the web-layer conflict reconcile resolves each id's compose project/service label over the READ plane first, so a foreign or system container is never passed here). Returns the rm exit error (if any).

func (*Runner) RemoveContainersHeld added in v0.9.0

func (r *Runner) RemoveContainersHeld(ctx context.Context, ids []string, onLine func(string)) error

RemoveContainersHeld is RemoveContainers for a caller that ALREADY HOLDS the one-docker-child semaphore (e.g. the self-heal remediation path, which runs its `up` via RunHeld). It must not be called without holding the semaphore. Same no-scoping contract as RemoveContainers.

func (*Runner) Run

func (r *Runner) Run(ctx context.Context, job Job, onLine func(string)) error

Run executes the job, invoking onLine for each (truncated) output line. It acquires the semaphore (blocking on ctx), and on ctx cancellation kills the whole process group and reaps it. Returns the command error (incl. non-zero exit) or a gate/semaphore error.

func (*Runner) RunHeld

func (r *Runner) RunHeld(ctx context.Context, job Job, onLine func(string)) error

RunHeld is Run for a caller that ALREADY HOLDS the one-docker-child semaphore (the self-healing supervisor, which acquires it non-blocking via its safety gate so it never queues a docker child). It must not be called without holding the semaphore.

func (*Runner) RunInternal

func (r *Runner) RunInternal(ctx context.Context, job Job, onLine func(string)) error

RunInternal runs a Mooring-OWNED infrastructure job (bringing up the embedded read-only socket-proxy) REGARDLESS of the §0 write-plane resource gate — the read plane must come up even on a sub-1 GB box. It is NOT for app workloads: the caller passes a fixed, embedded, Mooring-authored compose (never operator input), so it bypasses the RAM gate while keeping the static-argv discipline, the one-docker-child semaphore, and process-group reaping. It acquires the semaphore (blocking on ctx) like Run.

func (*Runner) RunStream added in v0.6.0

func (r *Runner) RunStream(ctx context.Context, argv []string, stdout io.Writer, onErrLine func(string)) error

RunStream execs `docker <argv...>` and streams its RAW stdout bytes to `stdout` (an io.Writer — e.g. the tar→gzip→encrypt backup pipeline), while stderr is line-truncated to onErrLine for logging. Unlike Run, stdout is NOT line-buffered or merged with stderr, so a binary dump/tar stream passes through byte-for-byte. Static argv only (Mooring-authored, never operator input); it runs under the §0 write gate + the one-docker-child semaphore and reaps the process group on ctx cancel. Used for backup SIDECARS (`docker run --rm … pg_dump` / `… tar`) — a fresh one-shot container, never an exec into a running one.

func (*Runner) RunStreamHeld added in v0.6.0

func (r *Runner) RunStreamHeld(ctx context.Context, argv []string, stdout io.Writer, onErrLine func(string)) error

RunStreamHeld is RunStream for a caller that ALREADY HOLDS the one-docker-child semaphore (the backup scheduler, which TryAcquires so it never queues a docker child). It must not be called without holding the semaphore.

func (*Runner) RunStreamStdin added in v0.6.0

func (r *Runner) RunStreamStdin(ctx context.Context, argv []string, stdin io.Reader, onLine func(string)) error

RunStreamStdin execs `docker <argv...>` feeding `stdin` to the child's STDIN (e.g. a decrypted+gunzipped tar stream piped into a `docker run -i … tar -x` restore sidecar), while stdout+stderr are line-truncated to onLine. Static argv only (Mooring-authored); runs under the §0 write gate + the one-docker-child semaphore and reaps the process group on ctx cancel. The counterpart of RunStream for the RESTORE direction.

func (*Runner) RunStreamStdinHeld added in v0.6.0

func (r *Runner) RunStreamStdinHeld(ctx context.Context, argv []string, stdin io.Reader, onLine func(string)) error

RunStreamStdinHeld is RunStreamStdin for a caller that ALREADY HOLDS the semaphore.

func (*Runner) WriteAllowed

func (r *Runner) WriteAllowed() (bool, string)

WriteAllowed reports whether the write plane is armed, and why not if not.

type Semaphore

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

Semaphore caps concurrent `docker` children at 1 across the whole process (poller stats go through the proxy and don't count; only exec children do). Remediation/scale-up use TryAcquire (never queue — queuing children IS the OOM vector, plan §4).

func NewSemaphore

func NewSemaphore() *Semaphore

NewSemaphore returns the global one-docker-child semaphore.

func (*Semaphore) Acquire

func (s *Semaphore) Acquire(ctx context.Context) error

Acquire blocks until the slot is free or ctx is done.

func (*Semaphore) Release

func (s *Semaphore) Release()

Release frees the slot.

func (*Semaphore) TryAcquire

func (s *Semaphore) TryAcquire() bool

TryAcquire grabs the slot without blocking; false means held.

Jump to

Keyboard shortcuts

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