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
- Variables
- func AdmitDisk(ctx context.Context, dk Scope, image string) error
- func AdmitResources(ctx context.Context, dk Scope, c *appcontract.Contract) error
- func BrowserEnvScript(values string) string
- func BuildFailure(operation string, output []byte, cause error) error
- func ChangeBuildImages() []string
- func ChangeOfBuildImage(repository string) (ids.ID, bool)
- func ChangeStackID(changeID ids.ID) string
- func ConfineStaticExport(ctx context.Context, root, output string) (string, error)
- func ContainerHostPort(ctx context.Context, dk Scope, name string, inner int) (int, error)
- func ContainerOfDataVolume(volume string) (string, bool)
- func ContractFileAt(ctx context.Context, repo, sha string) ([]byte, error)
- func EnsureStandingServices(ctx context.Context, dk Scope, stackID string, svcs []deploy.ServiceSpec, ...) (string, error)
- func ExactOrigin(raw string) (string, error)
- func ExportStaticBuild(ctx context.Context, dk Scope, contextDir string, sb appcontract.StaticBuild) (site string, done func(), err error)
- func HandVolumeToImageUser(ctx context.Context, dk Scope, volume, image, chownImage string)
- func IntranetNeeds(resolved []ResolvedNeed) []deploy.IntranetNeed
- func IsDigestReference(ref string) bool
- func IsLocalBuildTag(image string) bool
- func IsNamedVolume(volume string) bool
- func IsPreviewName(name string) bool
- func IsWorkPreviewLabel(label string) bool
- func IsWorkPreviewName(name string) bool
- func LoginRegistry(ctx context.Context, dk Scope, host, username, token, image string) error
- func MemoryUsage(ctx context.Context, dk Scope, names []string) (map[string]int64, error)
- func Named(name string) bool
- func ObserveExistingStorage(ctx context.Context, dk Scope, stackID, path string, svc deploy.ServiceSpec, ...) (deploy.StorageBinding, error)
- func ObserveStorageEngine(ctx context.Context, dk Scope, container, path, volume string) (string, string, error)
- func PackStaticBuild(ctx context.Context, dk Scope, contextDir string, sb appcontract.StaticBuild, ...) error
- func ParseImageUser(s string) (uid, gid string, ok bool)
- func ParsePreviewChangeID(name string) (ids.ID, bool)
- func PreparePreviewBuilds(ctx context.Context, dk Scope, ws, name string, c *appcontract.Plan) error
- func PrepareSource(ctx context.Context, repo, revision, slug string, ...) (deploy.Artifact, func(), error)
- func PreviewChangeName(changeID ids.ID) string
- func PreviewLabelName(label string) string
- func PreviewRunName(runID ids.ID) string
- func ProbeLiveness(ctx context.Context, dk Scope, container string, hostPort int, ...) bool
- func PruneBuiltImages(ctx context.Context, dk Scope) error
- func ReadContractAt(ctx context.Context, repo, sha string) (*appcontract.Contract, error)
- func ReadDisk(ctx context.Context, dk Scope, image, dataRoot string) (diskspace.Space, error)
- func ReadSelectedContract(root string) (*appcontract.Contract, error)
- func ReadWorkspaceContract(ws string) (*appcontract.Contract, error)
- func ReapPreviewOrphans(ctx context.Context, dk Scope)
- func RecordBoot(ctx context.Context, dk Scope, id deploy.DockerIdentity, ...) (deploy.Observation, error)
- func RefusesHealth(c *appcontract.Contract, publicOnly bool) error
- func RelativePath(root, path string) (string, error)
- func ReleasePreviewLabel(slug string, number int64) string
- func ReleaseStackID(slug string, number int64) string
- func RemovePreview(ctx context.Context, dk Scope, name, stack string) error
- func ResourceAdmissionContract(c *appcontract.Contract, services []deploy.ServiceSpec) *appcontract.Contract
- func ResourceArgs(r appcontract.Resources) []string
- func RestoreSource(ctx context.Context, repo, slug, raw string) (deploy.Artifact, func(), error)
- func Resume(ctx context.Context, dk Scope, p deploy.Placement, generation int64, ...) (deploy.Observation, error)
- func RunStepStackID(stepID ids.ID) string
- func RunningMemoryUsage(ctx context.Context, dk Scope) (map[string]int64, error)
- func SameContract(a, b *appcontract.Contract) bool
- func SelectedPath(root, path string) (string, error)
- func ServiceDrift(ctx context.Context, dk Scope, cname string, svc deploy.ServiceSpec) ([]string, error)
- func SourceArtifact(source deploy.Source, services []deploy.ServiceSpec) (deploy.Artifact, error)
- func SourceAt(ws, commit, slug string, services []deploy.ServiceSpec) (deploy.Artifact, error)
- func SourceServices(art deploy.Artifact) []deploy.ServiceSpec
- func StackOfNetwork(network string) (string, bool)
- func StagedBuildContext(ctx context.Context, ws, buildContext string) (string, func(), error)
- func StaleEndpoint(out string) bool
- func StartServices(ctx context.Context, dk Scope, id string, svcs []deploy.ServiceSpec) (string, func(), error)
- func StaticExportArgs(target, contextDir, dest string) []string
- func StaticExportCheckScript(export, output string) string
- func StaticServerCommand(port int) []string
- func StaticSiteDockerfile(server string, port int) string
- func SweepBootConfigs(scratch string) error
- func TearDownOwned(ctx context.Context, dk Scope, owned []deploy.Owned, serving string, ...) deploy.TakenDown
- func TrimBuildCache(ctx context.Context, dk Scope) error
- func VerifyIdentity(id deploy.DockerIdentity, runtime Runtime, image string) error
- func VisitorHost(address string) string
- func VolumeAt(ctx context.Context, dk Scope, container, path string) (string, error)
- func WorktreeFingerprint(ws string) string
- type BootError
- type BootRequest
- type BootResult
- type Booter
- type CLI
- type Client
- type Command
- type ContainerEvent
- type ContainerLimit
- type ContainerState
- type Contributions
- type DataMount
- type Delivery
- type Dependencies
- type Driver
- func (d *Driver) Controls() deploy.Controls
- func (d *Driver) FitResources(ctx context.Context, c *appcontract.Contract) (map[string]string, error)
- func (d *Driver) Inspect(ctx context.Context, p deploy.Placement) (bool, error)
- func (d *Driver) Observe(ctx context.Context, p deploy.Placement) (deploy.Observation, error)
- func (d *Driver) Reconcile(ctx context.Context, p deploy.Placement, generation int64, art deploy.Artifact, ...) (deploy.Observation, error)
- func (d *Driver) Resume(ctx context.Context, p deploy.Placement, generation int64, ...) (deploy.Observation, error)
- func (d *Driver) Sample(ctx context.Context, in ReadinessSample, allowed func(context.Context) error) (deploy.Observation, error)
- func (d *Driver) Teardown(ctx context.Context, p deploy.Placement, generation int64, td deploy.TakeDown) (deploy.TakenDown, error)
- type HealthController
- type HealthDependencies
- type Host
- func (h *Host) Boot(ctx context.Context, t BootRequest, c *appcontract.Contract) (BootResult, error)
- func (h *Host) PrepareImages(ctx context.Context, t BootRequest, c *appcontract.Plan) (*appcontract.Plan, error)
- func (h *Host) ResolveStack(ctx context.Context, c *appcontract.Contract, override []deploy.ServiceSpec) (ResolvedStack, error)
- func (h *Host) StartAppContainer(ctx context.Context, t BootRequest, c *appcontract.Part, network string, ...) (int, error)
- type HostInfo
- type InstalledBrowser
- type Inventory
- type Names
- type NeedCatalog
- type Ownership
- type PageWitness
- type Prefix
- func (p Prefix) BuildTag(container string) string
- func (p Prefix) DataVolume(container string) string
- func (p Prefix) Init(stackID, name string) string
- func (p Prefix) NeedVolume(stackID, need string) string
- func (p Prefix) Network(stackID string) string
- func (p Prefix) Service(stackID, service string) string
- type Prepared
- type Probe
- type Prober
- type PublicPrepared
- type ReadinessSample
- type RecentLog
- type RecordedImages
- type Refusing
- type RegistryCredential
- type RegistryLogin
- type RenderedProbe
- type ResolvedNeed
- type ResolvedStack
- type Routes
- type Runtime
- type Scope
- func (dk Scope) Absent() bool
- func (dk Scope) AgentImageLabel(ctx context.Context, image, label string) string
- func (dk Scope) AgentRuntimeVersion(ctx context.Context, image string) string
- func (dk Scope) Build(ctx context.Context, args ...string) ([]byte, error)
- func (dk Scope) BuildCommand(ctx context.Context, req Command) ([]byte, error)
- func (dk Scope) BuildImages(ctx context.Context, container string) ([]string, error)
- func (dk Scope) Command(ctx context.Context, req Command) ([]byte, error)
- func (dk Scope) DialAddress(hostPort int) string
- func (dk Scope) EnsureRunning(ctx context.Context, name string, runArgs []string) error
- func (dk Scope) ExecResult(ctx context.Context, container string, s containerresult.Spec) ([]byte, error)
- func (dk Scope) Exists(ctx context.Context, args ...string) (bool, error)
- func (dk Scope) FromFile(ctx context.Context, path string, args ...string) ([]byte, error)
- func (dk Scope) FrontDoor(servingLabel, deployment string, hostPort int) string
- func (dk Scope) Image(ctx context.Context, ref string) (execution.ImageAnswer, bool, error)
- func (dk Scope) ImageDigest(ctx context.Context, imageRef string) string
- func (dk Scope) Installs(installation string) bool
- func (dk Scope) InstanceLabel() []string
- func (dk Scope) Labels(class, owner string) []string
- func (dk Scope) Lines(ctx context.Context, args ...string) []string
- func (dk Scope) List(ctx context.Context, args ...string) ([]string, error)
- func (dk Scope) ListLabelled(ctx context.Context, key string, labels ...string) (map[string]string, error)
- func (dk Scope) OK(ctx context.Context, args ...string) bool
- func (dk Scope) ProbeURL(hostPort int) string
- func (dk Scope) PublishAddress() string
- func (dk Scope) ReapStack(ctx context.Context, stackID string)
- func (dk Scope) Remote() bool
- func (dk Scope) Remove(ctx context.Context, container string) error
- func (dk Scope) RemoveBuildImagesOf(ctx context.Context, container string) (inUse bool, err error)
- func (dk Scope) RemoveDisposable(ctx context.Context, container string) error
- func (dk Scope) RemoveDisposableStack(ctx context.Context, stackID string) error
- func (dk Scope) RemoveImageUnlessUsed(ctx context.Context, ref string) (inUse bool, err error)
- func (dk Scope) RemoveLabelled(ctx context.Context, labels ...string) ([]string, error)
- func (dk Scope) RemoveNetwork(ctx context.Context, network string) error
- func (dk Scope) RemoveStack(ctx context.Context, stackID string) error
- func (dk Scope) RemoveUnusedImage(ctx context.Context, ref string) error
- func (dk Scope) RemoveVolume(ctx context.Context, volume string) error
- func (dk Scope) RemoveWithVolumes(ctx context.Context, container string) error
- func (dk Scope) Result(ctx context.Context, s containerresult.Spec) ([]byte, error)
- func (dk Scope) RoutesDeployment(deployment string) bool
- func (dk Scope) Run(ctx context.Context, args ...string) ([]byte, error)
- func (dk Scope) RunStep(ctx context.Context, s Step) ([]byte, error)
- func (dk Scope) Running(ctx context.Context, container string) bool
- func (dk Scope) StopStep(ctx context.Context, stepID ids.ID) ([]string, error)
- func (dk Scope) Text(ctx context.Context, args ...string) string
- func (dk Scope) ToFile(ctx context.Context, path string, args ...string) error
- func (dk Scope) WithBootConfig(ctx context.Context, scratch string, login *RegistryCredential) (Scope, func() error, error)
- func (dk Scope) WithHost(host, hostname, domain string) Scope
- func (dk Scope) WithLifetime(ctx context.Context) Scope
- type Sealed
- type SecretReceipt
- type SecretResolver
- type SourceInputs
- type Step
- type Watched
Constants ¶
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.
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 )
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.
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.
const BrowserEnvVar = appcontract.BrowserEnvVar
BrowserEnvVar carries a static part's browser-safe values, a JSON object.
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.
const BuildCacheBudget = "4GB"
BuildCacheBudget is how much unused build cache a daemon keeps: the AppTown's own and a worker's alike.
const ContractPath = ".apptown/app.yaml"
ContractPath is where the app contract lives in a repository.
const MaxContractBytes = 1 << 20
MaxContractBytes bounds the app contract read from a commit.
const PreparedVersion = 1
PreparedVersion is the prepared value's shape; a machine given another refuses it.
const Redacted = "[secret]"
Redacted is what a generated credential reads as in a boot's failure.
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.
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.
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.
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 ¶
var ErrContainerAbsent = errors.New("Docker container is absent")
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.
var ErrNoAnswer = errors.New("no HTTP answer")
ErrNoAnswer is a sealed probe that got no HTTP answer.
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.
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.
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".
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ConfineStaticExport ¶
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 ¶
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 ¶
ContainerOfDataVolume is the inverse of DataVolume.
func ContractFileAt ¶
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 ¶
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 ¶
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 ¶
IsDigestReference says whether ref names an image by digest in a registry: <repository>@sha256:<hex>.
func IsLocalBuildTag ¶
IsLocalBuildTag: an image that exists only on this daemon.
func IsNamedVolume ¶
IsNamedVolume says whether a volume carries a name AppTown gives a data or need volume.
func IsPreviewName ¶
IsPreviewName says whether a container is a preview-tier app container (the vhost's cache policy and the orphan sweep read this).
func IsWorkPreviewLabel ¶
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 ¶
IsWorkPreviewName is IsWorkPreviewLabel for a container name.
func LoginRegistry ¶
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 ¶
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 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"):
- 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;
- confine: the output folder is checked before anything reads it (ConfineStaticExport);
- 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 ¶
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 ¶
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 PreviewChangeName ¶
func PreviewLabelName ¶
func PreviewRunName ¶
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 ¶
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 ¶
ReadContractAt reads the canonical runtime declaration at an exact repository revision.
func ReadDisk ¶
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 ¶
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 ReleasePreviewLabel ¶
func ReleaseStackID ¶
func RemovePreview ¶
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 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 RunningMemoryUsage ¶
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 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 ¶
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 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 ¶
StackOfNetwork is the inverse of Network.
func StagedBuildContext ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
VisitorHost is the Host a visitor's request carries at an address, for a gate's page check (BootRequest.VisitorHost).
func VolumeAt ¶
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 ¶
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 ¶
func AsBootError ¶
asBootError: the phase-carrying error behind a boot failure; any other error comes back wrapped with no phase.
func (*BootError) BeforeEffects ¶
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) KnownOutcome ¶
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.
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 Client ¶
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 ¶
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 ¶
DataMountAt is what a container mounts at path, of either kind: where a need service keeps its data.
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.
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) 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 ¶
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) 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 ¶
func (h *Host) Boot(ctx context.Context, t BootRequest, c *appcontract.Contract) (BootResult, error)
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 ¶
type HostInfo ¶
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.
type InstalledBrowser ¶
InstalledBrowser is what a running static part was started with for /_apptown/env.js, read from the container itself.
func InspectBrowserValues ¶
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.
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 ¶
ByKey names a deployment by its key: apptown-dep-<key>, apptown-svc-dep-<key>-<service>, and so on.
func NamesOf ¶
NamesOf is the names of a deployment from its record: by its key, which a deployment not yet recorded does not have.
func (Names) NeedVolume ¶
NeedVolume is the volume a need keeps its data in.
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 ¶
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 ¶
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) NeedVolume ¶
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.
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 ¶
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 ¶
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 ¶
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.
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.
type RegistryCredential ¶
type RegistryCredential struct {
Host, Username, Token string
}
RegistryCredential is the project's one registry login, for one boot.
type RegistryLogin ¶
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"`
}
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 ¶
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) AgentImageLabel ¶
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 ¶
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 ¶
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 ¶
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 ¶
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) DialAddress ¶
DialAddress is host:port for a published port: loopback here, the attached host by address there.
func (Scope) EnsureRunning ¶
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 ¶
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) FrontDoor ¶
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 ¶
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 ¶
ImageDigest resolves a pulled image ref to its content digest — the receipt that names the exact bytes.
func (Scope) Installs ¶
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 ¶
InstanceLabel is the --label argument naming this scope's installation; none when it has no id.
func (Scope) Labels ¶
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 ¶
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) 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) ProbeURL ¶
ProbeURL is where AppTown reaches a container's published port: its own loopback, or the attached host by address.
func (Scope) PublishAddress ¶
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 ¶
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) Remove ¶
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 ¶
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 ¶
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 ¶
RemoveDisposableStack is RemoveStack for a disposable stack (a preview's): each container's named data volume goes too.
func (Scope) RemoveImageUnlessUsed ¶
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 ¶
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 (Scope) RemoveStack ¶
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 ¶
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) RemoveWithVolumes ¶
RemoveWithVolumes removes a container with its anonymous volumes, for a container whose data goes with it.
func (Scope) Result ¶
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 ¶
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) RunStep ¶
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) StopStep ¶
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) 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.
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.
Source Files
¶
- app.go
- boot.go
- builder.go
- capacity.go
- client.go
- cold_policy.go
- contract_at.go
- contract_bytes.go
- driver.go
- events.go
- health.go
- health_policy.go
- host.go
- images.go
- intranet_needs.go
- inventory.go
- liveness_policy.go
- logs.go
- maintained_readiness.go
- memory.go
- names.go
- need_sizes.go
- owned.go
- prepared.go
- preview_name_parse.go
- preview_names.go
- probe.go
- registry.go
- result.go
- runtime.go
- scope.go
- sealed.go
- secrets.go
- source.go
- stack.go
- static_build.go
- step.go
- step_stop.go
- storage.go
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. |