container

package
v1.3.0 Latest Latest
Warning

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

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

Documentation

Overview

Package container turns a resolved config.Spec into container-runtime operations: build, create, start, reuse, exec, and inspection. Everything is argv construction over a runtime.Runner, so it is exercised end-to-end with a FakeRunner and no real container daemon.

Index

Constants

View Source
const (
	LabelComposeProject = "com.docker.compose.project"
	LabelComposeService = "com.docker.compose.service"
)

Compose label keys set by every compose implementation on the containers it creates. devc locates the attach container by these, never by generating an override file.

View Source
const (
	AgentBinary  = AgentDir + "/agent"
	AgentHostKey = AgentDir + "/host_key"
	AgentAuthKey = AgentDir + "/authorized_key"
	AgentEnvFile = AgentDir + "/env"
)

Agent file paths inside the container.

View Source
const (
	LabelID         = "com.github.terrakuh.devc.id"
	LabelName       = "com.github.terrakuh.devc.name"
	LabelLocal      = "com.github.terrakuh.devc.local"
	LabelConfigHash = "com.github.terrakuh.devc.config-hash"
)

Label keys stamped on every object devc creates, so workspaces can be found and their drift detected without any local state file.

View Source
const AgentDir = "/.devc"

AgentDir is where devc places the agent binary and its credentials inside the container.

Variables

This section is empty.

Functions

func AgentServeArgs

func AgentServeArgs(containerRef, user, cwd string, forwardAgent bool) []string

AgentServeArgs builds the argv that runs the injected agent as an SSH server over the exec pipe: `exec -i --user 0 <ctr> /.devc/agent __serve`. The agent runs as root and drops to the session user itself (--user below), the same privilege model as sshd.

func Build

func Build(ctx context.Context, r runtime.Runner, spec *config.Spec, platform string, io runtime.IO) error

Build runs the image build for a KindBuild spec.

func BuildArgs

func BuildArgs(spec *config.Spec, platform string) ([]string, error)

BuildArgs constructs the `build` argv for a KindBuild spec.

func BuildImageTag

func BuildImageTag(spec *config.Spec) string

BuildImageTag is the local tag devc assigns to an image it builds.

func ComposeConfigArgs added in v1.3.0

func ComposeConfigArgs(spec *config.Spec, project string) []string

ComposeConfigArgs constructs `compose -p <project> -f <file> config --services`, which prints the services the compose files declare - including the ones that have no container right now.

func ComposeCovers added in v1.3.0

func ComposeCovers(targets []string, service string) bool

ComposeCovers reports whether a target list includes service, treating the empty list as "every service" (see ComposeTargets).

func ComposeDown

func ComposeDown(ctx context.Context, c *runtime.Compose, spec *config.Spec, project string, volumes bool, io runtime.IO) error

ComposeDown tears the project down.

func ComposeDownArgs

func ComposeDownArgs(spec *config.Spec, project string, volumes bool) []string

ComposeDownArgs constructs `compose -p <project> -f <file> down [--volumes]`, which tears the whole project down. Removing individual services goes through ComposeRemoveArgs instead.

func ComposeLogsArgs

func ComposeLogsArgs(spec *config.Spec, project string, follow bool, services []string) []string

ComposeLogsArgs constructs `compose -p <project> -f <file> logs [--follow] [services]`. An empty services list shows the whole project's logs.

func ComposeRemoveArgs added in v1.3.0

func ComposeRemoveArgs(spec *config.Spec, project string, services []string) []string

ComposeRemoveArgs constructs `compose -p <project> -f <file> rm --force --stop <services>`, the per-service counterpart of down: it stops and removes just those containers and leaves the project's network and named volumes alone. `down <services>` would be the obvious spelling but is a recent docker-compose addition that podman-compose does not share, whereas `rm` is universal.

func ComposeRestartArgs added in v1.2.0

func ComposeRestartArgs(spec *config.Spec, project string, services []string) []string

ComposeRestartArgs constructs `compose -p <project> -f <file> restart [services]`. An empty services list restarts every service in the project; callers resolve their default through ComposeTargets.

func ComposeServiceNames added in v1.3.0

func ComposeServiceNames(ctx context.Context, c *runtime.Compose, spec *config.Spec, project string) ([]string, error)

ComposeServiceNames returns the services the workspace's compose files declare, in the order compose reports them.

func ComposeStopArgs

func ComposeStopArgs(spec *config.Spec, project string, services []string) []string

ComposeStopArgs constructs `compose -p <project> -f <file> stop [services]`. An empty services list stops the whole project.

func ComposeTargets added in v1.3.0

func ComposeTargets(explicit, fallback []string) []string

