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
- func AgentServeArgs(containerRef, user, cwd string, forwardAgent bool) []string
- func Build(ctx context.Context, r runtime.Runner, spec *config.Spec, platform string, ...) error
- func BuildArgs(spec *config.Spec, platform string) ([]string, error)
- func BuildImageTag(spec *config.Spec) string
- func ComposeConfigArgs(spec *config.Spec, project string) []string
- func ComposeCovers(targets []string, service string) bool
- func ComposeDown(ctx context.Context, c *runtime.Compose, spec *config.Spec, project string, ...) error
- func ComposeDownArgs(spec *config.Spec, project string, volumes bool) []string
- func ComposeLogsArgs(spec *config.Spec, project string, follow bool, services []string) []string
- func ComposeRemoveArgs(spec *config.Spec, project string, services []string) []string
- func ComposeRestartArgs(spec *config.Spec, project string, services []string) []string
- func ComposeServiceNames(ctx context.Context, c *runtime.Compose, spec *config.Spec, project string) ([]string, error)
- func ComposeStopArgs(spec *config.Spec, project string, services []string) []string
- func ComposeTargets(explicit, fallback []string) []string
- func ComposeUp(ctx context.Context, c *runtime.Compose, spec *config.Spec, project string, ...) error
- func ComposeUpArgs(spec *config.Spec, project string, rebuild, recreate bool, services []string) []string
- func ConfigHash(spec *config.Spec) string
- func ContainerName(spec *config.Spec) string
- func Create(ctx context.Context, r runtime.Runner, spec *config.Spec, opts CreateOptions, ...) (string, error)
- func ExecArgs(name, user, workdir string, env map[string]string, interactive, tty bool, ...) []string
- func Inject(ctx context.Context, r runtime.Runner, opts InjectOptions) error
- func Labels(spec *config.Spec) map[string]string
- func NameFromID(id string) string
- func ProbeEnv(ctx context.Context, r runtime.Runner, containerRef, user string, ...) map[string]string
- func ProjectName(spec *config.Spec) string
- func Remove(ctx context.Context, r runtime.Runner, name string) error
- func Restart(ctx context.Context, r runtime.Runner, name string) error
- func RunArgs(spec *config.Spec, opts CreateOptions, platform string) ([]string, error)
- func ServiceOf(i *Info) string
- func Start(ctx context.Context, r runtime.Runner, name string) error
- func Stop(ctx context.Context, r runtime.Runner, name string) error
- func WorkspaceIDFromProject(project string) (string, bool)
- type Action
- type ContainerConfig
- type ContainerState
- type CreateOptions
- type ImageInfo
- type Info
- func Find(ctx context.Context, r runtime.Runner, name string) (*Info, error)
- func FindComposeService(ctx context.Context, r runtime.Runner, project, service string) (*Info, error)
- func List(ctx context.Context, r runtime.Runner) ([]*Info, error)
- func ListComposeProject(ctx context.Context, r runtime.Runner, project string) ([]*Info, error)
- type InjectOptions
Constants ¶
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.
const ( AgentBinary = AgentDir + "/agent" AgentHostKey = AgentDir + "/host_key" AgentAuthKey = AgentDir + "/authorized_key" AgentEnvFile = AgentDir + "/env" )
Agent file paths inside the container.
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.
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 ¶
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 BuildImageTag ¶
BuildImageTag is the local tag devc assigns to an image it builds.
func ComposeConfigArgs ¶ added in v1.3.0
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
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 ¶
ComposeDownArgs constructs `compose -p <project> -f <file> down [--volumes]`, which tears the whole project down. Removing individual services goes through ComposeRemoveArgs instead.
func ComposeLogsArgs ¶
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
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
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 ¶
ComposeStopArgs constructs `compose -p <project> -f <file> stop [services]`. An empty services list stops the whole project.
func ComposeTargets ¶ added in v1.3.0
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 ¶
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 ¶
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 ¶
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 NameFromID ¶ added in v1.2.0
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 ¶
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 ServiceOf ¶ added in v1.3.0
ServiceOf is the compose service a container belongs to, empty for a container compose did not create.
func WorkspaceIDFromProject ¶ added in v1.2.0
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 )
type ContainerConfig ¶
type ContainerState ¶
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.
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 ¶
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 ¶
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
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).
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.