Documentation
¶
Index ¶
- Constants
- Variables
- func CheckPort(port int) (bool, error)
- func ComposeConfigHashes(ctx context.Context, files, envFiles []string, projectDir string) (map[string]string, error)
- func ComposeServiceNames(composeFilePaths []string) (map[string]struct{}, error)
- func ComposeTooOldMessage(v string) string
- func ComposeVersion(ctx context.Context) (string, error)
- func ContainerNetworks(ctx context.Context, name string) ([]string, error)
- func ContainerVolume(ctx context.Context, container, dest string) (string, error)
- func DeclaredHostPorts(ctx context.Context, workdir string, envFiles []string, composeFiles ...string) ([]int, map[int]string, error)
- func DefaultCommand(service string) []string
- func DefaultPortServiceNames() map[int]string
- func Diagnose(message string) string
- func EnsureComposeImages(ctx context.Context, workdir string, c *Compose, refs []LockedImage) (bool, error)
- func EnsureImage(ctx context.Context, ref LockedImage) (string, error)
- func Exec(ctx context.Context, container string, cmd []string, opts ExecOptions) error
- func ExecCapture(ctx context.Context, container string, cmd []string) (stdout, stderr string, err error)
- func ExecStdin(ctx context.Context, container string, cmd []string, stdin io.Reader) (stdout, stderr string, err error)
- func FindServiceContainer(ctx context.Context, m ServiceMatch) (string, error)
- func GetContainerLogs(ctx context.Context, name string, tail int) (string, error)
- func GetHealthStatus(ctx context.Context, name string) (string, error)
- func HealthGate(ctx context.Context, spec ServiceSpec, states StateSource, clock Clock) error
- func HealthTimeout(name string, interval, timeout, startPeriod, retries json.RawMessage) (time.Duration, error)
- func ImageIndexRaw(ctx context.Context, ref string) ([]byte, error)
- func ImageRepoDigests(ctx context.Context, ref string) ([]string, error)
- func InspectState(ctx context.Context, name string) (string, error)
- func LocalRepoDigest(ctx context.Context, ref string) string
- func ManifestInspect(ctx context.Context, ref string, verbose bool) ([]byte, error)
- func NetworkConnect(ctx context.Context, network, container string) error
- func NetworkDisconnect(ctx context.Context, network, container string) error
- func NetworkExists(ctx context.Context, name string) (bool, error)
- func OwnedHostPorts(ctx context.Context, workdir string, envFiles []string, composeFiles ...string) (map[int]bool, error)
- func ParseComposeVersion(s string) (major, minor, patch int, ok bool)
- func ProjectEnvFiles(workdir string) []string
- func RegisterPreDownHook(h PreDownHook) (unregister func())
- func Regressed(before, after []ContainerState) error
- func RemoveContainer(ctx context.Context, name string) error
- func RemoveOrphans(ctx context.Context, orphans []OrphanContainer) []error
- func RestartContainer(ctx context.Context, name string) error
- func RunOneShot(ctx context.Context, spec RunSpec) (stdout, stderr string, err error)
- func RunPostStartCleanup(ctx context.Context, projectName string) error
- func RunPreDownHooks(ctx context.Context, workdir string)
- func RunPreStartCleanup(ctx context.Context, projectName string) error
- func ServerVersion(ctx context.Context) (string, error)
- func SetExecHook(fn func(container string, cmd []string)) (restore func())
- func StartContainer(ctx context.Context, name string) error
- func StatefulServices(files []string) (map[string]bool, error)
- func StopContainer(ctx context.Context, name string) error
- func VolumeCreate(ctx context.Context, name string, labels map[string]string) error
- func VolumeExists(ctx context.Context, name string) (bool, error)
- func VolumeLabels(ctx context.Context, name string) (labels map[string]string, exists bool, err error)
- func VolumeRemove(ctx context.Context, name string) error
- type Clock
- type Compose
- func (c *Compose) ComposeConfig(ctx context.Context, workdir string) error
- func (c *Compose) ComposeDown(ctx context.Context, workdir string, opts DownOptions) error
- func (c *Compose) ComposePs(ctx context.Context, workdir string) ([]ContainerInfo, error)
- func (c *Compose) ComposePull(ctx context.Context, workdir string) error
- func (c *Compose) ComposePullDiagnosed(ctx context.Context, workdir string) error
- func (c *Compose) ComposePullService(ctx context.Context, workdir, service string) error
- func (c *Compose) ComposeRestart(ctx context.Context, workdir string, services ...string) error
- func (c *Compose) ComposeScale(ctx context.Context, workdir, service string, replicas int) error
- func (c *Compose) ComposeServiceNames(ctx context.Context, workdir string) ([]string, error)
- func (c *Compose) ComposeServiceStates(ctx context.Context, workdir, service string) ([]ContainerState, error)
- func (c *Compose) ComposeStop(ctx context.Context, workdir string, services ...string) error
- func (c *Compose) ComposeUp(ctx context.Context, workdir string, services ...string) error
- func (c *Compose) ComposeUpBuild(ctx context.Context, workdir string, services ...string) error
- func (c *Compose) ComposeUpNoDeps(ctx context.Context, workdir string, services ...string) error
- func (c *Compose) FreshStates(ctx context.Context, workdir, service string, baseline map[string]string) ([]ContainerState, error)
- func (c *Compose) OutputProject(ctx context.Context, workdir string, p ProjectRun, args ...string) ([]byte, error)
- func (c *Compose) Run(ctx context.Context, workdir string, args ...string) error
- func (c *Compose) RunProject(ctx context.Context, workdir string, p ProjectRun, args ...string) error
- func (c *Compose) StartMarks(ctx context.Context, workdir, service string) (map[string]string, error)
- type ComposeVerdict
- type Container
- type ContainerInfo
- type ContainerState
- type DownOptions
- type ExecOptions
- type Executor
- type IndexInfo
- type LockedImage
- type Mount
- type OrphanContainer
- type PortConflict
- type PreDownHook
- type ProjectRun
- type RunSpec
- type RunningService
- type ServiceMatch
- type ServiceSpec
- type StateSource
- type SystemClock
Constants ¶
const ( HealthyTimeout = 60 * time.Second RunningTimeout = 30 * time.Second )
Gate timeouts by service kind (D17): healthcheck or one-shot exit, else running (and still the same run one poll later).
const ImageOverrideFile = ".nself/state/image-overrides.yml"
const MaxHealthTimeout = 10 * time.Minute
MaxHealthTimeout caps ServiceSpec.HealthTimeout: a healthcheck declared with a huge retries or interval must not stall a deploy for hours.
const MinComposeVersion = "2.20.0"
MinComposeVersion is the oldest docker compose that reads every compose.env value nSelf writes.
const StateNotRestarted = "not-restarted"
StateNotRestarted marks an exited container that has not started since the baseline (see FreshStates).
Variables ¶
var ( ErrOneShotFailed = errors.New("one-shot service exited non-zero") ErrServiceCrashed = errors.New("service exited non-zero or is restarting") ErrGateTimeout = errors.New("service did not reach its ready state in time") ErrStateRead = errors.New("could not read container state") )
Gate failures. ErrOneShotFailed and ErrServiceCrashed map to E250 (the service is broken), ErrGateTimeout to E251 (too slow), ErrStateRead and ErrStateTimeout to no service code at all: docker could not answer, which says nothing about the service.
var ErrImageNotFound = errors.New("image not found locally")
ErrImageNotFound means the image is not present locally. Match with errors.Is.
var ErrNotIndex = errors.New("reference is not an image index")
ErrNotIndex means the reference resolves to a single manifest, not an index.
var ErrServiceContainerAmbiguous = errors.New("service container is ambiguous")
ErrServiceContainerAmbiguous is returned (wrapped, naming every candidate) when more than one running container matches a ServiceMatch. Match with errors.Is.
var ErrServiceContainerNotFound = errors.New("service container not found")
ErrServiceContainerNotFound is returned (wrapped) when no running container matches a ServiceMatch. Match with errors.Is.
var ErrStateTimeout = errors.New("docker gave no answer in time")
ErrStateTimeout is wrapped by a state read whose own bound fired. It is not context.DeadlineExceeded on purpose: callers outside the gate class it as a state-read failure, not as the user's interrupt.
var ReservedPorts = []int{
80, 443, 5432, 8080, 4000, 6379,
9000, 9001, 7700, 3021, 1025, 8025,
3008, 5000,
}
ReservedPorts lists ports used by the nSelf stack that must be checked for conflicts before starting services.
Functions ¶
func CheckPort ¶
CheckPort probes a single TCP port on localhost using DialTimeout. It returns true when the port is in use (connection succeeded) and false when the port is available (connection refused or timed out).
func ComposeConfigHashes ¶ added in v1.4.13
func ComposeConfigHashes(ctx context.Context, files, envFiles []string, projectDir string) (map[string]string, error)
ComposeConfigHashes runs `docker compose <-f ...> <--env-file ...> --project-directory <dir> config --hash '*'` and returns service -> hash.
Inputs: the -f files and --env-file files in the order `start` passes them, and the project directory relative paths resolve against. Outputs: one entry per service in the merged configuration. A failure to run compose, or a compose too old to know --hash, is an error: the caller decides whether that means "impact unknown".
func ComposeServiceNames ¶ added in v1.3.6
ComposeServiceNames reads every compose file in composeFilePaths (the base docker-compose.yml plus any plugin compose fragments — the same file set `docker compose -f ... -f ...` is invoked with, see build.ReadComposeManifest) and returns the union of all service names they define. This is the "desired state" DetectOrphans compares live containers against.
Inputs: composeFilePaths — absolute paths to YAML files; missing files are
skipped (best-effort — a plugin fragment can be removed from disk independently of the manifest that references it).
Outputs: the union of service keys across all readable files, and the
first hard parse error encountered (a file that exists but is not valid YAML is a real problem, not a missing-file gap).
Constraints: pure I/O + YAML parsing, no docker daemon access.
func ComposeTooOldMessage ¶ added in v1.4.15
ComposeTooOldMessage explains a too-old compose version and the fix.
func ComposeVersion ¶ added in v1.4.15
ComposeVersion returns the output of `docker compose version --short`, trimmed. It fails when docker or the compose plugin is missing.
func ContainerNetworks ¶ added in v1.4.15
ContainerNetworks returns the names of the networks the container is on, sorted.
func ContainerVolume ¶ added in v1.4.15
ContainerVolume returns the name of the named volume mounted at dest in the container, "" when nothing named is mounted there.
func DeclaredHostPorts ¶ added in v1.3.4
func DeclaredHostPorts(ctx context.Context, workdir string, envFiles []string, composeFiles ...string) ([]int, map[int]string, error)
DeclaredHostPorts returns the host ports the given compose files publish, together with a port -> service name map for error messages.
This exists because checking a fixed list of default ports is wrong for any stack that was configured off the defaults. A second nSelf project on one host must move its ports (POSTGRES_PORT=5433, HASURA_PORT=8181, ...); with a fixed list it is then blocked by the first project holding 5432 and 8080, ports it was never going to bind. That is what kept a staging stack down.
An error here means "could not determine", never "binds nothing". The caller must fall back to a conservative default list rather than check nothing. envFiles are passed as --env-file. Without them an installed plugin's docker-compose.plugin.yml cannot resolve ${DOCKER_NETWORK} and docker rejects the project as invalid, so this returns an error and the caller silently falls back to the default port list.
func DefaultCommand ¶
DefaultCommand returns the default shell or client command for a given service. Recognized services get their native CLI; everything else falls back to /bin/sh.
func DefaultPortServiceNames ¶ added in v1.3.4
DefaultPortServiceNames maps the ReservedPorts defaults to human names. Used only on the fallback path, when the published ports could not be read from compose; the normal path names services from the compose config itself, so a project on custom ports still gets "Port 8181 (hasura)" and not "unknown service".
func Diagnose ¶ added in v1.4.13
Diagnose turns Docker and registry errors into stable operator diagnoses.
func EnsureComposeImages ¶ added in v1.4.13
func EnsureComposeImages(ctx context.Context, workdir string, c *Compose, refs []LockedImage) (bool, error)
EnsureComposeImages checks every locked image used by the resolved stack on every start, including after a lock change on a previously started project. It writes or removes the mirror override and reports whether the file changed.
func EnsureImage ¶ added in v1.4.13
func EnsureImage(ctx context.Context, ref LockedImage) (string, error)
EnsureImage inspects the exact upstream digest, then pulls upstream and the same digest from its mirror in that order. It never tags a digest reference.
func Exec ¶
Exec runs a command inside a running container, attaching stdin/stdout/stderr for interactive sessions.
func ExecCapture ¶ added in v1.4.13
func ExecCapture(ctx context.Context, container string, cmd []string) (stdout, stderr string, err error)
ExecCapture runs `docker exec <container> <cmd...>` and returns the output.
func ExecStdin ¶ added in v1.4.13
func ExecStdin(ctx context.Context, container string, cmd []string, stdin io.Reader) (stdout, stderr string, err error)
ExecStdin runs `docker exec [-i] <container> <cmd...>` with stdin (nil: no stdin, no -i) and returns the captured output. A non-zero exit returns the exec error as is; stderr is returned alongside for the caller to quote.
func FindServiceContainer ¶ added in v1.4.13
func FindServiceContainer(ctx context.Context, m ServiceMatch) (string, error)
FindServiceContainer returns the name of the single running container that matches m. Zero matches return an error wrapping ErrServiceContainerNotFound; several return one wrapping ErrServiceContainerAmbiguous that names them. Docker being unreachable returns a different error, so callers can tell "not running" from "cannot tell".
func GetContainerLogs ¶
GetContainerLogs shells out to `docker logs --tail N` and returns the combined output.
func GetHealthStatus ¶
GetHealthStatus returns the health status of a container: "healthy", "unhealthy", "starting", "none" (no healthcheck configured), or "not_found".
func HealthGate ¶ added in v1.4.13
func HealthGate(ctx context.Context, spec ServiceSpec, states StateSource, clock Clock) error
HealthGate waits until spec's containers are ready for their kind (D17). Any kind fails at once on a container that exited non-zero or is restarting. Healthcheck declared -> every container healthy within HealthyTimeout (checked first, even with restart "no"). One-shot (restart "no", no healthcheck) -> every container exited 0 within HealthyTimeout. Otherwise -> every container running within RunningTimeout and seen running on two polls in a row with the same StartedAt (a crash loop passes one poll); a service with no restart line that exited 0 is done, as Docker treats it. A healthcheck service waits max(HealthyTimeout, spec.HealthTimeout). Each state read is bounded (see gateReadGrace); a read that gets no answer wraps ErrGateTimeout. A cancelled ctx returns ctx's error; a failed state read wraps ErrStateRead. A nil clock means SystemClock.
func HealthTimeout ¶ added in v1.4.14
func HealthTimeout(name string, interval, timeout, startPeriod, retries json.RawMessage) (time.Duration, error)
HealthTimeout is healthTimeout for callers that parse the resolved compose config themselves (internal/deploy's copy of this parser), so both compute the same wait.
func ImageIndexRaw ¶ added in v1.4.13
ImageIndexRaw returns the raw index JSON of ref via `docker buildx imagetools inspect --raw`.
func ImageRepoDigests ¶ added in v1.4.14
ImageRepoDigests returns the RepoDigests ("repo@sha256:<hex>") of the local image ref. An image without any (built locally, never pushed) returns an empty slice and no error.
func InspectState ¶ added in v1.4.15
InspectState returns the Docker state of the named container.
func LocalRepoDigest ¶ added in v1.4.14
LocalRepoDigest returns "sha256:<hex>" when the local image for ref has exactly one distinct digest recorded for ref's own repository, else "". A digest recorded for another repository (a retagged image) never counts.
func ManifestInspect ¶ added in v1.4.13
ManifestInspect runs `docker manifest inspect [--verbose] ref` and returns its stdout.
func NetworkConnect ¶ added in v1.4.15
NetworkConnect connects container to network. A container that is already on the network is left alone (no docker connect call).
func NetworkDisconnect ¶ added in v1.4.15
NetworkDisconnect disconnects container from network. A container that is not on the network, an absent network and an absent container are success.
func NetworkExists ¶ added in v1.4.15
NetworkExists reports whether a network with exactly this name exists.
func OwnedHostPorts ¶ added in v1.0.2
func OwnedHostPorts(ctx context.Context, workdir string, envFiles []string, composeFiles ...string) (map[int]bool, error)
OwnedHostPorts queries the running compose stack in workdir and returns the set of host-side port numbers currently bound by nself's own containers. These ports should not be reported as conflicts on startup — they are already owned by nself and will be reused by docker compose up.
envFiles are passed to docker compose as --env-file. They are REQUIRED once any plugin compose file is in play: an installed plugin's docker-compose.plugin.yml refers to ${DOCKER_NETWORK}, and without the env file that resolves to empty, so docker rejects the whole project with "service X refers to undefined network : invalid compose project" and this query fails.
If the query fails the error is RETURNED rather than swallowed. Reporting "nothing is owned" on a failure turns "I could not tell" into a confident wrong answer: every port the project itself already binds is then reported as a conflict, and `nself start` aborts against its own running stack.
func ParseComposeVersion ¶ added in v1.4.15
ParseComposeVersion reads "2.29.7", "v2.29.7", "2.29.7-desktop.1", "2.21.0+azure-1" or "2.20" (patch 0). It reports ok=false for anything else.
func ProjectEnvFiles ¶ added in v1.4.15
ProjectEnvFiles returns the --env-file list for the project in workdir by the rule of build.ComposeEnvFiles: the project .env (when present) then .nself/compose.env, or nil when compose.env is absent (compose then reads .env on its own). It serves packages that may not import internal/build; cmd/commands dev_test.go pins the two functions to each other.
func RegisterPreDownHook ¶ added in v1.4.15
func RegisterPreDownHook(h PreDownHook) (unregister func())
RegisterPreDownHook adds h to the hooks ComposeDown runs and returns the function that removes it again.
func Regressed ¶ added in v1.4.13
func Regressed(before, after []ContainerState) error
Regressed compares the containers a service's gate saw (before) with a later read (after). It returns ErrServiceCrashed, with the container named, when:
- an after container is restarting, exited non-zero, or is not in before (a replica replaced or added after the gate);
- a container that was running at its gate started again (a new StartedAt) or is now paused or dead;
- Docker reports any after container unhealthy, whatever the gate waited for, or a container that was healthy at its gate is no longer running and healthy;
- any before container, in any state, is missing from after.
Containers match by ID, or by Name when the ID is empty (old compose). Rows without a StartedAt cannot be compared by start time and are judged on state, identity and health. Exited 0 for a container that was never healthy is a finished run, not a crash; running/starting staying running/starting is fine.
func RemoveContainer ¶ added in v1.4.15
RemoveContainer force-removes the named container. An absent container is success.
func RemoveOrphans ¶ added in v1.3.6
func RemoveOrphans(ctx context.Context, orphans []OrphanContainer) []error
RemoveOrphans force-removes each orphan container by ID (docker rm -f — same primitive cleanup.go's forceRemoveContainer uses for init/zombie containers) and returns one error per failed removal. Never called unless the caller opted in (e.g. `nself build --remove-orphans`); detection alone never removes anything.
func RestartContainer ¶ added in v1.4.13
func RunOneShot ¶ added in v1.4.13
RunOneShot runs spec to completion (`docker run --rm`) and returns what the container wrote to stdout and stderr. A non-zero exit returns the captured output together with an error that quotes the last stderr line.
func RunPostStartCleanup ¶
RunPostStartCleanup runs the full post-startup cleanup sequence:
- Init container cleanup, repeated 3 times with 500ms delays (handles race conditions where containers are still being marked as exited).
- Zombie container cleanup for containers stuck in "created" state.
func RunPreDownHooks ¶ added in v1.4.15
RunPreDownHooks runs every registered hook for workdir.
func RunPreStartCleanup ¶ added in v1.2.2
RunPreStartCleanup removes stale artifacts that would break `docker compose up`: hash-prefixed rename-leftover containers (which hold ports and shadow clean container names). Run before compose up.
func SetExecHook ¶ added in v1.4.13
SetExecHook installs fn to be called once per ExecStdin call (test seam for exec counting) and returns a function that restores the previous hook.
func StartContainer ¶ added in v1.4.15
StartContainer starts a stopped container (a running one is left alone by docker).
func StatefulServices ¶ added in v1.4.13
StatefulServices returns the services that mount a named volume in any of the compose files (EPIC D7: a stateful service is one whose data lives in a named volume). A bind mount (a path) or tmpfs is not stateful. Missing files are skipped; a file that is not valid YAML is an error.
func StopContainer ¶ added in v1.4.15
StopContainer stops a container; a stopped one is not an error.
func VolumeCreate ¶ added in v1.4.15
VolumeCreate creates the named volume with the given labels. Creating a volume that exists with the same driver is a no-op in docker.
func VolumeExists ¶ added in v1.4.15
VolumeExists reports whether the named volume exists.
Types ¶
type Clock ¶ added in v1.4.13
Clock is the time source of the gate. Sleep returns early with the context's error when ctx is cancelled.
type Compose ¶
type Compose struct {
// DockerPath overrides the docker binary location. Empty uses PATH lookup.
DockerPath string
// ComposeFiles lists compose file paths passed as -f flags.
// Order matters: first file is the base, subsequent files extend/override.
// If empty, no -f flags are added and Docker uses its default discovery.
ComposeFiles []string
// EnvFiles lists env file paths passed as --env-file flags for ${VAR}
// interpolation (secrets are env-templated out of the generated compose
// YAML — see internal/build secret templating). Order matters: later
// files win on conflict. If empty, Docker Compose falls back to its
// default .env discovery.
EnvFiles []string
}
Compose shells out to `docker compose` for lifecycle operations.
func NewCompose ¶
NewCompose returns a Compose instance configured with the given compose files. If no files are provided, Docker Compose uses its default file discovery.
func (*Compose) ComposeConfig ¶
ComposeConfig runs `docker compose config` in the given workdir to validate the compose configuration. Returns nil on success.
func (*Compose) ComposeDown ¶
ComposeDown runs `docker compose down` with the given options in the given workdir.
func (*Compose) ComposePs ¶
ComposePs runs `docker compose ps --format json` and parses the output into a slice of ContainerInfo.
Docker Compose v2 prints either one JSON array or one JSON object per stdout line (NDJSON), depending on the release.
Both formats are handled: the raw output is first attempted as a JSON array; if that fails (or yields nothing), the output is re-scanned line by line as NDJSON. This makes the function version-agnostic.
func (*Compose) ComposePull ¶
ComposePull runs `docker compose pull` in the given workdir, pulling images for all services defined in the compose file.
func (*Compose) ComposePullDiagnosed ¶ added in v1.4.13
ComposePullDiagnosed retains a bounded stderr tail for first-run diagnosis. The general Compose runner can lose that tail when its pipe reader races process exit; a pull failure must preserve the registry's actual message.
func (*Compose) ComposePullService ¶ added in v1.1.3
ComposePullService runs `docker compose pull <service>` in the given workdir, pulling a fresh image only for the named service.
func (*Compose) ComposeRestart ¶
ComposeRestart runs `docker compose restart [services...]` in the given workdir.
func (*Compose) ComposeScale ¶ added in v1.1.3
ComposeScale runs `docker compose up -d --scale <service>=<n>` in the given workdir, adjusting the replica count for the named service.
func (*Compose) ComposeServiceNames ¶ added in v1.4.13
ComposeServiceNames returns `docker compose config --services` over the manifest and env files, in docker's order.
func (*Compose) ComposeServiceStates ¶ added in v1.4.13
func (c *Compose) ComposeServiceStates(ctx context.Context, workdir, service string) ([]ContainerState, error)
ComposeServiceStates returns every replica (running or stopped) of service. Stopped containers matter: a one-shot is only visible once it has exited. One-off `compose run` containers are dropped. The read is bounded by stateCallTimeout.
func (*Compose) ComposeStop ¶ added in v1.1.3
ComposeStop runs `docker compose stop [services...]` in the given workdir. Unlike ComposeDown, this stops containers without removing them, preserving their state for a subsequent ComposeUp.
func (*Compose) ComposeUp ¶
ComposeUp runs `docker compose up -d [services...]` in the given workdir.
func (*Compose) ComposeUpBuild ¶ added in v1.4.15
ComposeUpBuild runs `docker compose up -d --no-deps --build [services...]`: rebuild the named services' images and recreate only those containers.
func (*Compose) ComposeUpNoDeps ¶ added in v1.3.0
ComposeUpNoDeps runs `docker compose up -d --no-deps [services...]`.
This is the primitive that means "make these containers match the compose file": Compose recreates a container whose definition changed and leaves an unchanged one alone. `restart` does neither — it bounces the existing container and never re-reads the file. --no-deps keeps the operation scoped to the named services instead of pulling their dependencies up with them.
func (*Compose) FreshStates ¶ added in v1.4.13
func (c *Compose) FreshStates(ctx context.Context, workdir, service string, baseline map[string]string) ([]ContainerState, error)
FreshStates is ComposeServiceStates plus StartedAt on every running or exited container. An exited container whose StartedAt still equals its baseline mark is reported as StateNotRestarted, so a stale exit cannot pass the one-shot gate. No ID (old compose) means no mark and no StartedAt. A container removed between the ps and its inspect is dropped from the result (the gate polls again; Regressed reports it gone). The whole read shares one stateCallTimeout.
func (*Compose) OutputProject ¶ added in v1.4.15
func (c *Compose) OutputProject(ctx context.Context, workdir string, p ProjectRun, args ...string) ([]byte, error)
OutputProject runs args against p.Project in workdir and returns stdout. p.Stdout and p.Stderr are ignored: stderr is kept for the error, which carries its last line.
func (*Compose) Run ¶
Run executes a docker command with the given arguments, setting the working directory and inheriting the context for cancellation. Output is forwarded to os.Stdout/os.Stderr via goroutine-owned pipes rather than direct fd inheritance.
Direct fd inheritance (cmd.Stdout = os.Stdout) passes the test binary's stdout file descriptor to docker compose and all its children. The docker daemon, which is a separate long-lived process, may hold that fd open via IPC even after the docker compose process is killed — causing "*** Test I/O incomplete N s after exiting" in the Go test harness. Piped copying breaks the inheritance chain: the subprocess gets the write end of a pipe; our goroutine owns the read end and copies to os.Stdout. When the subprocess exits (or is killed), it closes the write end, the goroutine finishes, and the test binary's stdout fd is never held by any docker process.
WaitDelay gives the subprocess up to 5 seconds to drain pending I/O after the context is cancelled and the process is killed.
Setpgid places docker compose in its own process group so SIGKILL from the Cancel hook propagates to all spawned child processes, not just the top-level docker process.
func (*Compose) RunProject ¶ added in v1.4.15
func (c *Compose) RunProject(ctx context.Context, workdir string, p ProjectRun, args ...string) error
RunProject runs args against p.Project in workdir. A failure carries the tail of compose's stderr.
func (*Compose) StartMarks ¶ added in v1.4.13
func (c *Compose) StartMarks(ctx context.Context, workdir, service string) (map[string]string, error)
StartMarks maps container ID to StartedAt for each exited container of service. Taken before `up`, it lets FreshStates tell a one-shot that ran again (same container, new start time) from an old exit. The whole read (ps and every inspect) shares one stateCallTimeout.
type ComposeVerdict ¶ added in v1.4.15
type ComposeVerdict int
ComposeVerdict is the outcome of comparing a version with MinComposeVersion.
const ( // ComposeOK means the version is at least MinComposeVersion. ComposeOK ComposeVerdict = iota // ComposeTooOld means the version is below MinComposeVersion. ComposeTooOld // ComposeUnknown means the string could not be parsed. ComposeUnknown )
func CheckComposeVersion ¶ added in v1.4.15
func CheckComposeVersion(s string) ComposeVerdict
CheckComposeVersion compares s with MinComposeVersion.
type Container ¶
type Container struct {
ID string
Name string
Service string
State string // running, exited, paused, etc.
Health string // healthy, unhealthy, starting, none
Ports []string
}
Container represents a running or stopped container from ComposePs.
type ContainerInfo ¶
type ContainerInfo struct {
ID string
Name string
Service string // Docker Compose service name (e.g. "postgres", "hasura")
Image string
ImageRef string // the reference the container was created from (Config.Image), e.g. postgres:16-alpine
State string
Health string
Ports []string
Env map[string]string
Labels map[string]string
CreatedAt string
StartedAt string
Mounts []Mount
}
ContainerInfo holds detailed inspection data for a single container.
func InspectContainer ¶
func InspectContainer(ctx context.Context, name string) (*ContainerInfo, error)
InspectContainer shells out to `docker inspect` and returns parsed ContainerInfo.
type ContainerState ¶ added in v1.4.13
type ContainerState struct {
ID string `json:"ID"`
Name string `json:"Name"`
State string `json:"State"` // running, exited, restarting, ...
Health string `json:"Health"` // healthy, unhealthy, starting, or empty
ExitCode int `json:"ExitCode"`
StartedAt string `json:"-"` // daemon StartedAt; set by FreshStates, empty from a plain read
// Labels is a map or one "k=v,k=v" string, depending on the compose release.
Labels json.RawMessage `json:"Labels,omitempty"`
}
ContainerState is one container as `compose ps -a` reports it.
func (ContainerState) OneOff ¶ added in v1.4.13
func (s ContainerState) OneOff() bool
OneOff reports a container created by `docker compose run`. It is not a replica of the service, so the gate must not wait on it.
type DownOptions ¶
type DownOptions struct {
RemoveVolumes bool
RemoveImages bool // --rmi all
RemoveOrphans bool
Timeout int // seconds; 0 uses Docker default
}
DownOptions configures behavior for ComposeDown.
type ExecOptions ¶
ExecOptions configures behavior for container exec operations.
type Executor ¶
type Executor interface {
ComposeUp(ctx context.Context, services ...string) error
ComposeDown(ctx context.Context, opts DownOptions) error
ComposePs(ctx context.Context) ([]Container, error)
ComposeLogs(ctx context.Context, service string, follow bool, tail int) (io.ReadCloser, error)
Inspect(ctx context.Context, container string) (*ContainerInfo, error)
Exec(ctx context.Context, container string, cmd []string) error
}
Executor abstracts Docker Compose and container operations for testability.
type IndexInfo ¶ added in v1.4.13
type IndexInfo struct {
// MediaType is the index media type as published.
MediaType string
// Digest is "sha256:<hex>" of the raw index bytes (the index digest).
Digest string
// Platforms maps "linux/amd64", "linux/arm64", "linux/arm/v7" to the
// per-platform manifest digest.
Platforms map[string]string
}
IndexInfo is the parsed form of an image index.
func ParseIndex ¶ added in v1.4.13
ParseIndex computes the index digest of raw and extracts the per-platform digests. A trailing newline added by the CLI is not part of the digest.
type LockedImage ¶ added in v1.4.13
LockedImage is the Docker-facing projection of an image-lock entry. Keeping this value here preserves the L0 Docker funnel's dependency direction.
func (LockedImage) String ¶ added in v1.4.13
func (r LockedImage) String() string
type Mount ¶
type Mount struct {
Source string
Destination string
Type string // bind, volume, tmpfs
ReadOnly bool
}
Mount represents a container volume mount.
type OrphanContainer ¶ added in v1.3.6
type OrphanContainer struct {
ID string
Name string
Service string // may be empty if the container somehow lacks the label
State string
}
OrphanContainer describes a running-or-stopped container that belongs to this project (by compose project label) but has no matching service in the freshly generated compose files.
func DetectOrphans ¶ added in v1.3.6
func DetectOrphans(ctx context.Context, projectName string, defined map[string]struct{}) ([]OrphanContainer, error)
DetectOrphans lists every container belonging to projectName (by compose project label — see the package-level scoping note above) and returns the ones whose service is not present in defined. Returns an error only when the docker CLI itself could not be run (daemon unreachable, binary missing); callers should treat that as advisory-only and skip reporting rather than failing the caller's own command (a `nself build` run in a docker-less CI image must still succeed).
type PortConflict ¶
PortConflict records whether a specific port is already in use.
func CheckAllPorts ¶
func CheckAllPorts(ports []int) ([]PortConflict, error)
CheckAllPorts probes every port in the slice and returns only the entries where the port is already in use. A nil slice means no conflicts were found.
func CheckAllPortsFiltered ¶ added in v1.0.2
func CheckAllPortsFiltered(ctx context.Context, portList []int, workdir string, envFiles []string, composeFiles ...string) ([]PortConflict, error)
CheckAllPortsFiltered probes every port in the slice and returns only entries where the port is in use by a process that is NOT part of nself's own running compose stack. This prevents false positives where nself's own containers (e.g. postgres bound to 127.0.0.1:5432) are reported as conflicts on restart.
workdir, envFiles and composeFiles are forwarded to OwnedHostPorts. If that query fails the error is returned rather than degrading to unfiltered behaviour: unfiltered means the project's own ports read as conflicts, which blocks a legitimate start instead of catching a real one.
type PreDownHook ¶ added in v1.4.15
PreDownHook runs before `docker compose down` in workdir.
type ProjectRun ¶ added in v1.4.15
type ProjectRun struct {
Project string // -p value; empty keeps compose's default project name
Env []string // KEY=VALUE pairs appended to the inherited environment
Stdout io.Writer // nil discards
Stderr io.Writer // nil discards; the stderr tail still reaches the error
}
ProjectRun scopes one compose call to a named compose project with extra process environment (blue/green runs a second copy of the stack under its own -p name).
type RunSpec ¶ added in v1.4.13
type RunSpec struct {
// Image is the full image reference (a digest-pinned one for production use).
Image string
// Args are the arguments handed to the image's entrypoint.
Args []string
// EnvPass maps an environment variable name to its value. Only the name
// reaches argv (`-e NAME`); the value is set in the docker client's env.
EnvPass map[string]string
// Mounts are bind mounts; Source is a host path, Destination the in-container path.
Mounts []Mount
// User is "uid:gid"; empty leaves the image default.
User string
// Network is a docker network name; empty leaves the default bridge.
Network string
// PullNever refuses to pull a missing image (`--pull never`): the image must already exist locally.
PullNever bool
// ReadOnly mounts the root filesystem read-only (`--read-only`).
ReadOnly bool
// CapDrop lists capabilities to drop (`--cap-drop X`); "ALL" drops every one.
CapDrop []string
// SecurityOpt lists `--security-opt` values, e.g. "no-new-privileges:true".
SecurityOpt []string
// Name is the container name (`--name`); a caller that sets one can remove a
// container a killed run left behind (RemoveContainer).
Name string
// Labels are `--label key=value` pairs, rendered in key order.
Labels map[string]string
}
RunSpec describes one `docker run --rm` invocation.
type RunningService ¶ added in v1.4.13
type RunningService struct {
Name string
Service string
State string
ConfigHash string // empty when the container has no config-hash label
}
RunningService is one container of the project as the daemon reports it.
func RunningConfigHashes ¶ added in v1.4.13
func RunningConfigHashes(ctx context.Context, projectName string) ([]RunningService, error)
RunningConfigHashes lists every container (any state) carrying the compose project label, with its service and config-hash labels. An error means the daemon could not be asked.
type ServiceMatch ¶ added in v1.4.13
ServiceMatch selects a compose service's container. A container matches when its com.docker.compose.service label equals Service and either its com.docker.compose.project.working_dir label is one of WorkingDirs or its com.docker.compose.project label equals Project (ignored when empty). Only running containers match unless AnyState is set.
type ServiceSpec ¶ added in v1.4.13
type ServiceSpec struct {
Name string `json:"name"`
HasHealthcheck bool `json:"has_healthcheck"`
Restart string `json:"restart"`
// HealthTimeout is how long Docker may take to declare the healthcheck
// failed: start_period + retries*(interval+timeout). 0 without a healthcheck
// or when unknown (a spec built elsewhere). The latest Docker can still
// report healthy before it would declare the container unhealthy.
HealthTimeout time.Duration `json:"-"`
}
ServiceSpec is what the resolved compose model says about one service.
func ComposeServiceSpecs ¶ added in v1.4.13
func ComposeServiceSpecs(ctx context.Context, compose *Compose, workdir string) ([]ServiceSpec, error)
ComposeServiceSpecs reads the resolved config JSON over the compose's manifest and env files: one ServiceSpec per service, sorted by name.
func (ServiceSpec) OneShot ¶ added in v1.4.13
func (s ServiceSpec) OneShot() bool
OneShot reports a service that is meant to run once and exit: restart "no" and no healthcheck. A declared healthcheck wins (D17 order): such a service is long-running and is gated on healthy, never on exit.
type StateSource ¶ added in v1.4.13
type StateSource func(ctx context.Context) ([]ContainerState, error)
StateSource reads the service's containers; a remote host supplies its own. StartedAt on a running container lets the gate see a restart between polls; a source that leaves it empty still gets the two-poll check.
type SystemClock ¶ added in v1.4.13
type SystemClock struct{}
SystemClock is the real Clock.
func (SystemClock) Now ¶ added in v1.4.13
func (SystemClock) Now() time.Time
Now returns the wall clock time.
Source Files
¶
- cleanup.go
- compose.go
- compose_envfiles.go
- compose_exec.go
- compose_hash.go
- compose_hooks.go
- compose_services.go
- compose_services_spec.go
- compose_states.go
- compose_states_regress.go
- compose_states_unix.go
- compose_unix.go
- compose_version.go
- container_state.go
- exec.go
- exec_capture.go
- exec_stdin.go
- image_digest.go
- imagetools.go
- inspect.go
- interfaces.go
- network.go
- orphans.go
- port.go
- port_declared.go
- pull_fallback.go
- run_oneshot.go
- service_container.go
- version.go
- volume.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package dockertest decides whether a test that needs a Linux docker daemon runs, skips or fails on the current host (D-0286).
|
Package dockertest decides whether a test that needs a Linux docker daemon runs, skips or fails on the current host (D-0286). |