ComposeTargets picks the services a compose verb acts on: the ones the user named explicitly, or fallback when they named none. An empty result means "every service in the project" - that is how compose reads a missing service list, so it needs no special casing at the call sites.

func ComposeUp

func ComposeUp(ctx context.Context, c *runtime.Compose, spec *config.Spec, project string, rebuild, recreate bool, services []string, io runtime.IO) error

ComposeUp brings the given services up (detached); an empty list means every service in the project. rebuild rebuilds the service images before (re)creating; recreate forces the containers to be replaced even when compose considers them up-to-date.

func ComposeUpArgs

func ComposeUpArgs(spec *config.Spec, project string, rebuild, recreate bool, services []string) []string

ComposeUpArgs constructs `compose -p <project> -f <file> up -d [--build] [--force-recreate] [services]`. rebuild adds --build so the image is rebuilt from source; recreate adds --force-recreate so the container is replaced even when compose considers it up-to-date. A rebuild implies a recreate: a running container keeps its old image until it is recreated, so a bare --build would rebuild the image but leave the stale container in place. An empty services list brings up every service in the project.

func ConfigHash

func ConfigHash(spec *config.Spec) string

ConfigHash is a stable digest of the resolved Spec. A change means the devcontainer.json changed in a way that warrants recreating the container. The ID and ConfigPath are excluded so the hash reflects behaviour, not the workspace's location.

func ContainerName

func ContainerName(spec *config.Spec) string

ContainerName is the deterministic container name for a workspace.

func Create

func Create(ctx context.Context, r runtime.Runner, spec *config.Spec, opts CreateOptions, platform string) (string, error)

Create runs the container (run -d) and returns its ID.

func ExecArgs

func ExecArgs(name, user, workdir string, env map[string]string, interactive, tty bool, argvIn []string) []string

ExecArgs constructs an `exec` argv running argvIn as the given user in the working directory, injecting env. When interactive, a TTY is requested; the SSH transport must never set interactive.

func Inject

func Inject(ctx context.Context, r runtime.Runner, opts InjectOptions) error

Inject installs the agent binary and credentials into the container, idempotently. It skips the (large) binary copy when the container already runs the expected version. Keys and env are always refreshed (cheap, and keeps rotation simple).

All in-container steps run as root (--user 0): /.devc lives at the filesystem root and the agent must be able to drop privileges to the session user, so setup cannot depend on the container's default exec user (which, e.g. under --userns=keep-id, is unprivileged).

func Labels

func Labels(spec *config.Spec) map[string]string

Labels returns the label set for a workspace's container.

func NameFromID added in v1.2.0

func NameFromID(id string) string

NameFromID recovers a workspace's display name (the slug) from its id, undoing the "<slug>-<sha256(folder)[:8]>" scheme. Used for compose service containers, which carry no devc name label of their own. An id that does not match the scheme is returned unchanged.

func ProbeEnv

func ProbeEnv(ctx context.Context, r runtime.Runner, containerRef, user string, mode config.EnvProbe) map[string]string

ProbeEnv runs a shell inside the container to capture the environment a login and/or interactive shell would set (PATH additions from /etc/profile.d, nvm, etc.), per userEnvProbe. Without it, `ssh workspace 'go version'` would miss everything the profile scripts export, a classic and confusing failure.

It returns nil for EnvProbeNone or on any error (the probe is best-effort; a failed probe must never block bring-up).

func ProjectName

func ProjectName(spec *config.Spec) string

ProjectName returns the compose project name for a workspace. A user-set COMPOSE_PROJECT_NAME wins (compose itself would honour it, so devc must agree to find the containers); otherwise it is derived from the workspace id.

func Remove

func Remove(ctx context.Context, r runtime.Runner, name string) error

Remove force-removes a container (ignoring absence).

func Restart added in v1.2.0

func Restart(ctx context.Context, r runtime.Runner, name string) error

Restart restarts a container (starting it if it is stopped).

func RunArgs

func RunArgs(spec *config.Spec, opts CreateOptions, platform string) ([]string, error)

RunArgs constructs the `run -d` argv that creates the workspace container.

func ServiceOf added in v1.3.0

func ServiceOf(i *Info) string

ServiceOf is the compose service a container belongs to, empty for a container compose did not create.

func Start

func Start(ctx context.Context, r runtime.Runner, name string) error

Start starts an existing (stopped) container.

func Stop

func Stop(ctx context.Context, r runtime.Runner, name string) error

Stop stops a running container.

func WorkspaceIDFromProject added in v1.2.0

func WorkspaceIDFromProject(project string) (string, bool)

WorkspaceIDFromProject recovers the workspace id from a compose project name that ProjectName produced (devc-<id>), reporting false for any project not named that way. It is the inverse used by List to attribute compose service containers - which never carry devc's own labels - back to a workspace. Projects created under a user-set COMPOSE_PROJECT_NAME are not recognized, matching ProjectName: devc can only find what it named deterministically.

