imageservice: Add context to various methods

Co-authored-by: Paweł Gronowski <pawel.gronowski@docker.com>
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
This commit is contained in:
Nicolas De Loof 2022-10-26 18:13:17 +02:00 committed by Paweł Gronowski
parent 4c07d58592
commit def549c8f6
No known key found for this signature in database
GPG Key ID: B85EFCFE26DEF92A
40 changed files with 303 additions and 256 deletions

View File

@ -32,14 +32,14 @@ type copyBackend interface {
// stateBackend includes functions to implement to provide container state lifecycle functionality.
type stateBackend interface {
ContainerCreate(config types.ContainerCreateConfig) (container.CreateResponse, error)
ContainerCreate(ctx context.Context, config types.ContainerCreateConfig) (container.CreateResponse, error)
ContainerKill(name string, signal string) error
ContainerPause(name string) error
ContainerRename(oldName, newName string) error
ContainerResize(name string, height, width int) error
ContainerRestart(ctx context.Context, name string, options container.StopOptions) error
ContainerRm(name string, config *types.ContainerRmConfig) error
ContainerStart(name string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
ContainerStart(ctx context.Context, name string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
ContainerStop(ctx context.Context, name string, options container.StopOptions) error
ContainerUnpause(name string) error
ContainerUpdate(name string, hostConfig *container.HostConfig) (container.ContainerUpdateOKBody, error)
@ -54,7 +54,7 @@ type monitorBackend interface {
ContainerStats(ctx context.Context, name string, config *backend.ContainerStatsConfig) error
ContainerTop(name string, psArgs string) (*container.ContainerTopOKBody, error)
Containers(config *types.ContainerListOptions) ([]*types.Container, error)
Containers(ctx context.Context, config *types.ContainerListOptions) ([]*types.Container, error)
}
// attachBackend includes function to implement to provide container attaching functionality.
@ -68,7 +68,7 @@ type systemBackend interface {
}
type commitBackend interface {
CreateImageFromContainer(name string, config *backend.CreateImageConfig) (imageID string, err error)
CreateImageFromContainer(ctx context.Context, name string, config *backend.CreateImageConfig) (imageID string, err error)
}
// Backend is all the methods that need to be implemented to provide container specific functionality.

View File

@ -58,7 +58,7 @@ func (s *containerRouter) postCommit(ctx context.Context, w http.ResponseWriter,
Changes: r.Form["changes"],
}
imgID, err := s.backend.CreateImageFromContainer(r.Form.Get("container"), commitCfg)
imgID, err := s.backend.CreateImageFromContainer(ctx, r.Form.Get("container"), commitCfg)
if err != nil {
return err
}
@ -91,7 +91,7 @@ func (s *containerRouter) getContainersJSON(ctx context.Context, w http.Response
config.Limit = limit
}
containers, err := s.backend.Containers(config)
containers, err := s.backend.Containers(ctx, config)
if err != nil {
return err
}
@ -214,7 +214,7 @@ func (s *containerRouter) postContainersStart(ctx context.Context, w http.Respon
checkpoint := r.Form.Get("checkpoint")
checkpointDir := r.Form.Get("checkpoint-dir")
if err := s.backend.ContainerStart(vars["name"], hostConfig, checkpoint, checkpointDir); err != nil {
if err := s.backend.ContainerStart(ctx, vars["name"], hostConfig, checkpoint, checkpointDir); err != nil {
return err
}
@ -578,7 +578,7 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
hostConfig.PidsLimit = nil
}
ccr, err := s.backend.ContainerCreate(types.ContainerCreateConfig{
ccr, err := s.backend.ContainerCreate(ctx, types.ContainerCreateConfig{
Name: name,
Config: config,
HostConfig: hostConfig,

View File

@ -31,7 +31,7 @@ type imageBackend interface {
type importExportBackend interface {
LoadImage(ctx context.Context, inTar io.ReadCloser, outStream io.Writer, quiet bool) error
ImportImage(src string, repository string, platform *specs.Platform, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error
ImportImage(ctx context.Context, src string, repository string, platform *specs.Platform, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error
ExportImage(ctx context.Context, names []string, outStream io.Writer) error
}

View File

@ -68,7 +68,7 @@ func (ir *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrit
progressErr = ir.backend.PullImage(ctx, img, tag, platform, metaHeaders, authConfig, output)
} else { // import
src := r.Form.Get("fromSrc")
progressErr = ir.backend.ImportImage(src, repo, platform, tag, message, r.Body, output, r.Form["changes"])
progressErr = ir.backend.ImportImage(ctx, src, repo, platform, tag, message, r.Body, output, r.Form["changes"])
}
if progressErr != nil {
if !output.Flushed() {

View File

@ -12,7 +12,7 @@ import (
type Backend interface {
Init(req types.InitRequest) (string, error)
Join(req types.JoinRequest) error
Leave(force bool) error
Leave(ctx context.Context, force bool) error
Inspect() (types.Swarm, error)
Update(uint64, types.Spec, types.UpdateFlags) error
GetUnlockKey() (string, error)

View File

@ -56,7 +56,7 @@ func (sr *swarmRouter) leaveCluster(ctx context.Context, w http.ResponseWriter,
}
force := httputils.BoolValue(r, "force")
return sr.backend.Leave(force)
return sr.backend.Leave(ctx, force)
}
func (sr *swarmRouter) inspectCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {

View File

@ -60,13 +60,13 @@ type ExecBackend interface {
// ContainerAttachRaw attaches to container.
ContainerAttachRaw(cID string, stdin io.ReadCloser, stdout, stderr io.Writer, stream bool, attached chan struct{}) error
// ContainerCreateIgnoreImagesArgsEscaped creates a new Docker container and returns potential warnings
ContainerCreateIgnoreImagesArgsEscaped(config types.ContainerCreateConfig) (container.CreateResponse, error)
ContainerCreateIgnoreImagesArgsEscaped(ctx context.Context, config types.ContainerCreateConfig) (container.CreateResponse, error)
// ContainerRm removes a container specified by `id`.
ContainerRm(name string, config *types.ContainerRmConfig) error
// ContainerKill stops the container execution abruptly.
ContainerKill(containerID string, sig string) error
// ContainerStart starts a new container
ContainerStart(containerID string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
ContainerStart(ctx context.Context, containerID string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
// ContainerWait stops processing until the given container is stopped.
ContainerWait(ctx context.Context, name string, condition containerpkg.WaitCondition) (<-chan containerpkg.StateStatus, error)
}
@ -80,7 +80,7 @@ type Result struct {
// ImageCacheBuilder represents a generator for stateful image cache.
type ImageCacheBuilder interface {
// MakeImageCache creates a stateful image cache.
MakeImageCache(cacheFrom []string) ImageCache
MakeImageCache(ctx context.Context, cacheFrom []string) (ImageCache, error)
}
// ImageCache abstracts an image cache.

View File

@ -95,7 +95,7 @@ func (bm *BuildManager) Build(ctx context.Context, config backend.BuildConfig) (
if err != nil {
return nil, err
}
return b.build(source, dockerfile)
return b.build(ctx, source, dockerfile)
}
// builderOptions are the dependencies required by the builder
@ -136,6 +136,11 @@ func newBuilder(clientCtx context.Context, options builderOptions) (*Builder, er
config = new(types.ImageBuildOptions)
}
imageProber, err := newImageProber(clientCtx, options.Backend, config.CacheFrom, config.NoCache)
if err != nil {
return nil, err
}
b := &Builder{
clientCtx: clientCtx,
options: config,
@ -147,7 +152,7 @@ func newBuilder(clientCtx context.Context, options builderOptions) (*Builder, er
idMapping: options.IDMapping,
imageSources: newImageSources(clientCtx, options),
pathCache: options.PathCache,
imageProber: newImageProber(options.Backend, config.CacheFrom, config.NoCache),
imageProber: imageProber,
containerManager: newContainerManager(options.Backend),
}
@ -181,7 +186,7 @@ func buildLabelOptions(labels map[string]string, stages []instructions.Stage) {
// Build runs the Dockerfile builder by parsing the Dockerfile and executing
// the instructions from the file.
func (b *Builder) build(source builder.Source, dockerfile *parser.Result) (*builder.Result, error) {
func (b *Builder) build(ctx context.Context, source builder.Source, dockerfile *parser.Result) (*builder.Result, error) {
defer b.imageSources.Unmount()
stages, metaArgs, err := instructions.Parse(dockerfile.AST)
@ -205,7 +210,7 @@ func (b *Builder) build(source builder.Source, dockerfile *parser.Result) (*buil
buildLabelOptions(b.options.Labels, stages)
dockerfile.PrintWarnings(b.Stderr)
dispatchState, err := b.dispatchDockerfileWithCancellation(stages, metaArgs, dockerfile.EscapeToken, source)
dispatchState, err := b.dispatchDockerfileWithCancellation(ctx, stages, metaArgs, dockerfile.EscapeToken, source)
if err != nil {
return nil, err
}
@ -244,7 +249,7 @@ func printCommand(out io.Writer, currentCommandIndex int, totalCommands int, cmd
return currentCommandIndex + 1
}
func (b *Builder) dispatchDockerfileWithCancellation(parseResult []instructions.Stage, metaArgs []instructions.ArgCommand, escapeToken rune, source builder.Source) (*dispatchState, error) {
func (b *Builder) dispatchDockerfileWithCancellation(ctx context.Context, parseResult []instructions.Stage, metaArgs []instructions.ArgCommand, escapeToken rune, source builder.Source) (*dispatchState, error) {
dispatchRequest := dispatchRequest{}
buildArgs := NewBuildArgs(b.options.BuildArgs)
totalCommands := len(metaArgs) + len(parseResult)
@ -272,7 +277,7 @@ func (b *Builder) dispatchDockerfileWithCancellation(parseResult []instructions.
dispatchRequest = newDispatchRequest(b, escapeToken, source, buildArgs, stagesResults)
currentCommandIndex = printCommand(b.Stdout, currentCommandIndex, totalCommands, stage.SourceCode)
if err := initializeStage(dispatchRequest, &stage); err != nil {
if err := initializeStage(ctx, dispatchRequest, &stage); err != nil {
return nil, err
}
dispatchRequest.state.updateRunConfig()
@ -290,7 +295,7 @@ func (b *Builder) dispatchDockerfileWithCancellation(parseResult []instructions.
currentCommandIndex = printCommand(b.Stdout, currentCommandIndex, totalCommands, cmd)
if err := dispatch(dispatchRequest, cmd); err != nil {
if err := dispatch(ctx, dispatchRequest, cmd); err != nil {
return nil, err
}
dispatchRequest.state.updateRunConfig()
@ -317,7 +322,7 @@ func (b *Builder) dispatchDockerfileWithCancellation(parseResult []instructions.
// coming from the query parameter of the same name.
//
// TODO: Remove?
func BuildFromConfig(config *container.Config, changes []string, os string) (*container.Config, error) {
func BuildFromConfig(ctx context.Context, config *container.Config, changes []string, os string) (*container.Config, error) {
if len(changes) == 0 {
return config, nil
}
@ -327,7 +332,7 @@ func BuildFromConfig(config *container.Config, changes []string, os string) (*co
return nil, errdefs.InvalidParameter(err)
}
b, err := newBuilder(context.Background(), builderOptions{
b, err := newBuilder(ctx, builderOptions{
Options: &types.ImageBuildOptions{NoCache: true},
})
if err != nil {
@ -360,7 +365,7 @@ func BuildFromConfig(config *container.Config, changes []string, os string) (*co
dispatchRequest.state.imageID = config.Image
dispatchRequest.state.operatingSystem = os
for _, cmd := range commands {
err := dispatch(dispatchRequest, cmd)
err := dispatch(ctx, dispatchRequest, cmd)
if err != nil {
return nil, errdefs.InvalidParameter(err)
}

View File

@ -28,8 +28,8 @@ func newContainerManager(docker builder.ExecBackend) *containerManager {
}
// Create a container
func (c *containerManager) Create(runConfig *container.Config, hostConfig *container.HostConfig) (container.CreateResponse, error) {
container, err := c.backend.ContainerCreateIgnoreImagesArgsEscaped(types.ContainerCreateConfig{
func (c *containerManager) Create(ctx context.Context, runConfig *container.Config, hostConfig *container.HostConfig) (container.CreateResponse, error) {
container, err := c.backend.ContainerCreateIgnoreImagesArgsEscaped(ctx, types.ContainerCreateConfig{
Config: runConfig,
HostConfig: hostConfig,
})
@ -69,7 +69,7 @@ func (c *containerManager) Run(ctx context.Context, cID string, stdout, stderr i
}
}()
if err := c.backend.ContainerStart(cID, nil, "", ""); err != nil {
if err := c.backend.ContainerStart(ctx, cID, nil, "", ""); err != nil {
close(finished)
logCancellationError(cancelErrCh, "error from ContainerStart: "+err.Error())
return err

View File

@ -9,6 +9,7 @@ package dockerfile // import "github.com/docker/docker/builder/dockerfile"
import (
"bytes"
"context"
"fmt"
"runtime"
"sort"
@ -35,7 +36,7 @@ import (
//
// Sets the environment variable foo to bar, also makes interpolation
// in the dockerfile available from the next statement on via ${foo}.
func dispatchEnv(d dispatchRequest, c *instructions.EnvCommand) error {
func dispatchEnv(ctx context.Context, d dispatchRequest, c *instructions.EnvCommand) error {
runConfig := d.state.runConfig
commitMessage := bytes.NewBufferString("ENV")
for _, e := range c.Env {
@ -57,21 +58,21 @@ func dispatchEnv(d dispatchRequest, c *instructions.EnvCommand) error {
runConfig.Env = append(runConfig.Env, newVar)
}
}
return d.builder.commit(d.state, commitMessage.String())
return d.builder.commit(ctx, d.state, commitMessage.String())
}
// MAINTAINER some text <maybe@an.email.address>
//
// Sets the maintainer metadata.
func dispatchMaintainer(d dispatchRequest, c *instructions.MaintainerCommand) error {
func dispatchMaintainer(ctx context.Context, d dispatchRequest, c *instructions.MaintainerCommand) error {
d.state.maintainer = c.Maintainer
return d.builder.commit(d.state, "MAINTAINER "+c.Maintainer)
return d.builder.commit(ctx, d.state, "MAINTAINER "+c.Maintainer)
}
// LABEL some json data describing the image
//
// Sets the Label variable foo to bar,
func dispatchLabel(d dispatchRequest, c *instructions.LabelCommand) error {
func dispatchLabel(ctx context.Context, d dispatchRequest, c *instructions.LabelCommand) error {
if d.state.runConfig.Labels == nil {
d.state.runConfig.Labels = make(map[string]string)
}
@ -80,14 +81,14 @@ func dispatchLabel(d dispatchRequest, c *instructions.LabelCommand) error {
d.state.runConfig.Labels[v.Key] = v.Value
commitStr += " " + v.String()
}
return d.builder.commit(d.state, commitStr)
return d.builder.commit(ctx, d.state, commitStr)
}
// ADD foo /path
//
// Add the file 'foo' to '/path'. Tarball and Remote URL (http, https) handling
// exist here. If you do not wish to have this automatic handling, use COPY.
func dispatchAdd(d dispatchRequest, c *instructions.AddCommand) error {
func dispatchAdd(ctx context.Context, d dispatchRequest, c *instructions.AddCommand) error {
if c.Chmod != "" {
return errors.New("the --chmod option requires BuildKit. Refer to https://docs.docker.com/go/buildkit/ to learn how to build images with BuildKit enabled")
}
@ -102,13 +103,13 @@ func dispatchAdd(d dispatchRequest, c *instructions.AddCommand) error {
copyInstruction.chownStr = c.Chown
copyInstruction.allowLocalDecompression = true
return d.builder.performCopy(d, copyInstruction)
return d.builder.performCopy(ctx, d, copyInstruction)
}
// COPY foo /path
//
// Same as 'ADD' but without the tar and remote url handling.
func dispatchCopy(d dispatchRequest, c *instructions.CopyCommand) error {
func dispatchCopy(ctx context.Context, d dispatchRequest, c *instructions.CopyCommand) error {
if c.Chmod != "" {
return errors.New("the --chmod option requires BuildKit. Refer to https://docs.docker.com/go/buildkit/ to learn how to build images with BuildKit enabled")
}
@ -130,7 +131,7 @@ func dispatchCopy(d dispatchRequest, c *instructions.CopyCommand) error {
if c.From != "" && copyInstruction.chownStr == "" {
copyInstruction.preserveOwnership = true
}
return d.builder.performCopy(d, copyInstruction)
return d.builder.performCopy(ctx, d, copyInstruction)
}
func (d *dispatchRequest) getImageMount(imageRefOrID string) (*imageMount, error) {
@ -152,8 +153,11 @@ func (d *dispatchRequest) getImageMount(imageRefOrID string) (*imageMount, error
}
// FROM [--platform=platform] imagename[:tag | @digest] [AS build-stage-name]
func initializeStage(d dispatchRequest, cmd *instructions.Stage) error {
d.builder.imageProber.Reset()
func initializeStage(ctx context.Context, d dispatchRequest, cmd *instructions.Stage) error {
err := d.builder.imageProber.Reset(ctx)
if err != nil {
return err
}
var platform *specs.Platform
if v := cmd.Platform; v != "" {
@ -180,12 +184,12 @@ func initializeStage(d dispatchRequest, cmd *instructions.Stage) error {
if len(state.runConfig.OnBuild) > 0 {
triggers := state.runConfig.OnBuild
state.runConfig.OnBuild = nil
return dispatchTriggeredOnBuild(d, triggers)
return dispatchTriggeredOnBuild(ctx, d, triggers)
}
return nil
}
func dispatchTriggeredOnBuild(d dispatchRequest, triggers []string) error {
func dispatchTriggeredOnBuild(ctx context.Context, d dispatchRequest, triggers []string) error {
fmt.Fprintf(d.builder.Stdout, "# Executing %d build trigger", len(triggers))
if len(triggers) > 1 {
fmt.Fprint(d.builder.Stdout, "s")
@ -208,7 +212,7 @@ func dispatchTriggeredOnBuild(d dispatchRequest, triggers []string) error {
}
return err
}
err = dispatch(d, cmd)
err = dispatch(ctx, d, cmd)
if err != nil {
return err
}
@ -276,15 +280,15 @@ func (d *dispatchRequest) getFromImage(shlex *shell.Lex, basename string, platfo
return d.getImageOrStage(name, platform)
}
func dispatchOnbuild(d dispatchRequest, c *instructions.OnbuildCommand) error {
func dispatchOnbuild(ctx context.Context, d dispatchRequest, c *instructions.OnbuildCommand) error {
d.state.runConfig.OnBuild = append(d.state.runConfig.OnBuild, c.Expression)
return d.builder.commit(d.state, "ONBUILD "+c.Expression)
return d.builder.commit(ctx, d.state, "ONBUILD "+c.Expression)
}
// WORKDIR /tmp
//
// Set the working directory for future RUN/CMD/etc statements.
func dispatchWorkdir(d dispatchRequest, c *instructions.WorkdirCommand) error {
func dispatchWorkdir(ctx context.Context, d dispatchRequest, c *instructions.WorkdirCommand) error {
runConfig := d.state.runConfig
var err error
runConfig.WorkingDir, err = normalizeWorkdir(d.state.operatingSystem, runConfig.WorkingDir, c.Path)
@ -305,7 +309,7 @@ func dispatchWorkdir(d dispatchRequest, c *instructions.WorkdirCommand) error {
comment := "WORKDIR " + runConfig.WorkingDir
runConfigWithCommentCmd := copyRunConfig(runConfig, withCmdCommentString(comment, d.state.operatingSystem))
containerID, err := d.builder.probeAndCreate(d.state, runConfigWithCommentCmd)
containerID, err := d.builder.probeAndCreate(ctx, d.state, runConfigWithCommentCmd)
if err != nil || containerID == "" {
return err
}
@ -326,7 +330,7 @@ func dispatchWorkdir(d dispatchRequest, c *instructions.WorkdirCommand) error {
// RUN echo hi # sh -c echo hi (Linux and LCOW)
// RUN echo hi # cmd /S /C echo hi (Windows)
// RUN [ "echo", "hi" ] # echo hi
func dispatchRun(d dispatchRequest, c *instructions.RunCommand) error {
func dispatchRun(ctx context.Context, d dispatchRequest, c *instructions.RunCommand) error {
if !system.IsOSSupported(d.state.operatingSystem) {
return system.ErrNotSupportedOperatingSystem
}
@ -360,7 +364,7 @@ func dispatchRun(d dispatchRequest, c *instructions.RunCommand) error {
withEntrypointOverride(saveCmd, strslice.StrSlice{""}),
withoutHealthcheck())
cID, err := d.builder.create(runConfig)
cID, err := d.builder.create(ctx, runConfig)
if err != nil {
return err
}
@ -420,7 +424,7 @@ func prependEnvOnCmd(buildArgs *BuildArgs, buildArgVars []string, cmd strslice.S
//
// Set the default command to run in the container (which may be empty).
// Argument handling is the same as RUN.
func dispatchCmd(d dispatchRequest, c *instructions.CmdCommand) error {
func dispatchCmd(ctx context.Context, d dispatchRequest, c *instructions.CmdCommand) error {
runConfig := d.state.runConfig
cmd, argsEscaped := resolveCmdLine(c.ShellDependantCmdLine, runConfig, d.state.operatingSystem, c.Name(), c.String())
@ -436,7 +440,7 @@ func dispatchCmd(d dispatchRequest, c *instructions.CmdCommand) error {
runConfig.Cmd = cmd
runConfig.ArgsEscaped = argsEscaped
if err := d.builder.commit(d.state, fmt.Sprintf("CMD %q", cmd)); err != nil {
if err := d.builder.commit(ctx, d.state, fmt.Sprintf("CMD %q", cmd)); err != nil {
return err
}
if len(c.ShellDependantCmdLine.CmdLine) != 0 {
@ -450,7 +454,7 @@ func dispatchCmd(d dispatchRequest, c *instructions.CmdCommand) error {
//
// Set the default healthcheck command to run in the container (which may be empty).
// Argument handling is the same as RUN.
func dispatchHealthcheck(d dispatchRequest, c *instructions.HealthCheckCommand) error {
func dispatchHealthcheck(ctx context.Context, d dispatchRequest, c *instructions.HealthCheckCommand) error {
runConfig := d.state.runConfig
if runConfig.Healthcheck != nil {
oldCmd := runConfig.Healthcheck.Test
@ -459,7 +463,7 @@ func dispatchHealthcheck(d dispatchRequest, c *instructions.HealthCheckCommand)
}
}
runConfig.Healthcheck = c.Health
return d.builder.commit(d.state, fmt.Sprintf("HEALTHCHECK %q", runConfig.Healthcheck))
return d.builder.commit(ctx, d.state, fmt.Sprintf("HEALTHCHECK %q", runConfig.Healthcheck))
}
// ENTRYPOINT /usr/sbin/nginx
@ -469,7 +473,7 @@ func dispatchHealthcheck(d dispatchRequest, c *instructions.HealthCheckCommand)
//
// Handles command processing similar to CMD and RUN, only req.runConfig.Entrypoint
// is initialized at newBuilder time instead of through argument parsing.
func dispatchEntrypoint(d dispatchRequest, c *instructions.EntrypointCommand) error {
func dispatchEntrypoint(ctx context.Context, d dispatchRequest, c *instructions.EntrypointCommand) error {
runConfig := d.state.runConfig
cmd, argsEscaped := resolveCmdLine(c.ShellDependantCmdLine, runConfig, d.state.operatingSystem, c.Name(), c.String())
@ -491,14 +495,14 @@ func dispatchEntrypoint(d dispatchRequest, c *instructions.EntrypointCommand) er
runConfig.Cmd = nil
}
return d.builder.commit(d.state, fmt.Sprintf("ENTRYPOINT %q", runConfig.Entrypoint))
return d.builder.commit(ctx, d.state, fmt.Sprintf("ENTRYPOINT %q", runConfig.Entrypoint))
}
// EXPOSE 6667/tcp 7000/tcp
//
// Expose ports for links and port mappings. This all ends up in
// req.runConfig.ExposedPorts for runconfig.
func dispatchExpose(d dispatchRequest, c *instructions.ExposeCommand, envs []string) error {
func dispatchExpose(ctx context.Context, d dispatchRequest, c *instructions.ExposeCommand, envs []string) error {
// custom multi word expansion
// expose $FOO with FOO="80 443" is expanded as EXPOSE [80,443]. This is the only command supporting word to words expansion
// so the word processing has been de-generalized
@ -524,22 +528,22 @@ func dispatchExpose(d dispatchRequest, c *instructions.ExposeCommand, envs []str
d.state.runConfig.ExposedPorts[p] = struct{}{}
}
return d.builder.commit(d.state, "EXPOSE "+strings.Join(c.Ports, " "))
return d.builder.commit(ctx, d.state, "EXPOSE "+strings.Join(c.Ports, " "))
}
// USER foo
//
// Set the user to 'foo' for future commands and when running the
// ENTRYPOINT/CMD at container run time.
func dispatchUser(d dispatchRequest, c *instructions.UserCommand) error {
func dispatchUser(ctx context.Context, d dispatchRequest, c *instructions.UserCommand) error {
d.state.runConfig.User = c.User
return d.builder.commit(d.state, fmt.Sprintf("USER %v", c.User))
return d.builder.commit(ctx, d.state, fmt.Sprintf("USER %v", c.User))
}
// VOLUME /foo
//
// Expose the volume /foo for use. Will also accept the JSON array form.
func dispatchVolume(d dispatchRequest, c *instructions.VolumeCommand) error {
func dispatchVolume(ctx context.Context, d dispatchRequest, c *instructions.VolumeCommand) error {
if d.state.runConfig.Volumes == nil {
d.state.runConfig.Volumes = map[string]struct{}{}
}
@ -549,19 +553,19 @@ func dispatchVolume(d dispatchRequest, c *instructions.VolumeCommand) error {
}
d.state.runConfig.Volumes[v] = struct{}{}
}
return d.builder.commit(d.state, fmt.Sprintf("VOLUME %v", c.Volumes))
return d.builder.commit(ctx, d.state, fmt.Sprintf("VOLUME %v", c.Volumes))
}
// STOPSIGNAL signal
//
// Set the signal that will be used to kill the container.
func dispatchStopSignal(d dispatchRequest, c *instructions.StopSignalCommand) error {
func dispatchStopSignal(ctx context.Context, d dispatchRequest, c *instructions.StopSignalCommand) error {
_, err := signal.ParseSignal(c.Signal)
if err != nil {
return errdefs.InvalidParameter(err)
}
d.state.runConfig.StopSignal = c.Signal
return d.builder.commit(d.state, fmt.Sprintf("STOPSIGNAL %v", c.Signal))
return d.builder.commit(ctx, d.state, fmt.Sprintf("STOPSIGNAL %v", c.Signal))
}
// ARG name[=value]
@ -569,7 +573,7 @@ func dispatchStopSignal(d dispatchRequest, c *instructions.StopSignalCommand) er
// Adds the variable foo to the trusted list of variables that can be passed
// to builder using the --build-arg flag for expansion/substitution or passing to 'run'.
// Dockerfile author may optionally set a default value of this variable.
func dispatchArg(d dispatchRequest, c *instructions.ArgCommand) error {
func dispatchArg(ctx context.Context, d dispatchRequest, c *instructions.ArgCommand) error {
var commitStr strings.Builder
commitStr.WriteString("ARG ")
for i, arg := range c.Args {
@ -584,13 +588,13 @@ func dispatchArg(d dispatchRequest, c *instructions.ArgCommand) error {
d.state.buildArgs.AddArg(arg.Key, arg.Value)
}
return d.builder.commit(d.state, commitStr.String())
return d.builder.commit(ctx, d.state, commitStr.String())
}
// SHELL powershell -command
//
// Set the non-default shell to use.
func dispatchShell(d dispatchRequest, c *instructions.ShellCommand) error {
func dispatchShell(ctx context.Context, d dispatchRequest, c *instructions.ShellCommand) error {
d.state.runConfig.Shell = c.Shell
return d.builder.commit(d.state, fmt.Sprintf("SHELL %v", d.state.runConfig.Shell))
return d.builder.commit(ctx, d.state, fmt.Sprintf("SHELL %v", d.state.runConfig.Shell))
}

View File

@ -23,10 +23,15 @@ import (
is "gotest.tools/v3/assert/cmp"
)
func newBuilderWithMockBackend() *Builder {
func newBuilderWithMockBackend(t *testing.T) *Builder {
t.Helper()
mockBackend := &MockBackend{}
opts := &types.ImageBuildOptions{}
ctx := context.Background()
imageProber, err := newImageProber(ctx, mockBackend, nil, false)
assert.NilError(t, err, "Could not create image prober")
b := &Builder{
options: opts,
docker: mockBackend,
@ -37,14 +42,14 @@ func newBuilderWithMockBackend() *Builder {
Options: opts,
Backend: mockBackend,
}),
imageProber: newImageProber(mockBackend, nil, false),
imageProber: imageProber,
containerManager: newContainerManager(mockBackend),
}
return b
}
func TestEnv2Variables(t *testing.T) {
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
sb := newDispatchRequest(b, '\\', nil, NewBuildArgs(make(map[string]*string)), newStagesBuildResults())
envCommand := &instructions.EnvCommand{
Env: instructions.KeyValuePairs{
@ -52,7 +57,7 @@ func TestEnv2Variables(t *testing.T) {
instructions.KeyValuePair{Key: "var2", Value: "val2"},
},
}
err := dispatch(sb, envCommand)
err := dispatch(context.TODO(), sb, envCommand)
assert.NilError(t, err)
expected := []string{
@ -63,7 +68,7 @@ func TestEnv2Variables(t *testing.T) {
}
func TestEnvValueWithExistingRunConfigEnv(t *testing.T) {
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
sb := newDispatchRequest(b, '\\', nil, NewBuildArgs(make(map[string]*string)), newStagesBuildResults())
sb.state.runConfig.Env = []string{"var1=old", "var2=fromenv"}
envCommand := &instructions.EnvCommand{
@ -71,7 +76,7 @@ func TestEnvValueWithExistingRunConfigEnv(t *testing.T) {
instructions.KeyValuePair{Key: "var1", Value: "val1"},
},
}
err := dispatch(sb, envCommand)
err := dispatch(context.TODO(), sb, envCommand)
assert.NilError(t, err)
expected := []string{
"var1=val1",
@ -82,10 +87,10 @@ func TestEnvValueWithExistingRunConfigEnv(t *testing.T) {
func TestMaintainer(t *testing.T) {
maintainerEntry := "Some Maintainer <maintainer@example.com>"
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
sb := newDispatchRequest(b, '\\', nil, NewBuildArgs(make(map[string]*string)), newStagesBuildResults())
cmd := &instructions.MaintainerCommand{Maintainer: maintainerEntry}
err := dispatch(sb, cmd)
err := dispatch(context.TODO(), sb, cmd)
assert.NilError(t, err)
assert.Check(t, is.Equal(maintainerEntry, sb.state.maintainer))
}
@ -94,14 +99,14 @@ func TestLabel(t *testing.T) {
labelName := "label"
labelValue := "value"
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
sb := newDispatchRequest(b, '\\', nil, NewBuildArgs(make(map[string]*string)), newStagesBuildResults())
cmd := &instructions.LabelCommand{
Labels: instructions.KeyValuePairs{
instructions.KeyValuePair{Key: labelName, Value: labelValue},
},
}
err := dispatch(sb, cmd)
err := dispatch(context.TODO(), sb, cmd)
assert.NilError(t, err)
assert.Assert(t, is.Contains(sb.state.runConfig.Labels, labelName))
@ -109,12 +114,12 @@ func TestLabel(t *testing.T) {
}
func TestFromScratch(t *testing.T) {
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
sb := newDispatchRequest(b, '\\', nil, NewBuildArgs(make(map[string]*string)), newStagesBuildResults())
cmd := &instructions.Stage{
BaseName: "scratch",
}
err := initializeStage(sb, cmd)
err := initializeStage(context.TODO(), sb, cmd)
if runtime.GOOS == "windows" {
assert.Check(t, is.Error(err, "Windows does not support FROM scratch"))
@ -135,7 +140,7 @@ func TestFromWithArg(t *testing.T) {
assert.Check(t, is.Equal("alpine"+tag, name))
return &mockImage{id: "expectedthisid"}, nil, nil
}
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
b.docker.(*MockBackend).getImageFunc = getImage
args := NewBuildArgs(make(map[string]*string))
@ -151,7 +156,7 @@ func TestFromWithArg(t *testing.T) {
sb := newDispatchRequest(b, '\\', nil, args, newStagesBuildResults())
assert.NilError(t, err)
err = initializeStage(sb, cmd)
err = initializeStage(context.TODO(), sb, cmd)
assert.NilError(t, err)
assert.Check(t, is.Equal(expected, sb.state.imageID))
@ -161,7 +166,7 @@ func TestFromWithArg(t *testing.T) {
}
func TestFromWithArgButBuildArgsNotGiven(t *testing.T) {
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
args := NewBuildArgs(make(map[string]*string))
metaArg := instructions.ArgCommand{}
@ -172,7 +177,7 @@ func TestFromWithArgButBuildArgsNotGiven(t *testing.T) {
sb := newDispatchRequest(b, '\\', nil, args, newStagesBuildResults())
assert.NilError(t, err)
err = initializeStage(sb, cmd)
err = initializeStage(context.TODO(), sb, cmd)
assert.Error(t, err, "base name (${THETAG}) should not be blank")
}
@ -183,7 +188,7 @@ func TestFromWithUndefinedArg(t *testing.T) {
assert.Check(t, is.Equal("alpine", name))
return &mockImage{id: "expectedthisid"}, nil, nil
}
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
b.docker.(*MockBackend).getImageFunc = getImage
sb := newDispatchRequest(b, '\\', nil, NewBuildArgs(make(map[string]*string)), newStagesBuildResults())
@ -192,41 +197,41 @@ func TestFromWithUndefinedArg(t *testing.T) {
cmd := &instructions.Stage{
BaseName: "alpine${THETAG}",
}
err := initializeStage(sb, cmd)
err := initializeStage(context.TODO(), sb, cmd)
assert.NilError(t, err)
assert.Check(t, is.Equal(expected, sb.state.imageID))
}
func TestFromMultiStageWithNamedStage(t *testing.T) {
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
firstFrom := &instructions.Stage{BaseName: "someimg", Name: "base"}
secondFrom := &instructions.Stage{BaseName: "base"}
previousResults := newStagesBuildResults()
firstSB := newDispatchRequest(b, '\\', nil, NewBuildArgs(make(map[string]*string)), previousResults)
secondSB := newDispatchRequest(b, '\\', nil, NewBuildArgs(make(map[string]*string)), previousResults)
err := initializeStage(firstSB, firstFrom)
err := initializeStage(context.TODO(), firstSB, firstFrom)
assert.NilError(t, err)
assert.Check(t, firstSB.state.hasFromImage())
previousResults.indexed["base"] = firstSB.state.runConfig
previousResults.flat = append(previousResults.flat, firstSB.state.runConfig)
err = initializeStage(secondSB, secondFrom)
err = initializeStage(context.TODO(), secondSB, secondFrom)
assert.NilError(t, err)
assert.Check(t, secondSB.state.hasFromImage())
}
func TestOnbuild(t *testing.T) {
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
sb := newDispatchRequest(b, '\\', nil, NewBuildArgs(make(map[string]*string)), newStagesBuildResults())
cmd := &instructions.OnbuildCommand{
Expression: "ADD . /app/src",
}
err := dispatch(sb, cmd)
err := dispatch(context.TODO(), sb, cmd)
assert.NilError(t, err)
assert.Check(t, is.Equal("ADD . /app/src", sb.state.runConfig.OnBuild[0]))
}
func TestWorkdir(t *testing.T) {
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
sb := newDispatchRequest(b, '`', nil, NewBuildArgs(make(map[string]*string)), newStagesBuildResults())
sb.state.baseImage = &mockImage{}
workingDir := "/app"
@ -237,13 +242,13 @@ func TestWorkdir(t *testing.T) {
Path: workingDir,
}
err := dispatch(sb, cmd)
err := dispatch(context.TODO(), sb, cmd)
assert.NilError(t, err)
assert.Check(t, is.Equal(workingDir, sb.state.runConfig.WorkingDir))
}
func TestCmd(t *testing.T) {
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
sb := newDispatchRequest(b, '`', nil, NewBuildArgs(make(map[string]*string)), newStagesBuildResults())
sb.state.baseImage = &mockImage{}
command := "./executable"
@ -254,7 +259,7 @@ func TestCmd(t *testing.T) {
PrependShell: true,
},
}
err := dispatch(sb, cmd)
err := dispatch(context.TODO(), sb, cmd)
assert.NilError(t, err)
var expectedCommand strslice.StrSlice
@ -269,14 +274,14 @@ func TestCmd(t *testing.T) {
}
func TestHealthcheckNone(t *testing.T) {
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
sb := newDispatchRequest(b, '`', nil, NewBuildArgs(make(map[string]*string)), newStagesBuildResults())
cmd := &instructions.HealthCheckCommand{
Health: &container.HealthConfig{
Test: []string{"NONE"},
},
}
err := dispatch(sb, cmd)
err := dispatch(context.TODO(), sb, cmd)
assert.NilError(t, err)
assert.Assert(t, sb.state.runConfig.Healthcheck != nil)
@ -284,7 +289,7 @@ func TestHealthcheckNone(t *testing.T) {
}
func TestHealthcheckCmd(t *testing.T) {
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
sb := newDispatchRequest(b, '`', nil, NewBuildArgs(make(map[string]*string)), newStagesBuildResults())
expectedTest := []string{"CMD-SHELL", "curl -f http://localhost/ || exit 1"}
cmd := &instructions.HealthCheckCommand{
@ -292,7 +297,7 @@ func TestHealthcheckCmd(t *testing.T) {
Test: expectedTest,
},
}
err := dispatch(sb, cmd)
err := dispatch(context.TODO(), sb, cmd)
assert.NilError(t, err)
assert.Assert(t, sb.state.runConfig.Healthcheck != nil)
@ -300,7 +305,7 @@ func TestHealthcheckCmd(t *testing.T) {
}
func TestEntrypoint(t *testing.T) {
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
sb := newDispatchRequest(b, '`', nil, NewBuildArgs(make(map[string]*string)), newStagesBuildResults())
sb.state.baseImage = &mockImage{}
entrypointCmd := "/usr/sbin/nginx"
@ -311,7 +316,7 @@ func TestEntrypoint(t *testing.T) {
PrependShell: true,
},
}
err := dispatch(sb, cmd)
err := dispatch(context.TODO(), sb, cmd)
assert.NilError(t, err)
assert.Assert(t, sb.state.runConfig.Entrypoint != nil)
@ -325,14 +330,14 @@ func TestEntrypoint(t *testing.T) {
}
func TestExpose(t *testing.T) {
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
sb := newDispatchRequest(b, '`', nil, NewBuildArgs(make(map[string]*string)), newStagesBuildResults())
exposedPort := "80"
cmd := &instructions.ExposeCommand{
Ports: []string{exposedPort},
}
err := dispatch(sb, cmd)
err := dispatch(context.TODO(), sb, cmd)
assert.NilError(t, err)
assert.Assert(t, sb.state.runConfig.ExposedPorts != nil)
@ -344,19 +349,19 @@ func TestExpose(t *testing.T) {
}
func TestUser(t *testing.T) {
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
sb := newDispatchRequest(b, '`', nil, NewBuildArgs(make(map[string]*string)), newStagesBuildResults())
cmd := &instructions.UserCommand{
User: "test",
}
err := dispatch(sb, cmd)
err := dispatch(context.TODO(), sb, cmd)
assert.NilError(t, err)
assert.Check(t, is.Equal("test", sb.state.runConfig.User))
}
func TestVolume(t *testing.T) {
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
sb := newDispatchRequest(b, '`', nil, NewBuildArgs(make(map[string]*string)), newStagesBuildResults())
exposedVolume := "/foo"
@ -364,7 +369,7 @@ func TestVolume(t *testing.T) {
cmd := &instructions.VolumeCommand{
Volumes: []string{exposedVolume},
}
err := dispatch(sb, cmd)
err := dispatch(context.TODO(), sb, cmd)
assert.NilError(t, err)
assert.Assert(t, sb.state.runConfig.Volumes != nil)
assert.Check(t, is.Len(sb.state.runConfig.Volumes, 1))
@ -376,7 +381,7 @@ func TestStopSignal(t *testing.T) {
t.Skip("Windows does not support stopsignal")
return
}
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
sb := newDispatchRequest(b, '`', nil, NewBuildArgs(make(map[string]*string)), newStagesBuildResults())
sb.state.baseImage = &mockImage{}
signal := "SIGKILL"
@ -384,19 +389,19 @@ func TestStopSignal(t *testing.T) {
cmd := &instructions.StopSignalCommand{
Signal: signal,
}
err := dispatch(sb, cmd)
err := dispatch(context.TODO(), sb, cmd)
assert.NilError(t, err)
assert.Check(t, is.Equal(signal, sb.state.runConfig.StopSignal))
}
func TestArg(t *testing.T) {
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
sb := newDispatchRequest(b, '`', nil, NewBuildArgs(make(map[string]*string)), newStagesBuildResults())
argName := "foo"
argVal := "bar"
cmd := &instructions.ArgCommand{Args: []instructions.KeyValuePairOptional{{Key: argName, Value: &argVal}}}
err := dispatch(sb, cmd)
err := dispatch(context.TODO(), sb, cmd)
assert.NilError(t, err)
expected := map[string]string{argName: argVal}
@ -404,13 +409,13 @@ func TestArg(t *testing.T) {
}
func TestShell(t *testing.T) {
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
sb := newDispatchRequest(b, '`', nil, NewBuildArgs(make(map[string]*string)), newStagesBuildResults())
shellCmd := "powershell"
cmd := &instructions.ShellCommand{Shell: strslice.StrSlice{shellCmd}}
err := dispatch(sb, cmd)
err := dispatch(context.TODO(), sb, cmd)
assert.NilError(t, err)
expectedShell := strslice.StrSlice([]string{shellCmd})
@ -430,7 +435,7 @@ func TestPrependEnvOnCmd(t *testing.T) {
}
func TestRunWithBuildArgs(t *testing.T) {
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
args := NewBuildArgs(make(map[string]*string))
args.argsFromOptions["HTTP_PROXY"] = strPtr("FOO")
b.disableCommit = false
@ -462,7 +467,11 @@ func TestRunWithBuildArgs(t *testing.T) {
mockBackend.makeImageCacheFunc = func(_ []string) builder.ImageCache {
return imageCache
}
b.imageProber = newImageProber(mockBackend, nil, false)
imageProber, err := newImageProber(context.TODO(), mockBackend, nil, false)
assert.NilError(t, err, "Could not create image prober")
b.imageProber = imageProber
mockBackend.getImageFunc = func(_ string) (builder.Image, builder.ROLayer, error) {
return &mockImage{
id: "abcdef",
@ -484,7 +493,7 @@ func TestRunWithBuildArgs(t *testing.T) {
return "", nil
}
from := &instructions.Stage{BaseName: "abcdef"}
err := initializeStage(sb, from)
err = initializeStage(context.TODO(), sb, from)
assert.NilError(t, err)
sb.state.buildArgs.AddArg("one", strPtr("two"))
@ -504,14 +513,14 @@ func TestRunWithBuildArgs(t *testing.T) {
runinst.CmdLine = strslice.StrSlice{"echo foo"}
runinst.PrependShell = true
assert.NilError(t, dispatch(sb, runinst))
assert.NilError(t, dispatch(context.TODO(), sb, runinst))
// Check that runConfig.Cmd has not been modified by run
assert.Check(t, is.DeepEqual(origCmd, sb.state.runConfig.Cmd))
}
func TestRunIgnoresHealthcheck(t *testing.T) {
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
args := NewBuildArgs(make(map[string]*string))
sb := newDispatchRequest(b, '`', nil, args, newStagesBuildResults())
b.disableCommit = false
@ -528,7 +537,10 @@ func TestRunIgnoresHealthcheck(t *testing.T) {
mockBackend.makeImageCacheFunc = func(_ []string) builder.ImageCache {
return imageCache
}
b.imageProber = newImageProber(mockBackend, nil, false)
imageProber, err := newImageProber(context.TODO(), mockBackend, nil, false)
assert.NilError(t, err, "Could not create image prober")
b.imageProber = imageProber
mockBackend.getImageFunc = func(_ string) (builder.Image, builder.ROLayer, error) {
return &mockImage{
id: "abcdef",
@ -542,7 +554,7 @@ func TestRunIgnoresHealthcheck(t *testing.T) {
return "", nil
}
from := &instructions.Stage{BaseName: "abcdef"}
err := initializeStage(sb, from)
err = initializeStage(context.TODO(), sb, from)
assert.NilError(t, err)
expectedTest := []string{"CMD-SHELL", "curl -f http://localhost/ || exit 1"}
@ -559,7 +571,7 @@ func TestRunIgnoresHealthcheck(t *testing.T) {
assert.NilError(t, err)
cmd := healthint.(*instructions.HealthCheckCommand)
assert.NilError(t, dispatch(sb, cmd))
assert.NilError(t, dispatch(context.TODO(), sb, cmd))
assert.Assert(t, sb.state.runConfig.Healthcheck != nil)
mockBackend.containerCreateFunc = func(config types.ContainerCreateConfig) (container.CreateResponse, error) {
@ -574,12 +586,12 @@ func TestRunIgnoresHealthcheck(t *testing.T) {
run := runint.(*instructions.RunCommand)
run.PrependShell = true
assert.NilError(t, dispatch(sb, run))
assert.NilError(t, dispatch(context.TODO(), sb, run))
assert.Check(t, is.DeepEqual(expectedTest, sb.state.runConfig.Healthcheck.Test))
}
func TestDispatchUnsupportedOptions(t *testing.T) {
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
sb := newDispatchRequest(b, '`', nil, NewBuildArgs(make(map[string]*string)), newStagesBuildResults())
sb.state.baseImage = &mockImage{}
sb.state.operatingSystem = runtime.GOOS
@ -592,7 +604,7 @@ func TestDispatchUnsupportedOptions(t *testing.T) {
},
Chmod: "0655",
}
err := dispatch(sb, cmd)
err := dispatch(context.TODO(), sb, cmd)
assert.Error(t, err, "the --chmod option requires BuildKit. Refer to https://docs.docker.com/go/buildkit/ to learn how to build images with BuildKit enabled")
})
@ -604,7 +616,7 @@ func TestDispatchUnsupportedOptions(t *testing.T) {
},
Chmod: "0655",
}
err := dispatch(sb, cmd)
err := dispatch(context.TODO(), sb, cmd)
assert.Error(t, err, "the --chmod option requires BuildKit. Refer to https://docs.docker.com/go/buildkit/ to learn how to build images with BuildKit enabled")
})
@ -618,7 +630,7 @@ func TestDispatchUnsupportedOptions(t *testing.T) {
// one or more of these flags will be supported in future
for _, f := range []string{"mount", "network", "security", "any-flag"} {
cmd.FlagsUsed = []string{f}
err := dispatch(sb, cmd)
err := dispatch(context.TODO(), sb, cmd)
assert.Error(t, err, fmt.Sprintf("the --%s option requires BuildKit. Refer to https://docs.docker.com/go/buildkit/ to learn how to build images with BuildKit enabled", f))
}
})

View File

@ -20,6 +20,7 @@
package dockerfile // import "github.com/docker/docker/builder/dockerfile"
import (
"context"
"reflect"
"strconv"
"strings"
@ -34,7 +35,7 @@ import (
"github.com/pkg/errors"
)
func dispatch(d dispatchRequest, cmd instructions.Command) (err error) {
func dispatch(ctx context.Context, d dispatchRequest, cmd instructions.Command) (err error) {
if c, ok := cmd.(instructions.PlatformSpecific); ok {
err := c.CheckPlatform(d.state.operatingSystem)
if err != nil {
@ -65,39 +66,39 @@ func dispatch(d dispatchRequest, cmd instructions.Command) (err error) {
}()
switch c := cmd.(type) {
case *instructions.EnvCommand:
return dispatchEnv(d, c)
return dispatchEnv(ctx, d, c)
case *instructions.MaintainerCommand:
return dispatchMaintainer(d, c)
return dispatchMaintainer(ctx, d, c)
case *instructions.LabelCommand:
return dispatchLabel(d, c)
return dispatchLabel(ctx, d, c)
case *instructions.AddCommand:
return dispatchAdd(d, c)
return dispatchAdd(ctx, d, c)
case *instructions.CopyCommand:
return dispatchCopy(d, c)
return dispatchCopy(ctx, d, c)
case *instructions.OnbuildCommand:
return dispatchOnbuild(d, c)
return dispatchOnbuild(ctx, d, c)
case *instructions.WorkdirCommand:
return dispatchWorkdir(d, c)
return dispatchWorkdir(ctx, d, c)
case *instructions.RunCommand:
return dispatchRun(d, c)
return dispatchRun(ctx, d, c)
case *instructions.CmdCommand:
return dispatchCmd(d, c)
return dispatchCmd(ctx, d, c)
case *instructions.HealthCheckCommand:
return dispatchHealthcheck(d, c)
return dispatchHealthcheck(ctx, d, c)
case *instructions.EntrypointCommand:
return dispatchEntrypoint(d, c)
return dispatchEntrypoint(ctx, d, c)
case *instructions.ExposeCommand:
return dispatchExpose(d, c, envs)
return dispatchExpose(ctx, d, c, envs)
case *instructions.UserCommand:
return dispatchUser(d, c)
return dispatchUser(ctx, d, c)
case *instructions.VolumeCommand:
return dispatchVolume(d, c)
return dispatchVolume(ctx, d, c)
case *instructions.StopSignalCommand:
return dispatchStopSignal(d, c)
return dispatchStopSignal(ctx, d, c)
case *instructions.ArgCommand:
return dispatchArg(d, c)
return dispatchArg(ctx, d, c)
case *instructions.ShellCommand:
return dispatchShell(d, c)
return dispatchShell(ctx, d, c)
}
return errors.Errorf("unsupported command type: %v", reflect.TypeOf(cmd))
}

View File

@ -1,6 +1,7 @@
package dockerfile // import "github.com/docker/docker/builder/dockerfile"
import (
"context"
"os"
"runtime"
"testing"
@ -127,9 +128,9 @@ func TestDispatch(t *testing.T) {
}
}()
b := newBuilderWithMockBackend()
b := newBuilderWithMockBackend(t)
sb := newDispatchRequest(b, '`', buildContext, NewBuildArgs(make(map[string]*string)), newStagesBuildResults())
err = dispatch(sb, tc.cmd)
err = dispatch(context.TODO(), sb, tc.cmd)
assert.Check(t, is.ErrorContains(err, tc.expectedError))
})
}

View File

@ -1,6 +1,8 @@
package dockerfile // import "github.com/docker/docker/builder/dockerfile"
import (
"context"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/builder"
"github.com/sirupsen/logrus"
@ -9,30 +11,42 @@ import (
// ImageProber exposes an Image cache to the Builder. It supports resetting a
// cache.
type ImageProber interface {
Reset()
Reset(ctx context.Context) error
Probe(parentID string, runConfig *container.Config) (string, error)
}
type resetFunc func(context.Context) (builder.ImageCache, error)
type imageProber struct {
cache builder.ImageCache
reset func() builder.ImageCache
reset resetFunc
cacheBusted bool
}
func newImageProber(cacheBuilder builder.ImageCacheBuilder, cacheFrom []string, noCache bool) ImageProber {
func newImageProber(ctx context.Context, cacheBuilder builder.ImageCacheBuilder, cacheFrom []string, noCache bool) (ImageProber, error) {
if noCache {
return &nopProber{}
return &nopProber{}, nil
}
reset := func() builder.ImageCache {
return cacheBuilder.MakeImageCache(cacheFrom)
reset := func(ctx context.Context) (builder.ImageCache, error) {
return cacheBuilder.MakeImageCache(ctx, cacheFrom)
}
return &imageProber{cache: reset(), reset: reset}
cache, err := reset(ctx)
if err != nil {
return nil, err
}
return &imageProber{cache: cache, reset: reset}, nil
}
func (c *imageProber) Reset() {
c.cache = c.reset()
func (c *imageProber) Reset(ctx context.Context) error {
newCache, err := c.reset(ctx)
if err != nil {
return err
}
c.cache = newCache
c.cacheBusted = false
return nil
}
// Probe checks if cache match can be found for current build instruction.
@ -56,7 +70,9 @@ func (c *imageProber) Probe(parentID string, runConfig *container.Config) (strin
type nopProber struct{}
func (c *nopProber) Reset() {}
func (c *nopProber) Reset(ctx context.Context) error {
return nil
}
func (c *nopProber) Probe(_ string, _ *container.Config) (string, error) {
return "", nil

View File

@ -4,6 +4,7 @@ package dockerfile // import "github.com/docker/docker/builder/dockerfile"
// non-contiguous functionality. Please read the comments.
import (
"context"
"crypto/sha256"
"encoding/hex"
"fmt"
@ -27,7 +28,7 @@ func (b *Builder) getArchiver() *archive.Archiver {
return chrootarchive.NewArchiver(b.idMapping)
}
func (b *Builder) commit(dispatchState *dispatchState, comment string) error {
func (b *Builder) commit(ctx context.Context, dispatchState *dispatchState, comment string) error {
if b.disableCommit {
return nil
}
@ -36,7 +37,7 @@ func (b *Builder) commit(dispatchState *dispatchState, comment string) error {
}
runConfigWithCommentCmd := copyRunConfig(dispatchState.runConfig, withCmdComment(comment, dispatchState.operatingSystem))
id, err := b.probeAndCreate(dispatchState, runConfigWithCommentCmd)
id, err := b.probeAndCreate(ctx, dispatchState, runConfigWithCommentCmd)
if err != nil || id == "" {
return err
}
@ -107,7 +108,7 @@ func (b *Builder) exportImage(state *dispatchState, layer builder.RWLayer, paren
return nil
}
func (b *Builder) performCopy(req dispatchRequest, inst copyInstruction) error {
func (b *Builder) performCopy(ctx context.Context, req dispatchRequest, inst copyInstruction) error {
state := req.state
srcHash := getSourceHashFromInfos(inst.infos)
@ -147,7 +148,7 @@ func (b *Builder) performCopy(req dispatchRequest, inst copyInstruction) error {
// translated (if necessary because of user namespaces), and replace
// the root pair with the chown pair for copy operations
if inst.chownStr != "" {
identity, err = parseChownFlag(b, state, inst.chownStr, destInfo.root, b.idMapping)
identity, err = parseChownFlag(ctx, b, state, inst.chownStr, destInfo.root, b.idMapping)
if err != nil {
if b.options.Platform != "windows" {
return errors.Wrapf(err, "unable to convert uid/gid chown string to host mapping")
@ -331,18 +332,18 @@ func (b *Builder) probeCache(dispatchState *dispatchState, runConfig *container.
var defaultLogConfig = container.LogConfig{Type: "none"}
func (b *Builder) probeAndCreate(dispatchState *dispatchState, runConfig *container.Config) (string, error) {
func (b *Builder) probeAndCreate(ctx context.Context, dispatchState *dispatchState, runConfig *container.Config) (string, error) {
if hit, err := b.probeCache(dispatchState, runConfig); err != nil || hit {
return "", err
}
return b.create(runConfig)
return b.create(ctx, runConfig)
}
func (b *Builder) create(runConfig *container.Config) (string, error) {
func (b *Builder) create(ctx context.Context, runConfig *container.Config) (string, error) {
logrus.Debugf("[BUILDER] Command to be executed: %v", runConfig.Cmd)
hostConfig := hostConfigFromOptions(b.options)
container, err := b.containerManager.Create(runConfig, hostConfig)
container, err := b.containerManager.Create(ctx, runConfig, hostConfig)
if err != nil {
return "", err
}

View File

@ -1,6 +1,7 @@
package dockerfile // import "github.com/docker/docker/builder/dockerfile"
import (
"context"
"path/filepath"
"strconv"
"strings"
@ -11,7 +12,7 @@ import (
"github.com/pkg/errors"
)
func parseChownFlag(builder *Builder, state *dispatchState, chown, ctrRootPath string, identityMapping idtools.IdentityMapping) (idtools.Identity, error) {
func parseChownFlag(ctx context.Context, builder *Builder, state *dispatchState, chown, ctrRootPath string, identityMapping idtools.IdentityMapping) (idtools.Identity, error) {
var userStr, grpStr string
parts := strings.Split(chown, ":")
if len(parts) > 2 {

View File

@ -1,6 +1,7 @@
package dockerfile // import "github.com/docker/docker/builder/dockerfile"
import (
"context"
"os"
"path/filepath"
"testing"
@ -115,7 +116,7 @@ othergrp:x:6666:
},
} {
t.Run(testcase.name, func(t *testing.T) {
idPair, err := parseChownFlag(testcase.builder, testcase.state, testcase.chownStr, contextDir, testcase.idMapping)
idPair, err := parseChownFlag(context.TODO(), testcase.builder, testcase.state, testcase.chownStr, contextDir, testcase.idMapping)
assert.NilError(t, err, "Failed to parse chown flag: %q", testcase.chownStr)
assert.Check(t, is.DeepEqual(testcase.expected, idPair), "chown flag mapping failure")
})
@ -156,7 +157,7 @@ othergrp:x:6666:
},
} {
t.Run(testcase.name, func(t *testing.T) {
_, err := parseChownFlag(testcase.builder, testcase.state, testcase.chownStr, contextDir, testcase.idMapping)
_, err := parseChownFlag(context.TODO(), testcase.builder, testcase.state, testcase.chownStr, contextDir, testcase.idMapping)
assert.Check(t, is.Error(err, testcase.descr), "Expected error string doesn't match")
})
}

View File

@ -2,6 +2,7 @@ package dockerfile // import "github.com/docker/docker/builder/dockerfile"
import (
"bytes"
"context"
"os"
"path/filepath"
"strings"
@ -14,15 +15,15 @@ import (
"golang.org/x/sys/windows"
)
func parseChownFlag(builder *Builder, state *dispatchState, chown, ctrRootPath string, identityMapping idtools.IdentityMapping) (idtools.Identity, error) {
func parseChownFlag(ctx context.Context, builder *Builder, state *dispatchState, chown, ctrRootPath string, identityMapping idtools.IdentityMapping) (idtools.Identity, error) {
if builder.options.Platform == "windows" {
return getAccountIdentity(builder, chown, ctrRootPath, state)
return getAccountIdentity(ctx, builder, chown, ctrRootPath, state)
}
return identityMapping.RootPair(), nil
}
func getAccountIdentity(builder *Builder, accountName string, ctrRootPath string, state *dispatchState) (idtools.Identity, error) {
func getAccountIdentity(ctx context.Context, builder *Builder, accountName string, ctrRootPath string, state *dispatchState) (idtools.Identity, error) {
// If this is potentially a string SID then attempt to convert it to verify
// this, otherwise continue looking for the account.
if strings.HasPrefix(accountName, "S-") || strings.HasPrefix(accountName, "s-") {
@ -51,10 +52,10 @@ func getAccountIdentity(builder *Builder, accountName string, ctrRootPath string
// All other lookups failed, so therefore determine if the account in
// question exists in the container and if so, obtain its SID.
return lookupNTAccount(builder, accountName, state)
return lookupNTAccount(ctx, builder, accountName, state)
}
func lookupNTAccount(builder *Builder, accountName string, state *dispatchState) (idtools.Identity, error) {
func lookupNTAccount(ctx context.Context, builder *Builder, accountName string, state *dispatchState) (idtools.Identity, error) {
source, _ := filepath.Split(os.Args[0])
@ -81,7 +82,7 @@ func lookupNTAccount(builder *Builder, accountName string, state *dispatchState)
},
}
container, err := builder.containerManager.Create(runConfig, hostConfig)
container, err := builder.containerManager.Create(ctx, runConfig, hostConfig)
if err != nil {
return idtools.Identity{}, err
}

View File

@ -27,7 +27,7 @@ func (m *MockBackend) ContainerAttachRaw(cID string, stdin io.ReadCloser, stdout
return nil
}
func (m *MockBackend) ContainerCreateIgnoreImagesArgsEscaped(config types.ContainerCreateConfig) (container.CreateResponse, error) {
func (m *MockBackend) ContainerCreateIgnoreImagesArgsEscaped(ctx context.Context, config types.ContainerCreateConfig) (container.CreateResponse, error) {
if m.containerCreateFunc != nil {
return m.containerCreateFunc(config)
}
@ -49,7 +49,7 @@ func (m *MockBackend) ContainerKill(containerID string, sig string) error {
return nil
}
func (m *MockBackend) ContainerStart(containerID string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error {
func (m *MockBackend) ContainerStart(ctx context.Context, containerID string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error {
return nil
}
@ -73,11 +73,11 @@ func (m *MockBackend) GetImageAndReleasableLayer(ctx context.Context, refOrID st
return &mockImage{id: "theid"}, &mockLayer{}, nil
}
func (m *MockBackend) MakeImageCache(cacheFrom []string) builder.ImageCache {
func (m *MockBackend) MakeImageCache(ctx context.Context, cacheFrom []string) (builder.ImageCache, error) {
if m.makeImageCacheFunc != nil {
return m.makeImageCacheFunc(cacheFrom)
return m.makeImageCacheFunc(cacheFrom), nil
}
return nil
return nil, nil
}
func (m *MockBackend) CreateImage(config []byte, parent string) (builder.Image, error) {

View File

@ -252,7 +252,7 @@ func (cli *DaemonCli) start(opts *daemonOptions) (err error) {
// notify systemd that we're shutting down
notifyStopping()
shutdownDaemon(d)
shutdownDaemon(ctx, d)
// Stop notification processing and any background processes
cancel()
@ -359,11 +359,11 @@ func (cli *DaemonCli) stop() {
// shutdownDaemon just wraps daemon.Shutdown() to handle a timeout in case
// d.Shutdown() is waiting too long to kill container or worst it's
// blocked there
func shutdownDaemon(d *daemon.Daemon) {
func shutdownDaemon(ctx context.Context, d *daemon.Daemon) {
shutdownTimeout := d.ShutdownTimeout()
ch := make(chan struct{})
go func() {
d.Shutdown()
d.Shutdown(ctx)
close(ch)
}()
if shutdownTimeout < 0 {

View File

@ -37,8 +37,8 @@ type Backend interface {
FindNetwork(idName string) (libnetwork.Network, error)
SetupIngress(clustertypes.NetworkCreateRequest, string) (<-chan struct{}, error)
ReleaseIngress() (<-chan struct{}, error)
CreateManagedContainer(config types.ContainerCreateConfig) (container.CreateResponse, error)
ContainerStart(name string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
CreateManagedContainer(ctx context.Context, config types.ContainerCreateConfig) (container.CreateResponse, error)
ContainerStart(ctx context.Context, name string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
ContainerStop(ctx context.Context, name string, config container.StopOptions) error
ContainerLogs(ctx context.Context, name string, config *types.ContainerLogsOptions) (msgs <-chan *backend.LogMessage, tty bool, err error)
ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error
@ -53,7 +53,7 @@ type Backend interface {
SetContainerSecretReferences(name string, refs []*swarm.SecretReference) error
SetContainerConfigReferences(name string, refs []*swarm.ConfigReference) error
SystemInfo() *types.Info
Containers(config *types.ContainerListOptions) ([]*types.Container, error)
Containers(ctx context.Context, config *types.ContainerListOptions) ([]*types.Container, error)
SetNetworkBootstrapKeys([]*networktypes.EncryptionKey) error
DaemonJoinsCluster(provider cluster.Provider)
DaemonLeavesCluster()

View File

@ -290,7 +290,7 @@ func (c *containerAdapter) waitForDetach(ctx context.Context) error {
func (c *containerAdapter) create(ctx context.Context) error {
var cr containertypes.CreateResponse
var err error
if cr, err = c.backend.CreateManagedContainer(types.ContainerCreateConfig{
if cr, err = c.backend.CreateManagedContainer(ctx, types.ContainerCreateConfig{
Name: c.container.name(),
Config: c.container.config(),
HostConfig: c.container.hostConfig(c.dependencies.Volumes()),
@ -357,7 +357,7 @@ func (c *containerAdapter) start(ctx context.Context) error {
return err
}
return c.backend.ContainerStart(c.container.name(), nil, "", "")
return c.backend.ContainerStart(ctx, c.container.name(), nil, "", "")
}
func (c *containerAdapter) inspect(ctx context.Context) (types.ContainerJSON, error) {

View File

@ -356,7 +356,7 @@ func (c *Cluster) UnlockSwarm(req types.UnlockRequest) error {
}
// Leave shuts down Cluster and removes current state.
func (c *Cluster) Leave(force bool) error {
func (c *Cluster) Leave(ctx context.Context, force bool) error {
c.controlMutex.Lock()
defer c.controlMutex.Unlock()
@ -408,7 +408,7 @@ func (c *Cluster) Leave(force bool) error {
c.mu.Unlock()
if nodeID := state.NodeID(); nodeID != "" {
nodeContainers, err := c.listContainerForNode(nodeID)
nodeContainers, err := c.listContainerForNode(ctx, nodeID)
if err != nil {
return err
}
@ -604,11 +604,11 @@ func initClusterSpec(node *swarmnode.Node, spec types.Spec) error {
return ctx.Err()
}
func (c *Cluster) listContainerForNode(nodeID string) ([]string, error) {
func (c *Cluster) listContainerForNode(ctx context.Context, nodeID string) ([]string, error) {
var ids []string
filters := filters.NewArgs()
filters.Add("label", fmt.Sprintf("com.docker.swarm.node.id=%s", nodeID))
containers, err := c.config.Backend.Containers(&apitypes.ContainerListOptions{
containers, err := c.config.Backend.Containers(ctx, &apitypes.ContainerListOptions{
Filters: filters,
})
if err != nil {

View File

@ -1,6 +1,7 @@
package daemon // import "github.com/docker/docker/daemon"
import (
"context"
"fmt"
"runtime"
"strings"
@ -116,7 +117,7 @@ func merge(userConf, imageConf *containertypes.Config) error {
// CreateImageFromContainer creates a new image from a container. The container
// config will be updated by applying the change set to the custom config, then
// applying that config over the existing container config.
func (daemon *Daemon) CreateImageFromContainer(name string, c *backend.CreateImageConfig) (string, error) {
func (daemon *Daemon) CreateImageFromContainer(ctx context.Context, name string, c *backend.CreateImageConfig) (string, error) {
start := time.Now()
container, err := daemon.GetContainer(name)
if err != nil {
@ -146,7 +147,7 @@ func (daemon *Daemon) CreateImageFromContainer(name string, c *backend.CreateIma
if c.Config == nil {
c.Config = container.Config
}
newConfig, err := dockerfile.BuildFromConfig(c.Config, c.Changes, container.OS)
newConfig, err := dockerfile.BuildFromConfig(ctx, c.Config, c.Changes, container.OS)
if err != nil {
return "", err
}

View File

@ -1,10 +1,12 @@
package containerd
import (
"context"
"github.com/docker/docker/builder"
)
// MakeImageCache creates a stateful image cache.
func (i *ImageService) MakeImageCache(cacheFrom []string) builder.ImageCache {
func (i *ImageService) MakeImageCache(ctx context.Context, cacheFrom []string) (builder.ImageCache, error) {
panic("not implemented")
}

View File

@ -1,6 +1,7 @@
package containerd
import (
"context"
"errors"
"io"
@ -12,6 +13,6 @@ import (
// inConfig (if src is "-"), or from a URI specified in src. Progress output is
// written to outStream. Repository and tag names can optionally be given in
// the repo and tag arguments, respectively.
func (i *ImageService) ImportImage(src string, repository string, platform *specs.Platform, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error {
func (i *ImageService) ImportImage(ctx context.Context, src string, repository string, platform *specs.Platform, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error {
return errdefs.NotImplemented(errors.New("not implemented"))
}

View File

@ -33,31 +33,30 @@ type createOpts struct {
}
// CreateManagedContainer creates a container that is managed by a Service
func (daemon *Daemon) CreateManagedContainer(params types.ContainerCreateConfig) (containertypes.CreateResponse, error) {
return daemon.containerCreate(createOpts{
func (daemon *Daemon) CreateManagedContainer(ctx context.Context, params types.ContainerCreateConfig) (containertypes.CreateResponse, error) {
return daemon.containerCreate(ctx, createOpts{
params: params,
managed: true,
})
}
// ContainerCreate creates a regular container
func (daemon *Daemon) ContainerCreate(params types.ContainerCreateConfig) (containertypes.CreateResponse, error) {
return daemon.containerCreate(createOpts{
func (daemon *Daemon) ContainerCreate(ctx context.Context, params types.ContainerCreateConfig) (containertypes.CreateResponse, error) {
return daemon.containerCreate(ctx, createOpts{
params: params,
})
}
// ContainerCreateIgnoreImagesArgsEscaped creates a regular container. This is called from the builder RUN case
// and ensures that we do not take the images ArgsEscaped
func (daemon *Daemon) ContainerCreateIgnoreImagesArgsEscaped(params types.ContainerCreateConfig) (containertypes.CreateResponse, error) {
return daemon.containerCreate(createOpts{
func (daemon *Daemon) ContainerCreateIgnoreImagesArgsEscaped(ctx context.Context, params types.ContainerCreateConfig) (containertypes.CreateResponse, error) {
return daemon.containerCreate(ctx, createOpts{
params: params,
ignoreImagesArgsEscaped: true,
})
}
func (daemon *Daemon) containerCreate(opts createOpts) (containertypes.CreateResponse, error) {
ctx := context.TODO()
func (daemon *Daemon) containerCreate(ctx context.Context, opts createOpts) (containertypes.CreateResponse, error) {
start := time.Now()
if opts.params.Config == nil {
return containertypes.CreateResponse{}, errdefs.InvalidParameter(errors.New("Config cannot be empty in order to create a container"))
@ -100,7 +99,7 @@ func (daemon *Daemon) containerCreate(opts createOpts) (containertypes.CreateRes
return containertypes.CreateResponse{Warnings: warnings}, errdefs.InvalidParameter(err)
}
ctr, err := daemon.create(opts)
ctr, err := daemon.create(ctx, opts)
if err != nil {
return containertypes.CreateResponse{Warnings: warnings}, err
}
@ -114,8 +113,7 @@ func (daemon *Daemon) containerCreate(opts createOpts) (containertypes.CreateRes
}
// Create creates a new container from the given configuration with a given name.
func (daemon *Daemon) create(opts createOpts) (retC *container.Container, retErr error) {
ctx := context.TODO()
func (daemon *Daemon) create(ctx context.Context, opts createOpts) (retC *container.Container, retErr error) {
var (
ctr *container.Container
img *image.Image

View File

@ -526,7 +526,7 @@ func (daemon *Daemon) restore() error {
if err := daemon.prepareMountPoints(c); err != nil {
log.WithError(err).Error("failed to prepare mount points for container")
}
if err := daemon.containerStart(c, "", "", true); err != nil {
if err := daemon.containerStart(context.Background(), c, "", "", true); err != nil {
log.WithError(err).Error("failed to start container")
}
close(chNotify)
@ -617,7 +617,7 @@ func (daemon *Daemon) RestartSwarmContainers() {
return
}
if err := daemon.containerStart(c, "", "", true); err != nil {
if err := daemon.containerStart(ctx, c, "", "", true); err != nil {
logrus.WithField("container", c.ID).WithError(err).Error("failed to start swarm container")
}
@ -775,7 +775,8 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S
// initialization
defer func() {
if err != nil {
if err := d.Shutdown(); err != nil {
// Use a fresh context here. Passed context could be cancelled.
if err := d.Shutdown(context.Background()); err != nil {
logrus.Error(err)
}
}
@ -1193,17 +1194,17 @@ func (daemon *Daemon) ShutdownTimeout() int {
}
// Shutdown stops the daemon.
func (daemon *Daemon) Shutdown() error {
func (daemon *Daemon) Shutdown(ctx context.Context) error {
daemon.shutdown = true
// Keep mounts and networking running on daemon shutdown if
// we are to keep containers running and restore them.
if daemon.configStore.LiveRestoreEnabled && daemon.containers != nil {
// check if there are any running containers, if none we should do some cleanup
if ls, err := daemon.Containers(&types.ContainerListOptions{}); len(ls) != 0 || err != nil {
if ls, err := daemon.Containers(ctx, &types.ContainerListOptions{}); len(ls) != 0 || err != nil {
// metrics plugins still need some cleanup
daemon.cleanupMetricsPlugins()
return nil
return err
}
}

View File

@ -14,7 +14,7 @@ import (
func (daemon *Daemon) ContainerDiskUsage(ctx context.Context) ([]*types.Container, error) {
ch := daemon.usage.DoChan("ContainerDiskUsage", func() (interface{}, error) {
// Retrieve container list
containers, err := daemon.Containers(&types.ContainerListOptions{
containers, err := daemon.Containers(context.TODO(), &types.ContainerListOptions{
Size: true,
All: true,
})

View File

@ -37,7 +37,7 @@ type ImageService interface {
CountImages() int
ImageDiskUsage(ctx context.Context) ([]*types.ImageSummary, error)
ImagesPrune(ctx context.Context, pruneFilters filters.Args) (*types.ImagesPruneReport, error)
ImportImage(src string, repository string, platform *v1.Platform, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error
ImportImage(ctx context.Context, src string, repository string, platform *v1.Platform, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error
TagImage(imageName, repository, tag string) (string, error)
TagImageWithReference(imageID image.ID, newTag reference.Named) error
GetImage(ctx context.Context, refOrID string, options imagetype.GetImageOpts) (*image.Image, error)
@ -62,7 +62,7 @@ type ImageService interface {
// Build
MakeImageCache(sourceRefs []string) builder.ImageCache
MakeImageCache(ctx context.Context, cacheFrom []string) (builder.ImageCache, error)
CommitBuildStep(c backend.CommitConfig) (image.ID, error)
// Other

View File

@ -6,14 +6,14 @@ import (
imagetypes "github.com/docker/docker/api/types/image"
"github.com/docker/docker/builder"
"github.com/docker/docker/image/cache"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
// MakeImageCache creates a stateful image cache.
func (i *ImageService) MakeImageCache(sourceRefs []string) builder.ImageCache {
ctx := context.TODO()
func (i *ImageService) MakeImageCache(ctx context.Context, sourceRefs []string) (builder.ImageCache, error) {
if len(sourceRefs) == 0 {
return cache.NewLocal(i.imageStore)
return cache.NewLocal(i.imageStore), nil
}
cache := cache.New(i.imageStore)
@ -21,11 +21,14 @@ func (i *ImageService) MakeImageCache(sourceRefs []string) builder.ImageCache {
for _, ref := range sourceRefs {
img, err := i.GetImage(ctx, ref, imagetypes.GetImageOpts{})
if err != nil {
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
return nil, err
}
logrus.Warnf("Could not look up %s for cache resolution, skipping: %+v", ref, err)
continue
}
cache.Populate(img)
}
return cache
return cache, nil
}

View File

@ -1,6 +1,7 @@
package images // import "github.com/docker/docker/daemon/images"
import (
"context"
"encoding/json"
"io"
"net/http"
@ -29,7 +30,7 @@ import (
// inConfig (if src is "-"), or from a URI specified in src. Progress output is
// written to outStream. Repository and tag names can optionally be given in
// the repo and tag arguments, respectively.
func (i *ImageService) ImportImage(src string, repository string, platform *specs.Platform, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error {
func (i *ImageService) ImportImage(ctx context.Context, src string, repository string, platform *specs.Platform, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error {
var (
rc io.ReadCloser
resp *http.Response
@ -62,7 +63,7 @@ func (i *ImageService) ImportImage(src string, repository string, platform *spec
if !system.IsOSSupported(platform.OS) {
return errdefs.InvalidParameter(system.ErrNotSupportedOperatingSystem)
}
config, err := dockerfile.BuildFromConfig(&container.Config{}, changes, platform.OS)
config, err := dockerfile.BuildFromConfig(ctx, &container.Config{}, changes, platform.OS)
if err != nil {
return err
}

View File

@ -42,7 +42,7 @@ type iterationAction int
// containerReducer represents a reducer for a container.
// Returns the object to serialize by the api.
type containerReducer func(*container.Snapshot, *listContext) (*types.Container, error)
type containerReducer func(context.Context, *container.Snapshot, *listContext) (*types.Container, error)
const (
// includeContainer is the action to include a container in the reducer.
@ -106,8 +106,8 @@ func (r byCreatedDescending) Less(i, j int) bool {
}
// Containers returns the list of containers to show given the user's filtering.
func (daemon *Daemon) Containers(config *types.ContainerListOptions) ([]*types.Container, error) {
return daemon.reduceContainers(config, daemon.refreshImage)
func (daemon *Daemon) Containers(ctx context.Context, config *types.ContainerListOptions) ([]*types.Container, error) {
return daemon.reduceContainers(ctx, config, daemon.refreshImage)
}
func (daemon *Daemon) filterByNameIDMatches(view *container.View, filter *listContext) ([]container.Snapshot, error) {
@ -177,7 +177,7 @@ func (daemon *Daemon) filterByNameIDMatches(view *container.View, filter *listCo
}
// reduceContainers parses the user's filtering options and generates the list of containers to return based on a reducer.
func (daemon *Daemon) reduceContainers(config *types.ContainerListOptions, reducer containerReducer) ([]*types.Container, error) {
func (daemon *Daemon) reduceContainers(ctx context.Context, config *types.ContainerListOptions, reducer containerReducer) ([]*types.Container, error) {
if err := config.Filters.Validate(acceptedPsFilterTags); err != nil {
return nil, err
}
@ -187,7 +187,7 @@ func (daemon *Daemon) reduceContainers(config *types.ContainerListOptions, reduc
containers = []*types.Container{}
)
filter, err := daemon.foldFilter(view, config)
filter, err := daemon.foldFilter(ctx, view, config)
if err != nil {
return nil, err
}
@ -201,7 +201,7 @@ func (daemon *Daemon) reduceContainers(config *types.ContainerListOptions, reduc
}
for i := range containerList {
t, err := daemon.reducePsContainer(&containerList[i], filter, reducer)
t, err := daemon.reducePsContainer(ctx, &containerList[i], filter, reducer)
if err != nil {
if err != errStopIteration {
return nil, err
@ -218,7 +218,7 @@ func (daemon *Daemon) reduceContainers(config *types.ContainerListOptions, reduc
}
// reducePsContainer is the basic representation for a container as expected by the ps command.
func (daemon *Daemon) reducePsContainer(container *container.Snapshot, filter *listContext, reducer containerReducer) (*types.Container, error) {
func (daemon *Daemon) reducePsContainer(ctx context.Context, container *container.Snapshot, filter *listContext, reducer containerReducer) (*types.Container, error) {
// filter containers to return
switch includeContainerInList(container, filter) {
case excludeContainer:
@ -228,7 +228,7 @@ func (daemon *Daemon) reducePsContainer(container *container.Snapshot, filter *l
}
// transform internal container struct into api structs
newC, err := reducer(container, filter)
newC, err := reducer(ctx, container, filter)
if err != nil {
return nil, err
}
@ -243,8 +243,7 @@ func (daemon *Daemon) reducePsContainer(container *container.Snapshot, filter *l
}
// foldFilter generates the container filter based on the user's filtering options.
func (daemon *Daemon) foldFilter(view *container.View, config *types.ContainerListOptions) (*listContext, error) {
ctx := context.TODO()
func (daemon *Daemon) foldFilter(ctx context.Context, view *container.View, config *types.ContainerListOptions) (*listContext, error) {
psFilters := config.Filters
var filtExited []int
@ -580,8 +579,7 @@ func includeContainerInList(container *container.Snapshot, filter *listContext)
}
// refreshImage checks if the Image ref still points to the correct ID, and updates the ref to the actual ID when it doesn't
func (daemon *Daemon) refreshImage(s *container.Snapshot, filter *listContext) (*types.Container, error) {
ctx := context.TODO()
func (daemon *Daemon) refreshImage(ctx context.Context, s *container.Snapshot, filter *listContext) (*types.Container, error) {
c := s.Container
tmpImage := s.Image // keep the original ref if still valid (hasn't changed)
if tmpImage != s.ImageID {

View File

@ -1,6 +1,7 @@
package daemon
import (
"context"
"os"
"path/filepath"
"testing"
@ -88,7 +89,7 @@ func TestListInvalidFilter(t *testing.T) {
f := filters.NewArgs(filters.Arg("invalid", "foo"))
_, err = d.Containers(&types.ContainerListOptions{
_, err = d.Containers(context.Background(), &types.ContainerListOptions{
Filters: f,
})
assert.Assert(t, is.Error(err, "invalid filter 'invalid'"))
@ -109,7 +110,7 @@ func TestNameFilter(t *testing.T) {
// moby/moby #37453 - ^ regex not working due to prefix slash
// not being stripped
containerList, err := d.Containers(&types.ContainerListOptions{
containerList, err := d.Containers(context.Background(), &types.ContainerListOptions{
Filters: filters.NewArgs(filters.Arg("name", "^a")),
})
assert.NilError(t, err)
@ -118,7 +119,7 @@ func TestNameFilter(t *testing.T) {
assert.Assert(t, containerListContainsName(containerList, two.Name))
// Same as above but with slash prefix should produce the same result
containerListWithPrefix, err := d.Containers(&types.ContainerListOptions{
containerListWithPrefix, err := d.Containers(context.Background(), &types.ContainerListOptions{
Filters: filters.NewArgs(filters.Arg("name", "^/a")),
})
assert.NilError(t, err)
@ -127,7 +128,7 @@ func TestNameFilter(t *testing.T) {
assert.Assert(t, containerListContainsName(containerListWithPrefix, two.Name))
// Same as above but make sure it works for exact names
containerList, err = d.Containers(&types.ContainerListOptions{
containerList, err = d.Containers(context.Background(), &types.ContainerListOptions{
Filters: filters.NewArgs(filters.Arg("name", "b1")),
})
assert.NilError(t, err)
@ -135,7 +136,7 @@ func TestNameFilter(t *testing.T) {
assert.Assert(t, containerListContainsName(containerList, three.Name))
// Same as above but with slash prefix should produce the same result
containerListWithPrefix, err = d.Containers(&types.ContainerListOptions{
containerListWithPrefix, err = d.Containers(context.Background(), &types.ContainerListOptions{
Filters: filters.NewArgs(filters.Arg("name", "/b1")),
})
assert.NilError(t, err)

View File

@ -111,7 +111,7 @@ func (daemon *Daemon) handleContainerExit(c *container.Container, e *libcontaine
// But containerStart will use daemon.netController segment.
// So to avoid panic at startup process, here must wait util daemon restore done.
daemon.waitForStartupDone()
if err = daemon.containerStart(c, "", "", false); err != nil {
if err = daemon.containerStart(context.Background(), c, "", "", false); err != nil {
logrus.Debugf("failed to restart container: %+v", err)
}
}

View File

@ -1007,7 +1007,7 @@ func WithUser(c *container.Container) coci.SpecOpts {
}
}
func (daemon *Daemon) createSpec(c *container.Container) (retSpec *specs.Spec, err error) {
func (daemon *Daemon) createSpec(ctx context.Context, c *container.Container) (retSpec *specs.Spec, err error) {
var (
opts []coci.SpecOpts
s = oci.DefaultSpec()
@ -1052,7 +1052,7 @@ func (daemon *Daemon) createSpec(c *container.Container) (retSpec *specs.Spec, e
snapshotKey = c.ID
}
return &s, coci.ApplyOpts(context.Background(), nil, &containers.Container{
return &s, coci.ApplyOpts(ctx, nil, &containers.Container{
ID: c.ID,
Snapshotter: snapshotter,
SnapshotKey: snapshotKey,

View File

@ -1,6 +1,7 @@
package daemon // import "github.com/docker/docker/daemon"
import (
"context"
"os"
"path/filepath"
"testing"
@ -73,7 +74,7 @@ func TestTmpfsDevShmNoDupMount(t *testing.T) {
d := setupFakeDaemon(t, c)
defer cleanupFakeContainer(c)
_, err := d.createSpec(c)
_, err := d.createSpec(context.TODO(), c)
assert.Check(t, err)
}
@ -92,7 +93,7 @@ func TestIpcPrivateVsReadonly(t *testing.T) {
d := setupFakeDaemon(t, c)
defer cleanupFakeContainer(c)
s, err := d.createSpec(c)
s, err := d.createSpec(context.TODO(), c)
assert.Check(t, err)
// Find the /dev/shm mount in ms, check it does not have ro
@ -122,7 +123,7 @@ func TestSysctlOverride(t *testing.T) {
defer cleanupFakeContainer(c)
// Ensure that the implicit sysctl is set correctly.
s, err := d.createSpec(c)
s, err := d.createSpec(context.TODO(), c)
assert.NilError(t, err)
assert.Equal(t, s.Hostname, "foobar")
assert.Equal(t, s.Linux.Sysctl["kernel.domainname"], c.Config.Domainname)
@ -138,7 +139,7 @@ func TestSysctlOverride(t *testing.T) {
assert.Assert(t, c.HostConfig.Sysctls["kernel.domainname"] != c.Config.Domainname)
c.HostConfig.Sysctls["net.ipv4.ip_unprivileged_port_start"] = "1024"
s, err = d.createSpec(c)
s, err = d.createSpec(context.TODO(), c)
assert.NilError(t, err)
assert.Equal(t, s.Hostname, "foobar")
assert.Equal(t, s.Linux.Sysctl["kernel.domainname"], c.HostConfig.Sysctls["kernel.domainname"])
@ -146,7 +147,7 @@ func TestSysctlOverride(t *testing.T) {
// Ensure the ping_group_range is not set on a daemon with user-namespaces enabled
d.configStore.RemappedRoot = "dummy:dummy"
s, err = d.createSpec(c)
s, err = d.createSpec(context.TODO(), c)
assert.NilError(t, err)
_, ok := s.Linux.Sysctl["net.ipv4.ping_group_range"]
assert.Assert(t, !ok)
@ -154,7 +155,7 @@ func TestSysctlOverride(t *testing.T) {
// Ensure the ping_group_range is set on a container in "host" userns mode
// on a daemon with user-namespaces enabled
c.HostConfig.UsernsMode = "host"
s, err = d.createSpec(c)
s, err = d.createSpec(context.TODO(), c)
assert.NilError(t, err)
assert.Equal(t, s.Linux.Sysctl["net.ipv4.ping_group_range"], "0 2147483647")
}
@ -174,7 +175,7 @@ func TestSysctlOverrideHost(t *testing.T) {
defer cleanupFakeContainer(c)
// Ensure that the implicit sysctl is not set
s, err := d.createSpec(c)
s, err := d.createSpec(context.TODO(), c)
assert.NilError(t, err)
assert.Equal(t, s.Linux.Sysctl["net.ipv4.ip_unprivileged_port_start"], "")
assert.Equal(t, s.Linux.Sysctl["net.ipv4.ping_group_range"], "")
@ -182,7 +183,7 @@ func TestSysctlOverrideHost(t *testing.T) {
// Set an explicit sysctl.
c.HostConfig.Sysctls["net.ipv4.ip_unprivileged_port_start"] = "1024"
s, err = d.createSpec(c)
s, err = d.createSpec(context.TODO(), c)
assert.NilError(t, err)
assert.Equal(t, s.Linux.Sysctl["net.ipv4.ip_unprivileged_port_start"], c.HostConfig.Sysctls["net.ipv4.ip_unprivileged_port_start"])
}

View File

@ -26,8 +26,7 @@ const (
credentialSpecFileLocation = "CredentialSpecs"
)
func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
ctx := context.TODO()
func (daemon *Daemon) createSpec(ctx context.Context, c *container.Container) (*specs.Spec, error) {
img, err := daemon.imageService.GetImage(ctx, string(c.ImageID), imagetypes.GetImageOpts{})
if err != nil {
return nil, err

View File

@ -61,7 +61,7 @@ func (daemon *Daemon) containerRestart(ctx context.Context, container *container
}
}
if err := daemon.containerStart(container, "", "", true); err != nil {
if err := daemon.containerStart(ctx, container, "", "", true); err != nil {
return err
}

View File

@ -15,7 +15,7 @@ import (
)
// ContainerStart starts a container.
func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.HostConfig, checkpoint string, checkpointDir string) error {
func (daemon *Daemon) ContainerStart(ctx context.Context, name string, hostConfig *containertypes.HostConfig, checkpoint string, checkpointDir string) error {
if checkpoint != "" && !daemon.HasExperimental() {
return errdefs.InvalidParameter(errors.New("checkpoint is only supported in experimental mode"))
}
@ -92,14 +92,14 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.Hos
return errdefs.InvalidParameter(err)
}
}
return daemon.containerStart(ctr, checkpoint, checkpointDir, true)
return daemon.containerStart(ctx, ctr, checkpoint, checkpointDir, true)
}
// containerStart prepares the container to run by setting up everything the
// container needs, such as storage and networking, as well as links
// between containers. The container is left waiting for a signal to
// begin running.
func (daemon *Daemon) containerStart(container *container.Container, checkpoint string, checkpointDir string, resetRestartManager bool) (err error) {
func (daemon *Daemon) containerStart(ctx context.Context, container *container.Container, checkpoint string, checkpointDir string, resetRestartManager bool) (err error) {
start := time.Now()
container.Lock()
defer container.Unlock()
@ -151,7 +151,7 @@ func (daemon *Daemon) containerStart(container *container.Container, checkpoint
return err
}
spec, err := daemon.createSpec(container)
spec, err := daemon.createSpec(ctx, container)
if err != nil {
return errdefs.System(err)
}
@ -177,8 +177,6 @@ func (daemon *Daemon) containerStart(container *container.Container, checkpoint
return err
}
ctx := context.TODO()
ctr, err := libcontainerd.ReplaceContainer(ctx, daemon.containerd, container.ID, spec, shim, createOptions)
if err != nil {
return translateContainerdStartErr(container.Path, container.SetExitCode, err)