Help us shape the future of Go! Take the 2026 Go Developer Survey

docker

package
v1.0.0-rc.12 Latest Latest
Warning

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

Go to latest
Published: Oct 30, 2026 License: Apache-2.0 Imports: 41 Imported by: 0

Documentation

Overview

Package docker is the container runtime AppTown drives: which daemon a command talks to (AppTown's own, or an attached host's over SSH), the command itself, and the small questions asked of a daemon (is a container running, what is an image's digest, where is a port reachable). Every other driver and the console runtime build on it.

Index

Constants

View Source
const (
	PhaseResolve = "resolve" // an unknown need: refused at the door
	PhaseSecrets = "secrets" // a declared secret nothing provides, or a broken declaration
	PhaseConfig  = "config"  // the values a browser may be given could not be read
	PhaseNeeds   = "needs"   // the stack did not start
	PhaseFill    = "fill"    // the needs (or the app's data) could not be filled from the copy
	PhaseParts   = "parts"   // init containers or non-public parts
	PhaseApp     = "app"     // the public app container did not start
	PhaseProbe   = "probe"   // it started but never answered (LogTail has its last words)
	PhasePage    = "page"    // it answered, but the page a visitor opens is refused or missing
)

Boot phases, on BootError. The callers word their own failures per phase — the step evidence, the button's sentence and the rebuild log all differ.

View Source
const (
	HealthTick             = 15 * time.Second // how often the loop sweeps
	HealthGraceFloor       = 30 * time.Second // startupGrace is never shorter than this on a live env
	HealthFailThreshold    = 3                // consecutive misses before a restart
	HealthSuccessThreshold = 2                // consecutive passes to clear
	HealthBackoffBase      = 15 * time.Second // first backoff after a restart
	HealthBackoffCap       = 5 * time.Minute  // a crash-loop is held here, not hammered
	CrashLoopRestarts      = 5                // Docker restarts within the window that make a crash loop
	CrashLoopWindow        = 10 * time.Minute // Docker restarts an instant exit 7× in 12s; a healthy app never 5× in 10m
)
View Source
const (
	LogMaxLines   = 200
	LogMaxBytes   = 64 << 10
	LogReadWithin = 10 * time.Second
)

A container's recent log, read on an explicit request: the newest lines, bounded in count, size and time. There is no follow stream. A log may hold an application's secrets; the caller decides who may read it and keeps it out of every record.

View Source
const BootLifetime = 30 * time.Minute

BootLifetime bounds a preview's boot, from its first command to its answer: builds, pulls, init containers and the probe all end with it (Scope.WithLifetime), and a boot's configuration is never in use longer.

View Source
const BrowserEnvVar = appcontract.BrowserEnvVar

BrowserEnvVar carries a static part's browser-safe values, a JSON object.

View Source
const BrowserValuesFormat = `{"id":{{json .Id}},"env":[{{range .Config.Env}}{{if eq (index (split . "=") 0) "` + BrowserEnvVar + `"}}{{json .}},{{end}}{{end}}null]}`

BrowserValuesFormat asks the host for a container's immutable id and the one reserved browser value it was started with, and nothing else of its environment: every other variable may hold a secret, which is why Inspect never reads Config.Env.

View Source
const BuildCacheBudget = "4GB"

BuildCacheBudget is how much unused build cache a daemon keeps: the AppTown's own and a worker's alike.

View Source
const ContractPath = ".apptown/app.yaml"

ContractPath is where the app contract lives in a repository.

View Source
const MaxContractBytes = 1 << 20

MaxContractBytes bounds the app contract read from a commit.

View Source
const PreparedVersion = 1

PreparedVersion is the prepared value's shape; a machine given another refuses it.

View Source
const Redacted = "[secret]"

Redacted is what a generated credential reads as in a boot's failure.

View Source
const RuntimeFormat = `{"id":{{json .Id}},"image":{{json .Image}},"running":{{json .State.Running}},"labels":{{json .Config.Labels}},"memoryLimit":{{json .HostConfig.Memory}},` +
	`"state":{"status":{{json .State.Status}},"exitCode":{{json .State.ExitCode}},"oomKilled":{{json .State.OOMKilled}},"restartCount":{{json .RestartCount}},` +
	`"startedAt":{{json .State.StartedAt}},"finishedAt":{{json .State.FinishedAt}},"health":{{with index .State "Health"}}{{json .Status}}{{else}}""{{end}}}}`

RuntimeFormat is the inspect format the host is asked for: identity, liveness, the memory limit and the process state, never Config.Env or the health check's output. Docker renders it with missingkey=error and keeps State.Health only for a container with a health check, so Health is read with index, which answers nothing for a missing key. The process runner cancels the CLI and its children within a bounded deadline.

View Source
const StackLabel = dockerlabel.Stack

StackLabel names, on a preview's app container, the stack that lives and dies with it: a run's preview stack (pv<step>) cannot be told from the preview's name.

View Source
const TeardownBound = 2 * time.Minute

TeardownBound is how long a step's returned teardown may take: it runs after its caller's context may have ended, so it brings its own bound.

View Source
const WritesLabel = dockerlabel.Writes

WritesLabel marks a container that mounts a host folder writable: apptown.writes=<host path>. Whoever starts such a container labels it, so the folder's writers can be listed without knowing who started them.

Variables

View Source
var ErrContainerAbsent = errors.New("Docker container is absent")
View Source
var ErrLogUnreadable = errors.New("the host did not give the container's log")

ErrLogUnreadable is a log the host did not give: the daemon refused, the read timed out or was cancelled. Its words never include what the Docker client wrote, which may name a host's address or credentials.

View Source
var ErrNoAnswer = errors.New("no HTTP answer")

ErrNoAnswer is a sealed probe that got no HTTP answer.

View Source
var ErrNoBrowserValues = errors.New("the container carries no readable browser values")

ErrNoBrowserValues is a container that carries no readable browser value: a server part, or one started before AppTown set it. Either way what its page is given is not known.

View Source
var ErrNoContract = errors.New(".apptown/app.yaml not found — the app must declare its runtime contract")

ErrNoContract says the selected tree declares no hosted application.

View Source
var ErrNoLocalBackend = errors.New("this AppTown has no local Docker")

ErrNoLocalBackend refuses a call to AppTown's own Docker on an AppTown started with -no-local-docker. It is a backstop: owners answer from the mode first (Scope.Absent), and never read it as "not running".

View Source
var ErrRecordedImageMissing = errors.New("a recorded image is not on the daemon")

ErrRecordedImageMissing is a recorded image the daemon no longer has, or a digest its registry confirms it does not have.

Functions

func AdmitDisk

func AdmitDisk(ctx context.Context, dk Scope, image string) error

AdmitDisk refuses new disk-heavy work on a daemon (a boot's pulls, builds and new containers) while its data folder's filesystem has less than its floor free, or cannot be read (diskspace.Admit). It reads the disk now: a target's capacity view keeps its reading for minutes, and admission does not trust it. Stopping, removing and taking down never ask.

func AdmitResources

func AdmitResources(ctx context.Context, dk Scope, c *appcontract.Contract) error

AdmitResources refuses, before anything is made or removed, a part or need whose declared memory or CPUs exceed what the daemon can give any container: such a container could never run there. The sum of every limit on the host may exceed it (limits are caps, not reservations), so overcommit is admitted. A daemon that cannot say what it has is refused for now, not for good.

func BrowserEnvScript

func BrowserEnvScript(values string) string

BrowserEnvScript is /_apptown/env.js around a JSON object of values. No literal braces: the static server's config would read them as a placeholder.

func BuildFailure

func BuildFailure(operation string, output []byte, cause error) error

BuildKit puts the compiler/test failure after its setup and progress output. Keep the end of long logs so previews and console feedback retain the cause, while bounding the error sent through HTTP, session messages and audit rows.

func ChangeBuildImages

func ChangeBuildImages() []string

ChangeBuildImages selects every change preview's build images (image ls reference filters, ORed): its app's and its parts'.

func ChangeOfBuildImage

func ChangeOfBuildImage(repository string) (ids.ID, bool)

ChangeOfBuildImage is the change whose preview a build image is, by its repository (BuildTag of the preview, or of a part: <tag>-<part>). The change's id is the 36 characters after the prefix.

func ChangeStackID

func ChangeStackID(changeID ids.ID) string

func ConfineStaticExport

func ConfineStaticExport(ctx context.Context, root, output string) (string, error)

ConfineStaticExport is the site folder output names inside an exported build stage at root, once nothing in it can lead outside it. The export is the project's own build output, so it is read without following a link: every folder on the way to output, and everything under it, must be a plain folder or file. A link anywhere there is refused, wherever it points (built static output holds no links). Links elsewhere in the stage are never read. An output that is absolute or leaves the export is refused before anything runs; the rest is StaticExportCheckScript, the one check, run here under /bin/sh (it and find exist on macOS and Linux).

func ContainerHostPort

func ContainerHostPort(ctx context.Context, dk Scope, name string, inner int) (int, error)

ContainerHostPort is the host port a container's inner port is mapped to, asked of `docker port` and parsed from its "0.0.0.0:PORT" tail. inner is the container port to ask about (0 = the first mapping). This is the one parse of that answer.

func ContainerOfDataVolume

func ContainerOfDataVolume(volume string) (string, bool)

ContainerOfDataVolume is the inverse of DataVolume.

func ContractFileAt

func ContractFileAt(ctx context.Context, repo, sha string) ([]byte, error)

ContractFileAt is the app contract at an exact revision: the file at ContractPath, unparsed. It is every reader's: deploys, previews, an agent's needs, the MCP read and a change's additions all read a commit's contract here, so they agree on what a commit declares.

No contract is ErrNoContract, but only when .apptown is missing or a real folder: a link where the folder should be, a contract that is not a regular file, or one over MaxContractBytes is an error, never "nothing". The reads are git plumbing run hardened (gitexec.HubOutput).

func EnsureStandingServices

func EnsureStandingServices(ctx context.Context, dk Scope, stackID string, svcs []deploy.ServiceSpec, dataClass string, own Ownership) (string, error)

EnsureStandingServices starts a deployment's standing services (<prefix>svc-env-<slug>-<env>-<name>, owner = the env's stack id) and returns the network name, or "" when the deployment needs none. Idempotent: existing containers stand — their data is the persistence. A standing container whose declared parameters have MOVED (another user, database or image than the contract names now) cannot serve the app: a database made under one user, booted against a contract that now names another, fails "password authentication failed". Synthetic data is replaced; anything else is refused with the words, never silently replaced.

func ExactOrigin

func ExactOrigin(raw string) (string, error)

ExactOrigin validates an owner-produced browser origin before replacement. Empty means no configured route, as for a domainless local preview.

func ExportStaticBuild

func ExportStaticBuild(ctx context.Context, dk Scope, contextDir string, sb appcontract.StaticBuild) (site string, done func(), err error)

ExportStaticBuild runs a declared static site's build on dk and answers its output folder, checked (ConfineStaticExport), and done, which removes the export. The build is Scope.Build's: the selected daemon's own builder, for its own platform (the site is files).

func HandVolumeToImageUser

func HandVolumeToImageUser(ctx context.Context, dk Scope, volume, image, chownImage string)

HandVolumeToImageUser makes a data volume owned by the user an image declares (USER in its Dockerfile), resolving a name to a uid inside the image. Root, no USER, or an image without a shell to resolve a name: nothing is done and the volume keeps its ownership.

func IntranetNeeds

func IntranetNeeds(resolved []ResolvedNeed) []deploy.IntranetNeed

IntranetNeeds carries the resolved Docker emulators into the release renderer.

func IsDigestReference

func IsDigestReference(ref string) bool

IsDigestReference says whether ref names an image by digest in a registry: <repository>@sha256:<hex>.

func IsLocalBuildTag

func IsLocalBuildTag(image string) bool

IsLocalBuildTag: an image that exists only on this daemon.

func IsNamedVolume

func IsNamedVolume(volume string) bool

IsNamedVolume says whether a volume carries a name AppTown gives a data or need volume.

func IsPreviewName

func IsPreviewName(name string) bool

IsPreviewName says whether a container is a preview-tier app container (the vhost's cache policy and the orphan sweep read this).

func IsWorkPreviewLabel

func IsWorkPreviewLabel(label string) bool

IsWorkPreviewLabel says whether a preview label is a change's or a run's (change-<id>, run-<id>): the previews work boots, never a release's look.

func IsWorkPreviewName

func IsWorkPreviewName(name string) bool

IsWorkPreviewName is IsWorkPreviewLabel for a container name.

func LoginRegistry

func LoginRegistry(ctx context.Context, dk Scope, host, username, token, image string) error

LoginRegistry authenticates only images from this registry. Credentials are supplied per operation and reach Docker on stdin, never a command argument. A login that fails is an error, and the caller pulls nothing: a pull after it could succeed with another credential Docker holds, or none.

func MemoryUsage

func MemoryUsage(ctx context.Context, dk Scope, names []string) (map[string]int64, error)

MemoryUsage is what each named container uses now, as the daemon reports it (docker stats, one sample). A container the daemon does not report is absent from the answer; an answer that cannot be read is an error, never zero.

func Named

func Named(name string) bool

Named says whether a name begins with the prefix AppTown names things with.

func ObserveExistingStorage

func ObserveExistingStorage(ctx context.Context, dk Scope, stackID, path string, svc deploy.ServiceSpec, current *deploy.StorageBinding) (deploy.StorageBinding, error)

ObserveExistingStorage reads one existing service without starting, pulling, creating or deleting anything. Boot records what it observes for an existing engine that has no binding yet.

func ObserveStorageEngine

func ObserveStorageEngine(ctx context.Context, dk Scope, container, path, volume string) (string, string, error)

ObserveStorageEngine witnesses a physical copy's exact source container, immutable engine and actual named mount. It grants no mutation authority.

func PackStaticBuild

func PackStaticBuild(ctx context.Context, dk Scope, contextDir string, sb appcontract.StaticBuild, server string, port int, tag string) error

PackStaticBuild builds a declared static site on dk and packs its output into the file server's image, tagged tag (design/subsystems/deploy-targets.md, "Static sites and readiness"):

  1. export: the Dockerfile in contextDir is built to its target stage and that stage's files are written to a folder (docker build --output); nothing of it runs afterwards;
  2. confine: the output folder is checked before anything reads it (ConfineStaticExport);
  3. pack: the folder becomes the self-serving static image (StaticSiteDockerfile), as a committed static folder does.

Both builds go through Scope.Build, so they run on the daemon AppTown selected and its own builder, never on a Buildx builder chosen elsewhere.

func ParseImageUser

func ParseImageUser(s string) (uid, gid string, ok bool)

ParseImageUser reads a Dockerfile USER value ("app", "10001", "10001:10001", "app:app") into uid and gid parts; ok is false for an unset or root user.

func ParsePreviewChangeID

func ParsePreviewChangeID(name string) (ids.ID, bool)

ParsePreviewChangeID is the inverse of previewChangeName: strict — the whole suffix must be the id, so apptown-preview-change-7-old never reads as 7.

func PreparePreviewBuilds

func PreparePreviewBuilds(ctx context.Context, dk Scope, ws, name string, c *appcontract.Plan) error

PreparePreviewBuilds builds each explicit build context once. Different contexts cannot silently share the public image. Only the private plan receives tags.

func PrepareSource

func PrepareSource(ctx context.Context, repo, revision, slug string, services []deploy.ServiceSpec) (deploy.Artifact, func(), error)

func PreviewChangeName

func PreviewChangeName(changeID ids.ID) string

func PreviewLabelName

func PreviewLabelName(label string) string

func PreviewRunName

func PreviewRunName(runID ids.ID) string

func ProbeLiveness

func ProbeLiveness(ctx context.Context, dk Scope, container string, hostPort int, rp RenderedProbe, headers map[string]string) bool

ProbeLiveness executes one rendered liveness probe against a running env container: an in-container exec, a TCP connect to the mapped port, or a platform HTTP GET (shaped by AppTown front door so a hardened app doesn't 301 the check — the same signal the cold-boot render sends). Any transport error, or an answer the readiness rule refuses (appcontract.Ready), is a miss.

func PruneBuiltImages

func PruneBuiltImages(ctx context.Context, dk Scope) error

PruneBuiltImages removes the dangling images on dk that AppTown built (dockerlabel.Built), and no others: an image pulled by digest alone is dangling on Docker's classic store (the disk read's image), and a shared host's other images are not AppTown's.

func ReadContractAt

func ReadContractAt(ctx context.Context, repo, sha string) (*appcontract.Contract, error)

ReadContractAt reads the canonical runtime declaration at an exact repository revision.

func ReadDisk

func ReadDisk(ctx context.Context, dk Scope, image, dataRoot string) (diskspace.Space, error)

ReadDisk reads the filesystem holding the daemon's data folder in the daemon's standing disk reader (diskspace.ReadThroughDocker). Each call's output is combined, as every call through a scope's client is.

func ReadSelectedContract

func ReadSelectedContract(root string) (*appcontract.Contract, error)

Read contract presence from selected source before deciding whether this is a runtime deployment. A symlink must not turn that decision into a host-file read.

func ReadWorkspaceContract

func ReadWorkspaceContract(ws string) (*appcontract.Contract, error)

ReadWorkspaceContract reads the native declaration in a live workspace. Selected immutable source continues to use ReadSelectedContract and its confinement.

func ReapPreviewOrphans

func ReapPreviewOrphans(ctx context.Context, dk Scope)

ReapPreviewOrphans removes every preview this daemon holds, as RemovePreview removes one. It decides from labels and exact names, never substrings: the preview-class app containers and the services and init containers whose owner is a throwaway preview stack (never a deployment's env-<slug>-<env> stack, never an agent step's), each with its anonymous volumes; those stacks' networks; and the previews' data volumes.

func RecordBoot

func RecordBoot(ctx context.Context, dk Scope, id deploy.DockerIdentity, name, image, url string, port int, checkpoint deploy.Checkpoint) (deploy.Observation, error)

func RefusesHealth

func RefusesHealth(c *appcontract.Contract, publicOnly bool) error

RefusesHealth validates every executed component before any Docker effect. Sealed copies execute only the public application, retaining init completion.

func RelativePath

func RelativePath(root, path string) (string, error)

func ReleasePreviewLabel

func ReleasePreviewLabel(slug string, number int64) string

func ReleaseStackID

func ReleaseStackID(slug string, number int64) string

func RemovePreview

func RemovePreview(ctx context.Context, dk Scope, name, stack string) error

RemovePreview removes one preview's whole stack, and says whether anything of it could not be removed: its app container with its anonymous volumes and its data volume, then every container its stack owns (its services, its parts, an init container left standing) with theirs, and the stack's network. Every stop of a preview on this daemon comes here: a discard, a replacement, a restart, a boot that failed, an idle stop. Its build images stay; they are not part of what runs.

func ResourceAdmissionContract

func ResourceAdmissionContract(c *appcontract.Contract, services []deploy.ServiceSpec) *appcontract.Contract

ResourceAdmissionContract is a read-only projection of all containers a stack will boot. Supplied services are included for the existing local/worker admission protocol; this projection is never used as the boot's app contract.

func ResourceArgs

func ResourceArgs(r appcontract.Resources) []string

ResourceArgs are the docker run flags that hold a part to its declared resources: memory with swap at the same value (the declared figure is swap included), and CPUs. A part that declares nothing gets none: no limit, as declared.

func RestoreSource

func RestoreSource(ctx context.Context, repo, slug, raw string) (deploy.Artifact, func(), error)

func Resume

func Resume(ctx context.Context, dk Scope, p deploy.Placement, generation int64, noted map[string]any) (deploy.Observation, error)

Resume settles an attempt AppTown lost track of from what it recorded and what the host says now. Whenever the host answers, the outcome is known: the container the attempt recorded booting healthy, running as recorded, is the deployment; anything else (no record of a healthy boot, the container gone, replaced or stopped) is a failed attempt, whose leftovers the next release or a take-down removes. Only a host that cannot be asked leaves it unknown, for a later look. An attempt with no record whose boot did come up (AppTown stopped between the boot and writing its record) reads failed while its container runs: an accepted cost.

func RunStepStackID

func RunStepStackID(stepID ids.ID) string

func RunningMemoryUsage

func RunningMemoryUsage(ctx context.Context, dk Scope) (map[string]int64, error)

RunningMemoryUsage is what every running container uses now, by name (docker stats, one sample).

func SameContract

func SameContract(a, b *appcontract.Contract) bool

SameContract says whether two contracts declare the same thing.

func SelectedPath

func SelectedPath(root, path string) (string, error)

func ServiceDrift

func ServiceDrift(ctx context.Context, dk Scope, cname string, svc deploy.ServiceSpec) ([]string, error)

ServiceDrift names what differs between a standing service container and the service the contract declares now: "entrypoint", "command", "image", or env keys whose values moved. Empty when the container still serves the declaration. An entrypoint or command the declaration leaves to the image is not compared: the image's own is not known here.

func SourceArtifact

func SourceArtifact(source deploy.Source, services []deploy.ServiceSpec) (deploy.Artifact, error)

SourceArtifact binds a declaration already read from the selected tree to its durable inputs. Validation and boot share this declaration; no head is reread.

func SourceAt

func SourceAt(ws, commit, slug string, services []deploy.ServiceSpec) (deploy.Artifact, error)

func SourceServices

func SourceServices(art deploy.Artifact) []deploy.ServiceSpec

dockerSourceServices are the emulated services the selected source asked for, read back from the artifact's body.

func StackOfNetwork

func StackOfNetwork(network string) (string, bool)

StackOfNetwork is the inverse of Network.

func StagedBuildContext

func StagedBuildContext(ctx context.Context, ws, buildContext string) (string, func(), error)

stagedBuildContext stages tracked worktree edits without ignored or untracked files. Already materialized source trees have no .git and are used directly. A Git or archive failure must never substitute the live worktree.

The index is refreshed first: a folder copied to another path or machine (a worker's copy of the change folder) keeps index stat data that no longer matches its files, and on such a clean tree `git stash create` exits 1 without output instead of printing nothing.

func StaleEndpoint

func StaleEndpoint(out string) bool

StaleEndpoint says whether a run failed because the daemon still holds a gone container's network endpoint under the name.

func StartServices

func StartServices(ctx context.Context, dk Scope, id string, svcs []deploy.ServiceSpec) (string, func(), error)

startServices creates a per-step network and launches sidecars on it, then waits for the ones that declare a healthcheck to become healthy (a real readiness gate, not a blind sleep) so migrations/apps start against a ready dependency. Returns the network name and a teardown func (always non-nil).

The teardown removes the stack by its owner label, not by what this call started: a container an earlier attempt left (an AppTown that stopped mid step) still holds the network, and the network goes only once nothing is on it. Whatever it still cannot remove, the periodic reaper takes once the owner has finished (maintenance.Reaper.Containers).

func StaticExportArgs

func StaticExportArgs(target, contextDir, dest string) []string

StaticExportArgs are a static site's export build arguments after `build`: its declared target stage, its files written to dest, its context. A deploy, a release built on a worker and `apptown dev` all build a static site with them, so the three build it alike.

func StaticExportCheckScript

func StaticExportCheckScript(export, output string) string

StaticExportCheckScript is ConfineStaticExport for a shell where the export is (a release built in a worker's task, whose files never leave it): it refuses the export at export unless output is plainly there, with ConfineStaticExport's own reasons, and exits 1 saying why. Both are run over one table of exported trees (static_build_test.go), so they refuse the same exports.

func StaticServerCommand

func StaticServerCommand(port int) []string

StaticServerCommand serves a static part: the site from /srv, and /_apptown/env.js answered from BrowserEnvVar at request time, so one image serves every deployment its own values. A static site cannot read its container's environment; this file is how the attached integrations' public values (an error-reporting DSN, a feedback key) reach the page, as window.__APPTOWN_ENV__; without it a static app could adopt error reporting that never reports, with nothing putting the DSN in the page. Unset or empty, the file answers {} whatever the target set (App Platform sets nothing, and a bare expansion would end the script mid-expression). ReleasePath answers the part's release identity (ReleaseEnvVar, empty when unset): what a front door AppTown reaches only from outside is witnessed serving.

func StaticSiteDockerfile

func StaticSiteDockerfile(server string, port int) string

StaticSiteDockerfile packs a static site's folder into the file server's image with the command that serves it on port (StaticServerCommand): the image describes itself, so every target runs it the same way and none adds a command (a target that ran the file server's stock configuration would serve its default page). The build only copies files, so it needs no emulation for another platform.

func SweepBootConfigs

func SweepBootConfigs(scratch string) error

SweepBootConfigs removes every boot configuration under scratch: those of boots a stop interrupted, or whose own removal failed. Its owner calls it only when none of its boots runs (as it starts): a configuration is its boot's until that boot ends.

func TearDownOwned

func TearDownOwned(ctx context.Context, dk Scope, owned []deploy.Owned, serving string, backedUp bool, storage deploy.StorageBindings) deploy.TakenDown

TearDownOwned deletes what a deployment's list names, after its serving container is gone (serving: its ID, not deleted again): containers, then networks, then data volumes (only when backedUp), then images (only those no container uses). What the daemon says is gone is passed over; what it cannot be asked about, and a failed delete, is reported Left, never hidden. A container goes without its anonymous volumes: only a volume the list names is ever deleted.

func TrimBuildCache

func TrimBuildCache(ctx context.Context, dk Scope) error

TrimBuildCache trims dk's unused build cache to BuildCacheBudget.

func VerifyIdentity

func VerifyIdentity(id deploy.DockerIdentity, runtime Runtime, image string) error

verifyDockerIdentity checks that a running container is the one the deployment was admitted for: labels, image and liveness.

func VisitorHost

func VisitorHost(address string) string

VisitorHost is the Host a visitor's request carries at an address, for a gate's page check (BootRequest.VisitorHost).

func VolumeAt

func VolumeAt(ctx context.Context, dk Scope, container, path string) (string, error)

VolumeAt is the volume mounted at path in a container, "" when none is: where a need container keeps its data, named or anonymous.

func WorktreeFingerprint

func WorktreeFingerprint(ws string) string

WorktreeFingerprint is a print of what a boot would bake, so a container can say what it serves: every source file's path, size and mtime (a content edit bumps mtime, so a second edit to an already-dirty file changes the print; `git status` alone doesn't see that, so a preview would stay stale), plus the contract bytes. Skips runtime and derived dirs. Deliberately mtime-based, not a content hash: a spurious mtime bump costs one needless reboot — the safe direction to be wrong in.

Types

type BootError

type BootError struct {
	Phase   string
	Err     error
	LogTail string
}

func AsBootError

func AsBootError(err error) *BootError

asBootError: the phase-carrying error behind a boot failure; any other error comes back wrapped with no phase.

func (*BootError) BeforeEffects

func (e *BootError) BeforeEffects() bool

BeforeEffects says the boot failed before touching Docker: the attempt's outcome is known, nothing changed, and a new attempt may follow once the cause is fixed. A later phase can have left effects nobody saw.

func (*BootError) Error

func (e *BootError) Error() string

func (*BootError) KnownOutcome

func (e *BootError) KnownOutcome() bool

KnownOutcome says the attempt's outcome is known: the boot ran and reported, in a phase, that the new version did not come up. It failed. What it left on the host is on the deployment's list (Ownership), so the next release or a take-down removes it. Only an error with no phase (one a boot did not report) leaves the outcome unknown.

func (*BootError) Unwrap

func (e *BootError) Unwrap() error

type BootRequest

type BootRequest struct {
	// Allowed is the caller's current permission check, repeated before effects.
	Allowed func(context.Context) error
	// Log reports phase entry. It receives no environment values or command output.
	// Nil disables progress reporting without changing boot behavior.
	Log          deploy.Logf
	Slug         string  // the application's current display address; not routing identity
	ExactOrigins *string // nil retains captured route context; non-nil is the owner's exact browser origin (empty means none).
	ServingLabel string  // immutable label for a standing host route; separate from secret scope
	DataClass    string  // what a standing deployment holds; "" or "synthetic" lets a moved service be recreated
	Name         string  // the public app container: apptown-preview-change-7, <prefix>env-<slug>-main
	StackID      string  // owner of its stack (services, init, network): pvsnap-change-7, pv<step>, env-<slug>-<env>
	Workspace    string  // the tree to boot: a worktree, a run workspace, the project checkout
	// HostPort pins a standing deployment's stable port; 0 lets docker pick
	// (previews).
	HostPort int
	// Persistent marks a standing deployment: its needs are reused when
	// already running (data survives releases), everything restarts with the
	// host, and the labels say class=env — never reaped. Previews are the
	// opposite on every count.
	Persistent bool
	// Deployment names which deployment's secret bindings apply
	//: "preview" for every preview, the standing
	// deployment's name for a deploy or rebuild. Empty means preview.
	Deployment string
	// Services overrides the contract's sidecars (a workflow's services:
	// declaration); empty means the contract's own.
	Services []deploy.ServiceSpec
	Probe    time.Duration
	// Docker is which daemon the stack boots on: AppTown's own by default,
	// an attached host's for a standing deployment bound there.
	Docker Scope
	// PageCheck is the gate's extra question about the page a visitor
	// opens: a client-only site's page answers (below 400), and a
	// server app's root is not refused (check.PageRefusal). Gates ask it;
	// the try-it button and the rebuild do not.
	PageCheck bool
	// VisitorHost is the host name a visitor's request carries through the
	// front door (change-7.preview.example, shop.apps.example.com); the page
	// check sends it, so a host allow-list is judged as a visitor meets it.
	// "" sends the probe address's own.
	VisitorHost  string
	ReleaseImage string // Recorded public artifact for a historical release preview.
	// Incarnation names what the boot serves, for a preview: its source and
	// the digest of its prepared public values. It is labelled on the app
	// container (apptown.incarnation), and a reuse matches it. "" is none.
	Incarnation string
	// Scratch is the boot's own folder, where a prepared boot keeps its
	// Docker configuration; its owner sweeps it (SweepBootConfigs). A
	// prepared boot without one is refused.
	Scratch  string
	Identity *deploy.DockerIdentity // Standing execution from a selected source; previews have no deployment identity.
	// Recorded is a release's images: IDs already on this daemon, or images
	// by digest it pulls. The boot runs them and builds nothing
	// (PrepareImages), for a standing deployment or a release's preview.
	// nil prepares each image from the source.
	Recorded *RecordedImages
	// Revision is the committed revision a standing deployment serves. A
	// public static part is told its release identity
	// (appcontract.Contract.PublicRelease), answers it at ReleasePath, and
	// the boot witnesses that answer. "" (a preview of a worktree) tells it
	// nothing and witnesses nothing.
	Revision string
	// Record records what a standing deployment's boot creates (its
	// containers, a network it made, data volumes, the images it pulled or
	// built), as each is created: its take-down deletes exactly that. nil
	// records nothing (previews and runs have their own cleanup). A
	// creation that cannot be recorded fails the boot.
	Record         func(deploy.Owned) error
	Storage        deploy.StorageBindings
	RestoreStorage deploy.StorageRestore
	// Owned is the deployment's list before this boot (Ownership.Recorded).
	Owned []deploy.Owned
	// Sealed boots a restore rehearsal: no address outside its host, its
	// own network, its needs filled before any init step, and only the
	// public part (Sealed). nil boots as before.
	Sealed *Sealed
	// Fill puts a deployment's data back after its needs are up and before
	// any init step, part or the public app runs, on the stack's network
	// ("" when it has none), so nothing of the app writes into, or answers
	// from, the new and empty data first: a rebuild after AppTown was
	// restored. A failing fill ends the boot (PhaseFill) with nothing of the
	// app started. nil fills nothing.
	Fill func(network string) error
	// contains filtered or unexported fields
}

BootRequest names what a boot is for. Everything the sequence needs beyond the contract itself.

type BootResult

type BootResult struct {
	HostPort int
	Network  string
	Stack    ResolvedStack
	// Page is what the front-page check saw, passed or refused; nil when
	// the boot did not ask (no PageCheck, or it stopped before).
	Page *PageWitness
}

BootResult is what a boot produced. On a failure after the app started (probe, static check) HostPort and Network are still filled so the caller can name the URL or tear the stack down.

func (BootResult) Image

func (r BootResult) Image() string

Image is the public part's image id, as booted.

type Booter

type Booter interface {
	Boot(ctx context.Context, req BootRequest, c *appcontract.Contract) (BootResult, error)
}

Booter runs the one boot sequence for a request and reports the port and the public image that came up.

type CLI

type CLI struct{ Binary string }

func (CLI) Run

func (c CLI) Run(ctx context.Context, host string, req Command) ([]byte, error)

type Client

type Client interface {
	Run(context.Context, string, Command) ([]byte, error)
}

Client is the command transport consumed by a daemon scope. One client handles ordinary calls, bounded observations and streamed backup data. The composition root supplies it; a missing client never selects a real daemon.

type Command

type Command struct {
	Args    []string
	Stdin   io.Reader
	Stdout  io.Writer     // nil captures combined output; non-nil streams stdout only
	Stderr  io.Writer     // optional separate stream, e.g. the build log
	Timeout time.Duration // bounded observations retain the process-tree runner
	// Env adds NAME=value pairs to the docker CLI's own environment, so a
	// secret reaches a container by `-e NAME` and never appears in an
	// argument list another process can read.
	Env []string
}

type ContainerEvent

type ContainerEvent struct {
	Container string    // the container's name
	Action    string    // "oom", "die" or "kill"
	At        time.Time // the daemon's time for it
	ExitCode  *int      // a die's exit code; nil otherwise
	// Deployment and Generation are the container's AppTown identity labels,
	// as the event carried them: "" for a container that has none (a
	// deployment's needs and other parts outlive its generations).
	Deployment, Generation string
}

ContainerEvent is one thing the daemon reported happening to a container: Docker's own record, which AppTown reads and never infers.

func ContainerEvents

func ContainerEvents(ctx context.Context, dk Scope, since, until time.Time) ([]ContainerEvent, error)

ContainerEvents is what the daemon reports of containers being killed out of memory, exiting or being killed by a signal between since and until: one bounded read of its event log (docker events --until returns). The daemon keeps only its recent events in memory to replay, so a window larger than that buffer loses the oldest, and nothing is replayed across a daemon restart: an empty answer is "none reported", not "none happened".

func ParseContainerEvents

func ParseContainerEvents(out []byte) ([]ContainerEvent, error)

ParseContainerEvents reads docker events' JSON lines. A line that is not an event AppTown reads is an error, never skipped: a skipped event would read as one that did not happen.

type ContainerLimit

type ContainerLimit struct {
	Name        string
	MemoryBytes int64   // 0: no limit
	CPUs        float64 // 0: no limit
	// CPUUnread says a CPU constraint was set that AppTown could not
	// read as a number of CPUs: never counted as no limit.
	CPUUnread bool
	// AppTown says AppTown started it (it carries a class label); Class
	// and Owner are those labels, "" where absent, so a reader can say
	// whose it is: a deployment's, a preview's, agent work, AppTown's own.
	AppTown bool
	Class   string
	Owner   string
}

ContainerLimit is the limit Docker enforces on one running container, and whether AppTown started it (its class label).

func RunningLimits

func RunningLimits(ctx context.Context, dk Scope) ([]ContainerLimit, error)

RunningLimits is the limits Docker enforces on every running container: the daemon's own record (docker inspect), so a preview, a need, an override and software AppTown did not start are all in it. A CPU ceiling may be set three ways (--cpus, a quota over a period, a set of CPUs); the tightest one holds.

type ContainerState

type ContainerState struct {
	Status       string    `json:"status"`
	ExitCode     int       `json:"exitCode"`
	OOMKilled    bool      `json:"oomKilled"`
	RestartCount int       `json:"restartCount"`
	StartedAt    time.Time `json:"startedAt"`
	FinishedAt   time.Time `json:"finishedAt"`
	Health       string    `json:"health"`
}

ContainerState is the daemon's own record of a container's process: its status, its last exit, whether the kernel killed it at its memory limit, Docker's restart counter for this container (not a lifetime count across containers) and when it last started and finished. Health is the container's Docker health check status, "" when it has none configured.

type Contributions

type Contributions interface {
	EnvFor(context.Context) ([]string, error)
	BrowserEnv(context.Context) (string, error)
}

Contributions is the attached integrations' rendered env for an app, and the part of it safe for any browser to read, as a JSON object. A read that fails is an error, never fewer variables.

type DataMount

type DataMount struct {
	Volume, Bind string
	Found        bool
}

DataMount is where a container keeps what is at a path: a volume's name, or a bind mount's source on the host. Found is false when nothing is mounted there, so the container keeps it in its own layer.

func DataMountAt

func DataMountAt(ctx context.Context, dk Scope, container, path string) (DataMount, error)

DataMountAt is what a container mounts at path, of either kind: where a need service keeps its data.

func (DataMount) Spec

func (m DataMount) Spec() string

Spec is the mount as `docker run -v` takes it, before ":path".

type Delivery

type Delivery struct {
	Env      func(consumer string) map[string]string
	Receipts []SecretReceipt
	Profile  string
}

Delivery is the broker's answer for one boot.

func (Delivery) EnvFor

func (d Delivery) EnvFor(consumer string) map[string]string

EnvFor is what a part, an init step or a renderer asks of a delivery.

type Dependencies

type Dependencies struct {
	Secrets      SecretResolver
	Needs        NeedCatalog
	Registry     RegistryLogin
	Integrations Contributions
	Routes       Routes
	Probe        Prober // nil is the default probe
	// The images a boot runs for itself, from the tool versions snapshot its
	// caller's unit of work took: the file server for static parts, an image
	// with chown for handing a volume to the app's user ("" skips it), and
	// the df a new boot's disk admission runs.
	StaticServer string
	ChownImage   string
	DFImage      string
}

Dependencies is what the host asks of the world; nil for Registry, Integrations or Routes means "none", never a crash. A caller that serves many owners builds a host per owner: the collaborators already know whose secrets, registries and integrations they answer for.

type Driver

type Driver struct {
	Now func() time.Time // completion time of a current readiness sample
	// Allowed rechecks the caller before boot phases; nil is an unguarded caller.
	Allowed      func(context.Context) error
	ServingLabel string                                                          // immutable owner-supplied routing label, independent of source.Slug
	Scope        func(context.Context) (Scope, error)                            // which daemon: AppTown's own, or an attached host's
	Boot         Booter                                                          // the stack boot
	URL          func(servingLabel, deployment string, port int) (string, error) // the address a deployment is reached at
	AfterRelease func(p deploy.Placement)                                        // what follows a release (a backup)
	// Registry is the credential a release's images by digest are pulled
	// with, and Scratch the folder each pull's own Docker configuration is
	// written under (RecordedImages). A credential that cannot be read is
	// an error, never an anonymous pull.
	Registry func() (*RegistryCredential, error)
	Scratch  string
	// Owner records what the deployment's boot creates on the host; nil
	// records nothing, and then a take-down deletes only the container.
	Owner          deploy.Owner
	Storage        deploy.StorageBindings
	RestoreStorage deploy.StorageRestore
	// Owned reads the deployment's list, so a boot resets only what the
	// AppTown recorded making; nil reads nothing.
	Owned func(context.Context) ([]deploy.Owned, error)
	// DataClass is what the deployment declares it holds; only
	// "synthetic" lets a standing service be replaced when its declared
	// parameters move. "" is unknown, and protected.
	DataClass string
	// Fill, when set, puts the deployment's data back in this boot, after
	// its needs and before anything of the app starts (BootRequest.Fill):
	// a rebuild after AppTown was restored.
	Fill func(network string) error
}

Driver is a Docker host's driver: it builds the selected source on the host, or runs the images the source names (deploy.Source.Images: IDs on this daemon, or images by digest it pulls), and runs it as the placement's container, through the stack boot it is given.

func (*Driver) Controls

func (d *Driver) Controls() deploy.Controls

func (*Driver) FitResources

func (d *Driver) FitResources(ctx context.Context, c *appcontract.Contract) (map[string]string, error)

FitResources admits a release's declared resources against the daemon it runs on, before any effect (deploy.ResourceFitter): a part or need larger than the host is refused (AdmitResources). A Docker host holds each declaration exactly, so nothing is rounded: no part runs on a size of its own.

func (*Driver) Inspect

func (d *Driver) Inspect(ctx context.Context, p deploy.Placement) (bool, error)

Inspect asks the host whether the deployment's container is running; an absent container is not running, a host that cannot be asked is an error.

func (*Driver) Observe

func (d *Driver) Observe(ctx context.Context, p deploy.Placement) (deploy.Observation, error)

func (*Driver) Reconcile

func (d *Driver) Reconcile(ctx context.Context, p deploy.Placement, generation int64, art deploy.Artifact, key string, logf func(string, ...any), checkpoint deploy.Checkpoint) (deploy.Observation, error)

func (*Driver) Resume

func (d *Driver) Resume(ctx context.Context, p deploy.Placement, generation int64, noted map[string]any, logf func(string, ...any)) (deploy.Observation, error)

func (*Driver) Sample

func (d *Driver) Sample(ctx context.Context, in ReadinessSample, allowed func(context.Context) error) (deploy.Observation, error)

Sample asks one bounded readiness question of the exact running container. It neither settles a release nor restarts an application.

func (*Driver) Teardown

func (d *Driver) Teardown(ctx context.Context, p deploy.Placement, generation int64, td deploy.TakeDown) (deploy.TakenDown, error)

Teardown removes the recorded generation's container, verified by its labels, then everything else the deployment's list names (TearDownOwned). The container is the serving thing: failing to remove it fails the teardown, and nothing else is touched.

type HealthController

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

HealthController owns liveness for the deployments the apptown runs on Docker hosts: Docker restarts an exited process but never a running-but-hung one, and restarts a crashing one without limit.

func NewHealthController

func NewHealthController(deps HealthDependencies) *HealthController

func (*HealthController) Clock

func (c *HealthController) Clock(now func() time.Time)

Clock replaces the controller's clock, for tests of the crash-loop window.

func (*HealthController) Run

func (c *HealthController) Run(ctx context.Context)

Run sweeps until cancellation.

func (*HealthController) Seed

func (c *HealthController) Seed(container string, fails int)

Seed records observations for a container, for tests of the sweep.

func (*HealthController) Sweep

func (c *HealthController) Sweep(ctx context.Context)

healthSweep probes every standing env's public part once and acts on the clear-cut liveness failures. Errors are logged, never fatal — a controller that dies is worse than one that misses a tick.

func (*HealthController) Watching

func (c *HealthController) Watching(container string) bool

Watching says whether the controller holds observations for a container.

type HealthDependencies

type HealthDependencies struct {
	Watch      func(context.Context) []Watched                                           // the standing deployments the apptown runs on hosts it talks to
	PublicPart func(context.Context, Watched) *appcontract.Part                          // the running release's public part, nil when unreadable
	FrontDoor  func() map[string]string                                                  // the front-door signal a probe sends
	Record     func(ctx context.Context, w Watched, kind string, payload map[string]any) // the receipt of a restart or a hold
	Now        func() time.Time                                                          // the clock; nil means time.Now
	// AfterSweep runs once at the end of each sweep: the owner's reading of
	// what the daemons reported since the last (limit events). nil: none.
	AfterSweep func(context.Context)
}

HealthDependencies is what the controller asks of the world.

type Host

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

Host is the built-in Docker host (architecture.md §5.6, §11): the one boot sequence every path runs (previews, landings, releases, rebuilds), with what it needs of the world declared and supplied at construction. A standalone tool builds one from its own values; AppTown builds one over its secrets broker, dependency catalog, registry connectors, attached integrations and routes.

func NewHost

func NewHost(deps Dependencies) *Host

func (*Host) Boot

Boot runs the sequence for one target. The order is the contract: needs healthy → init to completion → parts → app → probe. What it says of a failure (the error, the app's last words, the front-page verdict) never holds a value AppTown generated for the boot's needs: those become Redacted wherever the boot runs, so no record or answer made from it carries one (deploy.ServiceSpec.Credentials).

func (*Host) PrepareImages

func (h *Host) PrepareImages(ctx context.Context, t BootRequest, c *appcontract.Plan) (*appcontract.Plan, error)

PrepareImages prepares each selected app and init image once, on the selected daemon. Standing containers run image IDs, never a tag another generation can replace. Static files travel in an image too; no runtime mount retains the staging directory.

func (*Host) ResolveStack

func (h *Host) ResolveStack(ctx context.Context, c *appcontract.Contract, override []deploy.ServiceSpec) (ResolvedStack, error)

resolveStack reads the contract's needs and fulfils them locally: emulator containers plus the env the app reads to use them. In cloud a provider fulfils the same needs with real resources; the app code is identical. An unknown need is refused with the one sentence every surface uses.

func (*Host) StartAppContainer

func (h *Host) StartAppContainer(ctx context.Context, t BootRequest, c *appcontract.Part, network string, secretEnv map[string]string) (int, error)

type HostInfo

type HostInfo struct {
	MemoryBytes int64
	CPUs        int
	DataRoot    string
}

HostInfo is what a daemon says it can give containers: its memory and CPUs (docker info: the host's, or its container's limits when the daemon itself runs in one), and the folder its data lives in.

func ReadHostInfo

func ReadHostInfo(ctx context.Context, dk Scope) (HostInfo, error)

ReadHostInfo asks the daemon what it can give containers.

type InstalledBrowser

type InstalledBrowser struct {
	ID     string
	Values map[string]string
}

InstalledBrowser is what a running static part was started with for /_apptown/env.js, read from the container itself.

func InspectBrowserValues

func InspectBrowserValues(ctx context.Context, dk Scope, name string) (InstalledBrowser, error)

InspectBrowserValues reads the browser values a container was started with. A missing, repeated or malformed value is ErrNoBrowserValues, never an empty set: an empty set is a fact the container must state.

type Inventory

type Inventory struct {
	Scope func(context.Context) (Scope, error)
	Also  []string // containers the host also reports by name (the caller's own database on its built-in host)
	// Images is the image references the deployments on the target
	// recorded (deploy.Owned of kind image), each asked for exactly.
	Images func(context.Context) ([]string, error)
}

Inventory answers what a Docker host holds: the standing containers named by AppTown, its volumes and networks, and image references, as the daemon reports them, over the host's scope so an attached host answers for itself. It is built for a target, not a deployment: it can look, never boot. What does not carry the scope's installation label confirms records only.

func (Inventory) Inventory

func (i Inventory) Inventory(ctx context.Context) ([]deploy.Resource, error)

type Names

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

Names are what one standing deployment's things on a host are called: its stack id (the owner label of its services, init containers and network), and every name built from it under its prefix.

func ByKey

func ByKey(id ids.ID) Names

ByKey names a deployment by its key: apptown-dep-<key>, apptown-svc-dep-<key>-<service>, and so on.

func NamesOf

func NamesOf(id ids.ID, deployment string) (Names, error)

NamesOf is the names of a deployment from its record: by its key, which a deployment not yet recorded does not have.

func (Names) App

func (n Names) App() string

App is the public app container.

func (Names) DataVolume

func (n Names) DataVolume() string

DataVolume is the app's data volume.

func (Names) Init

func (n Names) Init(name string) string

Init is an init container.

func (Names) NeedVolume

func (n Names) NeedVolume(need string) string

NeedVolume is the volume a need keeps its data in.

func (Names) Network

func (n Names) Network() string

Network is the stack's network.

func (Names) Service

func (n Names) Service(service string) string

Service is a need's or a non-public part's container.

func (Names) Stack

func (n Names) Stack() string

Stack is the deployment's stack id: the owner label value of its services, init containers and network.

type NeedCatalog

type NeedCatalog interface {
	// Fulfil refuses a need it cannot fulfil as declared with the sentence
	// the release and preview show (an unknown need, a withdrawn
	// declaration).
	Fulfil(ctx context.Context, needs []string, params map[string]map[string]string) (services []deploy.ServiceSpec, env map[string]string, err error)
	Data(ctx context.Context, capability string) (string, error)
}

NeedCatalog fulfils the contract's needs locally: emulator containers and the env the app reads to use them; Data is where an emulator keeps its data, "" for one that keeps none. A kind that cannot be read is an error, never "keeps none": a standing service remade without its data folder would start empty.

type Ownership

type Ownership struct {
	// Storage records engine identity separately from deletion ownership.
	Storage        deploy.StorageBindings
	RestoreStorage deploy.StorageRestore
	Record         func(deploy.Owned) error
	Needs          map[string]string
	// Recorded is the deployment's list as it stood before this boot: what
	// AppTown may delete (a synthetic need's volume, when its parameters
	// moved). Nothing else is ever deleted.
	Recorded []deploy.Owned
	// Persistent is a standing deployment's stack: its parts live with it
	// (class env, restarted with the host), never idle-reaped.
	Persistent bool
	// Info is the informational labels a standing deployment's things carry
	// for people (dockerlabel.Informational); nil for previews and runs.
	Info []string
}

Ownership is how a standing boot records what it creates. A nil Record records nothing: previews and runs are cleaned up by their own owners. Needs names the need services and where each keeps its data ("" keeps none).

type PageWitness

type PageWitness struct {
	Path   string `json:"path"`
	Host   string `json:"host,omitempty"`
	Status int    `json:"status,omitempty"` // 0: no answer
	Passed bool   `json:"passed"`
	// Verdict says what the answer means for a visitor, in a sentence.
	Verdict string `json:"verdict"`
}

PageWitness is the front-page check's record: the path that answered, the host name the request carried, the status, and the verdict. A pass is evidence like a refusal, not the absence of one.

type Prefix

type Prefix string

Names on the host are a protocol: the vhost router turns a hostname into a container name, the reapers decide fate from labels and prefixes, and the live fleet carries these exact strings. Every name a deployment on the built-in host uses is built here, with its inverse.

Prefix begins every name: Current. Previews and everything disposable are named by the id of what they serve (a change, a run, a step, a chat); a standing deployment by its key (Names).

const Current Prefix = "apptown-"

Current is what everything AppTown makes on a host is named with.

func (Prefix) BuildTag

func (p Prefix) BuildTag(container string) string

BuildTag: the local image a boot builds from a workspace's Dockerfile, keyed by the container it serves. The prefix marks it local: never pulled from a registry.

func (Prefix) DataVolume

func (p Prefix) DataVolume(container string) string

DataVolume: the named volume behind a container's dataDir (<prefix>data-<container>). A preview's dies with the preview; a deployment's IS the persistence.

func (Prefix) Init

func (p Prefix) Init(stackID, name string) string

Init: an init container on a stack (<prefix>init-<stack>-<name>).

func (Prefix) NeedVolume

func (p Prefix) NeedVolume(stackID, need string) string

NeedVolume is the named volume a standing deployment's need keeps its data in (<prefix>need-<stack>-<need>), made by AppTown before the need's container mounts it.

func (Prefix) Network

func (p Prefix) Network(stackID string) string

Network: a stack's network (<prefix>net-<stack>).

func (Prefix) Service

func (p Prefix) Service(stackID, service string) string

Service: a service container on a stack (<prefix>svc-<stack>-<service>).

type Prepared

type Prepared struct {
	Version int `json:"version"`
	// Contract is the selected contract the values were prepared for: the
	// boot runs it, and nothing else may use them (preparedSecrets).
	Contract *appcontract.Contract `json:"contract"`
	// Services replace the contract's sidecars (a workflow's services:).
	Services []deploy.ServiceSpec         `json:"services,omitempty"`
	Secrets  map[string]map[string]string `json:"secrets,omitempty"` // per consumer
	Receipts []SecretReceipt              `json:"receipts,omitempty"`
	Profile  string                       `json:"profile,omitempty"`
	Needs    []deploy.ServiceSpec         `json:"needs,omitempty"`
	NeedEnv  map[string]string            `json:"needEnv,omitempty"`
	NeedData map[string]string            `json:"needData,omitempty"`
	// Env is the attached integrations' server environment: it may hold
	// secrets, and is never public.
	Env []string `json:"env,omitempty"`
	// SecretsFingerprint identifies Secrets and Env without revealing them:
	// a keyed digest the caller that holds the key sets ("" when both are
	// empty). A secret's version does not always change with its value (an
	// Infisical value, a built-in one set again), so the values themselves
	// are what a changed secret or integration value changes, and with it
	// the preview's identity.
	SecretsFingerprint string              `json:"secretsFingerprint,omitempty"`
	BrowserEnv         string              `json:"browserEnv"`
	FrontDoor          map[string]string   `json:"frontDoor,omitempty"`
	Origins            string              `json:"origins,omitempty"`
	Registry           *RegistryCredential `json:"registry,omitempty"`
}

Prepared is everything a boot reads beyond its tree and its Docker, resolved before the boot (design/operations/workers.md, "Previews on the worker"): the secrets per consumer, the needs as the services and environment that fulfil them, the integration environment, the browser values, the routes, and the one registry login. A machine that boots it reads nothing else; Dependencies gives a Host exactly these values.

func PrepareBoot

func PrepareBoot(ctx context.Context, deps Dependencies, registry *RegistryCredential, slug, deployment, ws string, c *appcontract.Contract) (Prepared, error)

PrepareBoot resolves everything a boot of c from ws reads, through deps, for deployment ("" is preview), with the project's registry login. A need the catalog does not know, a required secret nothing provides, or browser values that cannot be read for a static site stop it here, as they would stop the boot.

func (Prepared) Dependencies

func (p Prepared) Dependencies(probe Prober, images toolversions.Images) Dependencies

Dependencies are the prepared values as a Host's dependencies, with the machine's own probe and the images of one tool versions snapshot.

func (Prepared) Public

func (p Prepared) Public() PublicPrepared

Public is the prepared boot without its secret values, integration environment or login.

type Probe

type Probe struct{ Settle time.Duration } // Settle 0 is the three-second production default

Probe owns the beat between an app's first answer and the second that proves it stayed up. A nil prober retains the three-second production default; a test can configure its own instance without changing other apps.

func (*Probe) Check

func (p *Probe) Check(ctx context.Context, dk Scope, container, url string, timeout time.Duration, probe RenderedProbe) (bool, string)

check answers "is the app actually up?": an HTTP response from the app itself, still alive after a settle window. A raw TCP dial is NOT evidence — Docker Desktop's port proxy accepts connections whether or not anything inside the container listens, so a dead app would pass such a health gate in one second. On failure the container's log tail is returned so the crash reaches ${{feedback.latest}} as rework feedback instead of dying unobserved.

type Prober

type Prober interface {
	Check(ctx context.Context, dk Scope, container, url string, timeout time.Duration, probe RenderedProbe) (bool, string)
}

Prober answers "is the app actually up?" for a container at a URL.

type PublicPrepared

type PublicPrepared struct {
	Version            int                   `json:"version"`
	Contract           *appcontract.Contract `json:"contract"`
	Services           []deploy.ServiceSpec  `json:"services,omitempty"`
	Receipts           []SecretReceipt       `json:"receipts,omitempty"`
	Profile            string                `json:"profile,omitempty"`
	SecretsFingerprint string                `json:"secretsFingerprint,omitempty"`
	Needs              []deploy.ServiceSpec  `json:"needs,omitempty"`
	NeedEnv            map[string]string     `json:"needEnv,omitempty"`
	NeedData           map[string]string     `json:"needData,omitempty"`
	BrowserEnv         string                `json:"browserEnv"`
	FrontDoor          map[string]string     `json:"frontDoor,omitempty"`
	Origins            string                `json:"origins,omitempty"`
}

PublicPrepared is the part of a prepared boot that is not secret: what a preview's record keeps, and what its identity is a digest of. The secret receipts (names, stores and versions, no values) and the fingerprint of the secret values and integration environment are in it, so a changed binding, secret or integration value is a new identity and a running preview is not kept with the old one.

func (PublicPrepared) Digest

func (p PublicPrepared) Digest() string

Digest identifies the public prepared values, the contract among them: with the source, a preview incarnation's identity.

type ReadinessSample

type ReadinessSample struct {
	Placement       deploy.Placement
	Artifact, Image string
	Part            *appcontract.Part
	Timeout         time.Duration
}

ReadinessSample is the selected generation's retained intent and image. The application owner resolves its immutable source; no working tree is read.

type RecentLog

type RecentLog struct {
	Text      string
	Truncated bool
}

RecentLog is what one read of a container's log returned: its newest lines, oldest first. Truncated says older output may exist that is not shown: the read reached its line bound, or was cut to its size bound.

func ReadRecentLog

func ReadRecentLog(ctx context.Context, dk Scope, container string) (RecentLog, error)

ReadRecentLog reads the newest LogMaxLines lines of a container's output (stdout and stderr, with Docker's timestamps), cut to the newest LogMaxBytes, within LogReadWithin. A container that is absent is ErrContainerAbsent; any other failure is ErrLogUnreadable with only a timeout or cancellation said.

type RecordedImages

type RecordedImages struct {
	Parts, Init map[string]string
	// Login is the registry credential images by digest are pulled with,
	// written into a Docker configuration of the pull's own under Scratch
	// (WithBootConfig), never logged in where another command could find
	// it. nil pulls anonymously.
	Login   *RegistryCredential
	Scratch string
}

RecordedImages are a release's images by part and by init step: image IDs as recorded on the daemon that built them, or images by digest in the release's registry (<repository>@sha256:<hex>), which any daemon pulls.

func (*RecordedImages) Present

func (r *RecordedImages) Present(ctx context.Context, dk Scope) error

Present verifies every recorded image is on the daemon under its ID.

type Refusing

type Refusing struct{ Attached Client }

Refusing is the client of an AppTown with no local Docker daemon: every call is refused with ErrNoLocalBackend. An admitted target's scope (WithHost) gets Attached instead, which passes that target's --host on every call, so neither the ambient context nor DOCKER_HOST ever chooses a daemon.

func (Refusing) NoLocalBackend

func (Refusing) NoLocalBackend()

NoLocalBackend marks a client that stands for no daemon: Refusing, or a test's recording stand-in for it.

func (Refusing) Run

type RegistryCredential

type RegistryCredential struct {
	Host, Username, Token string
}

RegistryCredential is the project's one registry login, for one boot.

type RegistryLogin

type RegistryLogin interface {
	Login(ctx context.Context, dk Scope, imageRef string) error
}

RegistryLogin logs the daemon into the registry an image is pulled from. A login that fails, or a credential that cannot be read, is an error.

type RenderedProbe

type RenderedProbe struct {
	Policy      *appcontract.HealthPolicy
	PolicyError error
	Path        string            // HTTP path to hit (default "/")
	Headers     map[string]string // front-door shaping (ingress.go), nil = probe naked
	Expect      int               // required HTTP status; 0 = below 400 (appcontract.Ready)
	Release     string            // a release identity the answer must serve (appcontract.ServesRelease); "" = none
	Grace       time.Duration     // startupGrace floor — extends the probe deadline
	// The controller's liveness variants (probeApp/cold-boot uses only the HTTP
	// fields above): a TCP connect, or a command run inside the container.
	TCP  bool     // dial the port instead of an HTTP GET
	Exec []string // `docker exec` this command; exit 0 = healthy
}

RenderedProbe is one deployment's concrete readiness probe, derived from a part's intent (or a synthesized default) shaped by the ingress contract. It is what probeApp actually executes — the render's whole job is turning topology- neutral intent into this.

func RenderColdBootProbe

func RenderColdBootProbe(pub *appcontract.Part, frontDoor map[string]string) RenderedProbe

renderColdBootProbe derives the cold-boot READINESS probe for the public part (design/subsystems/healthchecks.md §4.3, cold-boot row). Cold-boot readiness is what bit us: an app hardened for behind-the-proxy 301s a naked hit, so the probe must reproduce the front-door signal (frontDoor) the ingress contract supplies.

Inputs are pure: the public part (nil when the contract could not be read) and the deployment's front-door headers (ingress.go). Declaring nothing yields the §8 default — GET / shaped by the front door — so a naive app boots without writing a probe line. Topology (the header) never comes from the app.

func RenderLivenessProbe

func RenderLivenessProbe(pub *appcontract.Part) RenderedProbe

RenderLivenessProbe derives the LIVENESS probe for the public part — the one the health controller (§6) acts on. Liveness drives RESTART, so its default is deliberately dependency-free (§8): a TCP connect to the mapped port, which on a real host means "the process is up and listening." That default almost never false-restarts a healthy app; a part that wants hang-detection declares an http/exec liveness explicitly. Never carries checksDeps (guardrail §5.1, enforced at parse).

type ResolvedNeed

type ResolvedNeed struct {
	deploy.ServiceSpec
	Data string
}

ResolvedNeed is a fulfilled need plus its emulator's data path.

type ResolvedStack

type ResolvedStack struct {
	// Plan owns the resolved execution values for each consumer.
	Plan *appcontract.Plan
	// NeedNames retain only the output names, for scoped-secret admission.
	NeedNames []string
	// Services are the sidecars (the contract's, or a workflow override)
	// followed by the needs' emulators — the stack, in start order.
	Services []deploy.ServiceSpec
	// Needs are the fulfilled needs (the tail of Services) with where each
	// emulator keeps its data; the intranet gives each a named volume.
	Needs []ResolvedNeed
	// Secrets is the broker's delivery for this boot: per consumer, the
	// values to inject; and the receipts (names, stores, versions — never
	// values) the boot records.
	Secrets Delivery
}

ResolvedStack: what a contract runs beside, fulfilled for the docker provider — the one answer every path (and the intranet's compose) shares.

type Routes

type Routes interface {
	FrontDoorHeaders() map[string]string
	PublicOrigins(ctx context.Context) string
}

Routes is how an app is reached: the front-door headers a probe sends, and the origins a browser reaches the app at.

type Runtime

type Runtime struct {
	ID      string            `json:"id"`
	Image   string            `json:"image"`
	Running bool              `json:"running"`
	Labels  map[string]string `json:"labels"`
	// MemoryLimit is the memory the container is held to, in bytes; 0 is no
	// limit.
	MemoryLimit int64 `json:"memoryLimit"`
	// State is what the daemon says of the container's process: nil when
	// the answer carried none, which is "not reported", never a clean exit.
	State *ContainerState `json:"state,omitempty"`
}

func Inspect

func Inspect(ctx context.Context, dk Scope, name string) (Runtime, error)

type Scope

type Scope struct {
	Client   Client
	Host     string // DOCKER_HOST, "" for AppTown's own daemon
	Hostname string // the attached host's address, for probes and plain URLs
	Domain   string // the attached host's ingress domain, "" when it has none
	// Config is a Docker configuration folder of this scope's own, for one
	// boot (WithBootConfig); "" is the ambient one.
	Config string
	// Lifetime bounds every command through this scope: when it ends, each
	// command still running is stopped (a boot's lifetime, WithLifetime). nil
	// is no bound beyond each command's own.
	Lifetime context.Context
	// Now is the clock a container's apptown.created label is stamped from,
	// which the reaper judges a container's age by; nil is the real one.
	Now func() time.Time
	// NoStreams is a daemon reached through a proxy that carries plain
	// requests and answers but not attached streams (Portainer's Docker
	// proxy): a step that streams runs as a job instead (RunStep).
	NoStreams bool
	// Redact replaces the values a boot generated (its needs' credentials)
	// in what a failure keeps of a container's own output, before that is
	// cut short (Boot sets it once its needs are resolved); nil keeps the
	// text. It is never applied to what AppTown compares or acts on.
	Redact func(string) string
	// Instance is the installation id every container, volume and network
	// made through this scope is labelled with (dockerlabel.Instance): the
	// inventory reports as not accounted for only what carries it. "" labels
	// nothing, and then nothing reads as this installation's.
	Instance string
}

Scope is which Docker daemon a command talks to: AppTown's own (Host == "") or an attached host's, reached over SSH by the alias the AppTown keeps for it (target_attach.go). The environment path carries one from the driver down through boot, parts, services and probes, so a standing deployment on a droplet is booted exactly like one here; every other caller receives the local scope assembled in App.New.

func LocalCLI

func LocalCLI(binary string) Scope

LocalCLI is the scope of the docker binary run directly against the daemon its environment names (apptown-worker, and tests): the one place a program with no daemon of its own of this kind gets its Docker calls.

func (Scope) Absent

func (dk Scope) Absent() bool

Absent reports AppTown's own daemon on an AppTown that has none.

func (Scope) AgentImageLabel

func (dk Scope) AgentImageLabel(ctx context.Context, image, label string) string

AgentImageLabel reads a version label baked into the agent image — receipts should say which runtimes ran, and the mutable tag doesn't.

func (Scope) AgentRuntimeVersion

func (dk Scope) AgentRuntimeVersion(ctx context.Context, image string) string

AgentRuntimeVersion reads the pi version label baked into the agent image (cached per image ID — receipts should say which pi ran, and the mutable tag "apptown-agent" doesn't).

func (Scope) Build

func (dk Scope) Build(ctx context.Context, args ...string) ([]byte, error)

Build runs `docker build args...` on dk's daemon by the one build rule (internal/dockerbuild): that daemon's own builder named explicitly, the extra certificates as the build's secret, AppTown's label. Every build of a project's source AppTown makes on a daemon goes through it, so the source and its build go to the daemon AppTown selected and nowhere else.

func (Scope) BuildCommand

func (dk Scope) BuildCommand(ctx context.Context, req Command) ([]byte, error)

BuildCommand is Build with the command's other settings (where its output goes): req.Args are the build's own arguments, its context last.

func (Scope) BuildImages

func (dk Scope) BuildImages(ctx context.Context, container string) ([]string, error)

BuildImages lists the local build images made for one container: its own (its BuildTag) and its parts' and release generations' (its BuildTag +"-…"). The caller decides which belong to it: the "-…" form can also match another owner's longer name.

func (Scope) Command

func (dk Scope) Command(ctx context.Context, req Command) ([]byte, error)

func (Scope) DialAddress

func (dk Scope) DialAddress(hostPort int) string

DialAddress is host:port for a published port: loopback here, the attached host by address there.

func (Scope) EnsureRunning

func (dk Scope) EnsureRunning(ctx context.Context, name string, runArgs []string) error

EnsureRunning makes the named container run: a running one is left alone, a stopped one is started, and a missing one is created with `docker run -d` and runArgs (which must name it). Another process may create it at the same moment; a failed run that leaves the container existing is treated as that race and the existing container is started instead. Docker reserves the name before the winner's container can be inspected, so after a name conflict the loser waits a bounded time for it to appear: test binaries starting together on a machine without the image (a fresh CI runner) all pull it, and one that asked once read the winner's container as missing.

func (Scope) ExecResult

func (dk Scope) ExecResult(ctx context.Context, container string, s containerresult.Spec) ([]byte, error)

ExecResult runs s.Script in the running container and returns its answer, read from a file it wrote there (containerresult.RunIn).

func (Scope) Exists

func (dk Scope) Exists(ctx context.Context, args ...string) (bool, error)

Exists asks the daemon whether an object is there (args: the inspect command, such as "volume", "inspect", name). Only the daemon's own "no such" answer is absence; any other failure is an error, never "gone".

func (Scope) FromFile

func (dk Scope) FromFile(ctx context.Context, path string, args ...string) ([]byte, error)

func (Scope) FrontDoor

func (dk Scope) FrontDoor(servingLabel, deployment string, hostPort int) string

FrontDoor is where people reach a deployment on an attached host: main under the target's ingress domain when it has one (RoutesDeployment, design/subsystems/ingress.md), else the host by address and published port.

func (Scope) Image

func (dk Scope) Image(ctx context.Context, ref string) (execution.ImageAnswer, bool, error)

Image is the one image probe (execution.InspectImage): found with its ID and labels, absent (the daemon says there is no such image), or an error (the daemon could not be asked or its answer not read). Callers decide what an error means; none reads it as absent.

func (Scope) ImageDigest

func (dk Scope) ImageDigest(ctx context.Context, imageRef string) string

ImageDigest resolves a pulled image ref to its content digest — the receipt that names the exact bytes.

func (Scope) Installs

func (dk Scope) Installs(installation string) bool

Installs reports whether a thing labelled with installation was made by this scope's installation; with no id of its own, nothing is.

func (Scope) InstanceLabel

func (dk Scope) InstanceLabel() []string

InstanceLabel is the --label argument naming this scope's installation; none when it has no id.

func (Scope) Labels

func (dk Scope) Labels(class, owner string) []string

Labels tags a spawned container so the reaper (design/subsystems/container-lifecycle.md) identifies it by class + owner without name-parsing, and judges its age by apptown.created, stamped from the scope's clock. class is one of preview|service|step|dind|console|env; env/infra are never reaped.

func (Scope) Lines

func (dk Scope) Lines(ctx context.Context, args ...string) []string

Lines runs a listing and returns its non-empty Lines. A non-zero exit is logged — a reaper that cannot list is a reaper that silently leaks — and yields nothing.

func (Scope) List

func (dk Scope) List(ctx context.Context, args ...string) ([]string, error)

List is Lines for a caller that must tell an empty answer from a failed one.

func (Scope) ListLabelled

func (dk Scope) ListLabelled(ctx context.Context, key string, labels ...string) (map[string]string, error)

ListLabelled lists the containers carrying all of labels (key=value), each with the value of its label key ("" when it has none).

func (Scope) OK

func (dk Scope) OK(ctx context.Context, args ...string) bool

func (Scope) ProbeURL

func (dk Scope) ProbeURL(hostPort int) string

ProbeURL is where AppTown reaches a container's published port: its own loopback, or the attached host by address.

func (Scope) PublishAddress

func (dk Scope) PublishAddress() string

PublishAddress is the address a container's port is published on. On AppTown's own daemon it is loopback: AppTown is on the same host and its proxy (vhost.go) is the only front door, so a wider bind would open a LAN path around the proxy's header sanitisation. On an attached host it is every interface: AppTown probes the app there, and people reach it there when the host has no domain, at the host's address and the published port (ProbeURL, FrontDoor). A loopback bind on that host is reachable from neither. Who else may reach the port is the host's firewall, the operator's.

func (Scope) ReapStack

func (dk Scope) ReapStack(ctx context.Context, stackID string)

ReapStack removes a throwaway stack: every container labelled as owned by it (its services, and any init container still standing), then its network. Exact label matches — nothing is reaped by name coincidence.

func (Scope) Remote

func (dk Scope) Remote() bool

func (Scope) Remove

func (dk Scope) Remove(ctx context.Context, container string) error

Remove, RemoveNetwork and RemoveVolume treat an object already gone as removed. A failure is logged and returned; callers that act on it (a deleted project's cleanup) retry and report it, the rest may ignore it.

func (Scope) RemoveBuildImagesOf

func (dk Scope) RemoveBuildImagesOf(ctx context.Context, container string) (inUse bool, err error)

RemoveBuildImagesOf removes the build images made for one container (a preview's: its app's and its parts'), never forcing: inUse says one a container still uses stayed.

func (Scope) RemoveDisposable

func (dk Scope) RemoveDisposable(ctx context.Context, container string) error

RemoveDisposable removes a disposable container (a preview's app, a deleted project's deployment) with its anonymous volumes and its named data volume: nothing of it carries over to the next one of its name.

func (Scope) RemoveDisposableStack

func (dk Scope) RemoveDisposableStack(ctx context.Context, stackID string) error

RemoveDisposableStack is RemoveStack for a disposable stack (a preview's): each container's named data volume goes too.

func (Scope) RemoveImageUnlessUsed

func (dk Scope) RemoveImageUnlessUsed(ctx context.Context, ref string) (inUse bool, err error)

RemoveImageUnlessUsed is RemoveUnusedImage for a caller that reports what it removed: inUse says a container still uses the image, which therefore stays.

func (Scope) RemoveLabelled

func (dk Scope) RemoveLabelled(ctx context.Context, labels ...string) ([]string, error)

RemoveLabelled removes every container carrying all of labels (key=value), with its anonymous volumes, and returns those Docker still lists afterwards. Only throwaway containers (a step's agents, a folder's writers) are removed this way. A daemon that cannot be asked is an error: it confirms nothing.

func (Scope) RemoveNetwork

func (dk Scope) RemoveNetwork(ctx context.Context, network string) error

func (Scope) RemoveStack

func (dk Scope) RemoveStack(ctx context.Context, stackID string) error

RemoveStack is ReapStack for a caller that must know it worked: a failed listing or removal is returned, so a cleanup cannot record a stack removed while its services still run. Its containers are throwaway and go with their anonymous volumes; a named volume stays.

func (Scope) RemoveUnusedImage

func (dk Scope) RemoveUnusedImage(ctx context.Context, ref string) error

RemoveUnusedImage removes an image no container uses. One a container still uses, running or stopped, is kept, and that is not a failure: the daemon refuses it without force, and nothing here forces.

func (Scope) RemoveVolume

func (dk Scope) RemoveVolume(ctx context.Context, volume string) error

func (Scope) RemoveWithVolumes

func (dk Scope) RemoveWithVolumes(ctx context.Context, container string) error

RemoveWithVolumes removes a container with its anonymous volumes, for a container whose data goes with it.

func (Scope) Result

func (dk Scope) Result(ctx context.Context, s containerresult.Spec) ([]byte, error)

Result runs s.Script in a throwaway container of s.Image on this scope's daemon and returns its answer, read from a file in the container once it has exited, never from its output (containerresult.Run).

func (Scope) RoutesDeployment

func (dk Scope) RoutesDeployment(deployment string) bool

RoutesDeployment says whether the host's ingress serves this deployment at <slug>.<domain>: the host has an ingress domain (only an attached host does; a scope naming it for its address only, as attachedFrontDoor builds, has no Host), and the deployment is main. The project's name is main's, as the main tier domain is on AppTown's own host (vhost.go): Traefik joins every container that declares one router into one service and splits requests between them, so a second deployment carrying main's route would take main's visitors (soak finding 55). Any other deployment is reached at the host and its published port.

func (Scope) Run

func (dk Scope) Run(ctx context.Context, args ...string) ([]byte, error)

func (Scope) RunStep

func (dk Scope) RunStep(ctx context.Context, s Step) ([]byte, error)

RunStep runs a step. A daemon reached with attached streams runs it as one command. One reached through a proxy that carries only plain requests (Portainer's, Scope.NoStreams) runs it as a job: a container made for it (an exec becomes a container of the running one's image, its environment, sharing its network and its volumes), its input copied in, started, waited for, its exit status read, its output copied out, and removed whatever happened. The output is what the error carries: stderr for a streamed step, the job's log for a job.

A step's output is a copy of data, which the container's stdout can lose at its end and still exit 0. So its command is framed (containerresult.Framed): it ends with a trailer, its byte count and sha256, which the step's output is held to before RunStep returns. A copy without its trailer, or whose trailer does not match, is the step's error (containerresult.ErrCutShort), in both forms.

func (Scope) Running

func (dk Scope) Running(ctx context.Context, container string) bool

func (Scope) StopStep

func (dk Scope) StopStep(ctx context.Context, stepID ids.ID) ([]string, error)

StopStep removes every container a step is running: each is named execution.StepContainer, so it begins execution.StepContainerPrefix. On failure it returns only the removals already confirmed, plus the error.

func (Scope) Text

func (dk Scope) Text(ctx context.Context, args ...string) string

func (Scope) ToFile

func (dk Scope) ToFile(ctx context.Context, path string, args ...string) error

func (Scope) WithBootConfig

func (dk Scope) WithBootConfig(ctx context.Context, scratch string, login *RegistryCredential) (Scope, func() error, error)

WithBootConfig is dk with a Docker configuration of its own, for one boot, in a folder under scratch (the boot's own place, which the caller sweeps: SweepBootConfigs). It holds the boot's one registry login, and nothing else: no command of the boot reads the machine's configuration or its credential helpers. It selects the same Docker as the ambient configuration: a named context in use is carried over, its records shared. done removes it, and answers whether it could.

Docker looks for a native credential helper (a keychain) only when a configuration holds no credentials at all, and then keeps logins there, outside the folder. The configuration is therefore written with its credentials, never by `docker login`, and a boot without a login holds one entry for a host that does not exist, so nothing is looked up.

func (Scope) WithHost

func (dk Scope) WithHost(host, hostname, domain string) Scope

func (Scope) WithLifetime

func (dk Scope) WithLifetime(ctx context.Context) Scope

WithLifetime is dk with every command bounded by ctx.

type Sealed

type Sealed struct {
	// Fill fills the stack's new, empty needs from a copy, on its own
	// network, after they are healthy and before any init step reads them.
	Fill func(network string) error
	// ProbeImage runs the in-network probe; it needs a shell, nc and awk
	// (busybox has them).
	ProbeImage string
	// Host is the host name the probe's requests carry: the deployment
	// the rehearsal stands in for, as its visitors reach it.
	Host string
}

Sealed is what a sealed boot needs beyond an ordinary one.

func (*Sealed) Get

func (s *Sealed) Get(ctx context.Context, dk Scope, network, container string, port int, path string) (int, error)

Get asks the app container at port, on the sealed stack's network, for path, and returns the status it answers. A readiness or data check is judged on that answer: a redirect is its status, never where it leads (a data path that redirects to a sign-in page has not read the data). The front page follows redirects to the same host (Page). Nothing but the status is returned.

func (*Sealed) Page

func (s *Sealed) Page(ctx context.Context, dk Scope, network, container string, port int) (int, error)

Page asks for the root as a visitor arrives, following same-host redirects (to /login, /dashboard) as the page probe does (check.ProbePage), and returns the status it ends on. A redirect to another host is the answer as it stands and is never followed, so one naming production never reaches production; every request goes to the rehearsal's container.

type SecretReceipt

type SecretReceipt struct {
	Name      string   `json:"name"`
	Store     string   `json:"store"`
	Version   string   `json:"version"`
	Consumers []string `json:"consumers"`
	Generated bool     `json:"generated,omitempty"`
}

SecretReceipt is what a boot records about one delivered secret: names, stores, versions, never values.

type SecretResolver

type SecretResolver interface {
	Resolve(ctx context.Context, slug, deployment, ws string, c *appcontract.Contract, allowed func(context.Context) error) (Delivery, error)
}

SecretResolver resolves the app's declared secrets for one boot: per consumer, the values to inject, and the receipts (never values) the boot records. A resolver that registers credentials calls allowed again before each registration; nil carries no additional check. Boot checks before resolution.

type SourceInputs

type SourceInputs struct {
	Version  int                  `json:"version"`
	Revision string               `json:"revision"`
	Services []deploy.ServiceSpec `json:"services,omitempty"`
}

Selected configuration, before resolving credentials. Only this request and its hash are durable; a staged directory belongs to one execution.

type Step

type Step struct {
	Exec    string   // the running container to run in
	Image   string   // else: a throwaway container of this image
	Options []string // docker run options for Image (--network, -v, --volumes-from)
	Env     []string
	// Command is the shell command; Argv, when set instead, runs as it is.
	Command string
	Argv    []string
	Stdin   io.Reader
	Stdout  io.Writer
	// Name names the container a job makes (a person finds a job a stopped
	// AppTown left by it, and by its labels); "" lets the daemon name it.
	Name string
}

Step is one command of a data copy run against a daemon: in a running container (docker exec), or in a throwaway container of an image with docker run options (a network, a volume). Its input, when it reads one, is a file on stdin; its output, when it writes one, is a file from stdout. Env names the variables it is given, NAME=value: the values reach the container by name only, never as arguments.

type Watched

type Watched struct {
	DeploymentID, ProjectID ids.ID                // the selected records, never resolved again by name
	Identity                deploy.DockerIdentity // the settled deployment and generation on this host
	Slug                    string                // the application
	Name                    string                // the deployment
	HostPort                int
	Container               string
	Docker                  Scope // the daemon it stands on
}

Watched is one standing deployment the controller probes.

Directories

Path Synopsis
Package dockerfake models the small Docker daemon contract used by tests.
Package dockerfake models the small Docker daemon contract used by tests.
Package dockertest runs the docker CLI against this machine's own daemon for tests that set up, inspect or clean up containers, images and networks the code under test does not.
Package dockertest runs the docker CLI against this machine's own daemon for tests that set up, inspect or clean up containers, images and networks the code under test does not.

Jump to

Keyboard shortcuts

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