Types

type Action

type Action int

Action is what `up` must do to bring a workspace container to running state.

const (
	// ActionCreate: no container exists; build (if needed) and run.
	ActionCreate Action = iota
	// ActionStart: a stopped container matches; start it.
	ActionStart
	// ActionAttach: a running container matches; nothing to do.
	ActionAttach
	// ActionRecreate: a container exists but its config hash differs; the
	// caller removes and recreates it (only when recreate is allowed).
	ActionRecreate
	// ActionDrift: a container exists, config changed, but recreate was not
	// requested; the caller warns and attaches/starts the existing one.
	ActionDrift
)

func Decide

func Decide(existing *Info, spec *config.Spec, allowRecreate bool) Action

Decide chooses the Action for an existing container (nil = none) given the desired spec and whether the user allowed recreation.

type ContainerConfig

type ContainerConfig struct {
	Labels map[string]string `json:"Labels"`
	Image  string            `json:"Image"`
}

type ContainerState

type ContainerState struct {
	Status  string `json:"Status"` // "running", "exited", "created", ...
	Running bool   `json:"Running"`
}

type CreateOptions

type CreateOptions struct {
	// Userns is the value for --userns (e.g. "keep-id"); empty omits the flag.
	Userns string
	// SELinuxLabel is "z" (shared) or "Z" (private), appended to the default
	// workspace bind mount; empty omits relabeling.
	SELinuxLabel string
}

CreateOptions carries host-environment choices that the Spec does not: how to map users and relabel SELinux volumes. They are computed once by the CLI (from flags + runtime probing) and threaded through.

type ImageInfo

type ImageInfo struct {
	Architecture string `json:"Architecture"` // "amd64", "arm64"
	Os           string `json:"Os"`           // "linux"
}

ImageInfo is the subset of image `inspect` output devc needs: the platform, so the agent binary of the right architecture is injected.

func InspectImage

func InspectImage(ctx context.Context, r runtime.Runner, ref string) (*ImageInfo, error)

InspectImage returns the platform info for an image reference.

type Info

type Info struct {
	ID     string          `json:"Id"`
	Name   string          `json:"Name"`
	State  ContainerState  `json:"State"`
	Config ContainerConfig `json:"Config"`
}

Info is the subset of `inspect` output devc needs about a container.

func Find

func Find(ctx context.Context, r runtime.Runner, name string) (*Info, error)

Find locates the workspace container by its devc name and returns its Info. It returns (nil, nil) when no such container exists, distinguishing "absent" from a real inspection error.

func FindComposeService

func FindComposeService(ctx context.Context, r runtime.Runner, project, service string) (*Info, error)

FindComposeService locates the single container backing spec.Service in the given project, using the container runtime's `ps` filtered by compose labels. It returns (nil, nil) when the service has no container, and an error when the service is scaled to more than one.

func List

func List(ctx context.Context, r runtime.Runner) ([]*Info, error)

List returns one Info per workspace devc created, single-container and compose alike. Single-container workspaces carry devc's own id label and are found directly. Compose service containers are created by compose, not devc, so they never carry that label; they are found by their deterministic devc-<id> compose project label instead, and a project's several service containers are collapsed into one synthesized workspace row carrying only the id label. The list is best-effort: a container that disappears between the `ps` and its `inspect` is skipped rather than failing the whole enumeration.

func ListComposeProject added in v1.3.0

func ListComposeProject(ctx context.Context, r runtime.Runner, project string) ([]*Info, error)

ListComposeProject returns one Info per container in the project, running or not, sorted by service name (then container id, so a scaled service's containers keep a stable order).

func (Info) Running

func (i Info) Running() bool

Running reports whether the container is up.

type InjectOptions

type InjectOptions struct {
	// Container is the target container reference (name or id).
	Container string
	// AgentSource is the host path of the agent binary to copy, normally the
	// running devc binary itself (/proc/self/exe). It must be a static,
	// CGO-free linux binary of the container's architecture.
	AgentSource string
	// HostArch is the GOARCH of AgentSource; injection errors if it does not
	// match the container's architecture.
	HostArch string
	// Version is the expected agent version; a container whose agent already
	// reports it skips the binary copy.
	Version string
	// HostKeyFile and AuthorizedKeyFile are host paths to the agent's host key
	// and the single authorized client public key.
	HostKeyFile       string
	AuthorizedKeyFile string
	// Env is injected into every ssh session (remoteEnv plus the env probe).
	Env map[string]string
}

InjectOptions parameterises agent injection.

Jump to

Keyboard shortcuts

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