diff --git a/api/server/router/container/backend.go b/api/server/router/container/backend.go index 4db989a10201b..f0624eef836b3 100644 --- a/api/server/router/container/backend.go +++ b/api/server/router/container/backend.go @@ -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. diff --git a/api/server/router/container/container_routes.go b/api/server/router/container/container_routes.go index 6670b9ec68137..5df051fc95f4a 100644 --- a/api/server/router/container/container_routes.go +++ b/api/server/router/container/container_routes.go @@ -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, diff --git a/api/server/router/image/backend.go b/api/server/router/image/backend.go index ece336bef4e2c..6e96437c73499 100644 --- a/api/server/router/image/backend.go +++ b/api/server/router/image/backend.go @@ -24,14 +24,14 @@ type imageBackend interface { ImageDelete(imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error) ImageHistory(imageName string) ([]*image.HistoryResponseItem, error) Images(ctx context.Context, opts types.ImageListOptions) ([]*types.ImageSummary, error) - GetImage(refOrID string, platform *specs.Platform) (retImg *dockerimage.Image, retErr error) + GetImage(ctx context.Context, refOrID string, platform *specs.Platform) (*dockerimage.Image, error) TagImage(imageName, repository, tag string) (string, error) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (*types.ImagesPruneReport, error) } type importExportBackend interface { LoadImage(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(names []string, outStream io.Writer) error } diff --git a/api/server/router/image/image_routes.go b/api/server/router/image/image_routes.go index b186e61ade5a0..554cb28db3d7d 100644 --- a/api/server/router/image/image_routes.go +++ b/api/server/router/image/image_routes.go @@ -76,7 +76,7 @@ func (s *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrite progressErr = s.backend.PullImage(ctx, image, tag, platform, metaHeaders, authConfig, output) } else { // import src := r.Form.Get("fromSrc") - progressErr = s.backend.ImportImage(src, repo, platform, tag, message, r.Body, output, r.Form["changes"]) + progressErr = s.backend.ImportImage(ctx, src, repo, platform, tag, message, r.Body, output, r.Form["changes"]) } if progressErr != nil { if !output.Flushed() { @@ -204,7 +204,7 @@ func (s *imageRouter) deleteImages(ctx context.Context, w http.ResponseWriter, r } func (s *imageRouter) getImagesByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { - image, err := s.backend.GetImage(vars["name"], nil) + image, err := s.backend.GetImage(ctx, vars["name"], nil) if err != nil { return err } diff --git a/api/server/router/swarm/backend.go b/api/server/router/swarm/backend.go index d0c7e60fb3270..fa63e363bdb14 100644 --- a/api/server/router/swarm/backend.go +++ b/api/server/router/swarm/backend.go @@ -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) diff --git a/api/server/router/swarm/cluster_routes.go b/api/server/router/swarm/cluster_routes.go index 05c10082a1c8b..15c20094513ca 100644 --- a/api/server/router/swarm/cluster_routes.go +++ b/api/server/router/swarm/cluster_routes.go @@ -55,7 +55,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 { diff --git a/builder/builder.go b/builder/builder.go index f01563812f937..2fc371da90246 100644 --- a/builder/builder.go +++ b/builder/builder.go @@ -61,13 +61,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) } @@ -81,7 +81,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 } // ImageCache abstracts an image cache. diff --git a/builder/dockerfile/builder.go b/builder/dockerfile/builder.go index 820c2d102e7b6..5bc30d18af1ec 100644 --- a/builder/dockerfile/builder.go +++ b/builder/dockerfile/builder.go @@ -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 @@ -147,7 +147,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: newImageProber(clientCtx, options.Backend, config.CacheFrom, config.NoCache), containerManager: newContainerManager(options.Backend), } @@ -181,7 +181,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 +205,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 +244,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 +272,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 +290,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() @@ -318,7 +318,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 } @@ -361,7 +361,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) } diff --git a/builder/dockerfile/containerbackend.go b/builder/dockerfile/containerbackend.go index 99a6b14f6d844..ebb261a1c460e 100644 --- a/builder/dockerfile/containerbackend.go +++ b/builder/dockerfile/containerbackend.go @@ -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 diff --git a/builder/dockerfile/dispatchers.go b/builder/dockerfile/dispatchers.go index 65a3a8540cd54..9b13aa8d30335 100644 --- a/builder/dockerfile/dispatchers.go +++ b/builder/dockerfile/dispatchers.go @@ -9,6 +9,7 @@ package dockerfile // import "github.com/docker/docker/builder/dockerfile" import ( "bytes" + "context" "fmt" "runtime" "sort" @@ -36,7 +37,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 { @@ -58,23 +59,23 @@ 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 // // 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) } @@ -83,7 +84,7 @@ 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 @@ -91,7 +92,7 @@ func dispatchLabel(d dispatchRequest, c *instructions.LabelCommand) error { // 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") } @@ -106,14 +107,14 @@ 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") } @@ -135,7 +136,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) { @@ -158,7 +159,7 @@ 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 { +func initializeStage(ctx context.Context, d dispatchRequest, cmd *instructions.Stage) error { d.builder.imageProber.Reset() var platform *specs.Platform @@ -186,12 +187,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") @@ -214,7 +215,7 @@ func dispatchTriggeredOnBuild(d dispatchRequest, triggers []string) error { } return err } - err = dispatch(d, cmd) + err = dispatch(ctx, d, cmd) if err != nil { return err } @@ -282,16 +283,16 @@ 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) @@ -312,7 +313,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 } @@ -334,7 +335,7 @@ func dispatchWorkdir(d dispatchRequest, c *instructions.WorkdirCommand) error { // 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 } @@ -368,7 +369,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 } @@ -429,7 +430,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()) @@ -445,7 +446,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 { @@ -460,7 +461,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 @@ -469,7 +470,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 @@ -480,7 +481,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()) @@ -502,7 +503,7 @@ 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 @@ -510,7 +511,7 @@ func dispatchEntrypoint(d dispatchRequest, c *instructions.EntrypointCommand) er // 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 @@ -536,7 +537,7 @@ 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 @@ -544,16 +545,16 @@ func dispatchExpose(d dispatchRequest, c *instructions.ExposeCommand, envs []str // 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{}{} } @@ -563,20 +564,20 @@ 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] @@ -584,7 +585,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 { @@ -599,13 +600,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)) } diff --git a/builder/dockerfile/dispatchers_test.go b/builder/dockerfile/dispatchers_test.go index 2c543f60e59d4..aae002392aa2f 100644 --- a/builder/dockerfile/dispatchers_test.go +++ b/builder/dockerfile/dispatchers_test.go @@ -37,7 +37,7 @@ func newBuilderWithMockBackend() *Builder { Options: opts, Backend: mockBackend, }), - imageProber: newImageProber(mockBackend, nil, false), + imageProber: newImageProber(context.TODO(), mockBackend, nil, false), containerManager: newContainerManager(mockBackend), } return b @@ -52,7 +52,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{ @@ -71,7 +71,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", @@ -85,7 +85,7 @@ func TestMaintainer(t *testing.T) { b := newBuilderWithMockBackend() 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)) } @@ -101,7 +101,7 @@ func TestLabel(t *testing.T) { 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)) @@ -114,7 +114,7 @@ func TestFromScratch(t *testing.T) { 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")) @@ -151,7 +151,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)) @@ -172,7 +172,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") } @@ -192,7 +192,7 @@ 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)) } @@ -204,12 +204,12 @@ func TestFromMultiStageWithNamedStage(t *testing.T) { 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()) } @@ -220,7 +220,7 @@ func TestOnbuild(t *testing.T) { 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])) } @@ -237,7 +237,7 @@ 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)) } @@ -254,7 +254,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 @@ -276,7 +276,7 @@ func TestHealthcheckNone(t *testing.T) { 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) @@ -293,7 +293,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) @@ -312,7 +312,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) @@ -333,7 +333,7 @@ func TestExpose(t *testing.T) { 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) @@ -351,7 +351,7 @@ func TestUser(t *testing.T) { 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)) } @@ -365,7 +365,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)) @@ -385,7 +385,7 @@ 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)) } @@ -397,7 +397,7 @@ func TestArg(t *testing.T) { 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} @@ -411,7 +411,7 @@ func TestShell(t *testing.T) { 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}) @@ -463,7 +463,7 @@ func TestRunWithBuildArgs(t *testing.T) { mockBackend.makeImageCacheFunc = func(_ []string) builder.ImageCache { return imageCache } - b.imageProber = newImageProber(mockBackend, nil, false) + b.imageProber = newImageProber(nil, mockBackend, nil, false) mockBackend.getImageFunc = func(_ string) (builder.Image, builder.ROLayer, error) { return &mockImage{ id: "abcdef", @@ -485,7 +485,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")) @@ -505,7 +505,7 @@ 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)) @@ -529,7 +529,7 @@ func TestRunIgnoresHealthcheck(t *testing.T) { mockBackend.makeImageCacheFunc = func(_ []string) builder.ImageCache { return imageCache } - b.imageProber = newImageProber(mockBackend, nil, false) + b.imageProber = newImageProber(nil, mockBackend, nil, false) mockBackend.getImageFunc = func(_ string) (builder.Image, builder.ROLayer, error) { return &mockImage{ id: "abcdef", @@ -543,7 +543,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"} @@ -560,7 +560,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) { @@ -575,7 +575,7 @@ 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)) } @@ -593,7 +593,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") }) @@ -605,7 +605,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") }) @@ -619,7 +619,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)) } }) diff --git a/builder/dockerfile/evaluator.go b/builder/dockerfile/evaluator.go index 1201eb320b4ea..f03a0490f9914 100644 --- a/builder/dockerfile/evaluator.go +++ b/builder/dockerfile/evaluator.go @@ -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)) } diff --git a/builder/dockerfile/evaluator_test.go b/builder/dockerfile/evaluator_test.go index 27e01954d0bf2..e151559ad9bb7 100644 --- a/builder/dockerfile/evaluator_test.go +++ b/builder/dockerfile/evaluator_test.go @@ -1,6 +1,7 @@ package dockerfile // import "github.com/docker/docker/builder/dockerfile" import ( + ctx "context" "os" "runtime" "testing" @@ -129,7 +130,7 @@ func TestDispatch(t *testing.T) { b := newBuilderWithMockBackend() sb := newDispatchRequest(b, '`', context, NewBuildArgs(make(map[string]*string)), newStagesBuildResults()) - err = dispatch(sb, tc.cmd) + err = dispatch(ctx.TODO(), sb, tc.cmd) assert.Check(t, is.ErrorContains(err, tc.expectedError)) }) } diff --git a/builder/dockerfile/imageprobe.go b/builder/dockerfile/imageprobe.go index 6960bf8897360..028b08c3eaeb6 100644 --- a/builder/dockerfile/imageprobe.go +++ b/builder/dockerfile/imageprobe.go @@ -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" @@ -19,13 +21,13 @@ type imageProber struct { 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 { if noCache { return &nopProber{} } reset := func() builder.ImageCache { - return cacheBuilder.MakeImageCache(cacheFrom) + return cacheBuilder.MakeImageCache(ctx, cacheFrom) } return &imageProber{cache: reset(), reset: reset} } diff --git a/builder/dockerfile/internals.go b/builder/dockerfile/internals.go index 1bc445d383cd0..544b977f240f2 100644 --- a/builder/dockerfile/internals.go +++ b/builder/dockerfile/internals.go @@ -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" @@ -72,7 +73,7 @@ func (b *Builder) getArchiver(src, dst containerfs.Driver) Archiver { } } -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 } @@ -81,7 +82,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 } @@ -152,7 +153,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) @@ -192,7 +193,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.Path(), b.idMapping) + identity, err = parseChownFlag(ctx, b, state, inst.chownStr, destInfo.root.Path(), b.idMapping) if err != nil { if b.options.Platform != "windows" { return errors.Wrapf(err, "unable to convert uid/gid chown string to host mapping") @@ -376,18 +377,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 } diff --git a/builder/dockerfile/internals_linux.go b/builder/dockerfile/internals_linux.go index d4c714241fa1e..37e096590f479 100644 --- a/builder/dockerfile/internals_linux.go +++ b/builder/dockerfile/internals_linux.go @@ -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 { diff --git a/builder/dockerfile/internals_linux_test.go b/builder/dockerfile/internals_linux_test.go index 75af92ab5f91e..6f56d43afcb52 100644 --- a/builder/dockerfile/internals_linux_test.go +++ b/builder/dockerfile/internals_linux_test.go @@ -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") }) } diff --git a/builder/dockerfile/internals_windows.go b/builder/dockerfile/internals_windows.go index 335f87cdc7b0f..4bdb54f04dd37 100644 --- a/builder/dockerfile/internals_windows.go +++ b/builder/dockerfile/internals_windows.go @@ -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 } diff --git a/builder/dockerfile/mockbackend_test.go b/builder/dockerfile/mockbackend_test.go index 0310374a69208..da77054521c9e 100644 --- a/builder/dockerfile/mockbackend_test.go +++ b/builder/dockerfile/mockbackend_test.go @@ -28,7 +28,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) } @@ -50,7 +50,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 } @@ -74,7 +74,7 @@ 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 { if m.makeImageCacheFunc != nil { return m.makeImageCacheFunc(cacheFrom) } diff --git a/cmd/dockerd/daemon.go b/cmd/dockerd/daemon.go index 9e65d74c37666..30531938a3ec4 100644 --- a/cmd/dockerd/daemon.go +++ b/cmd/dockerd/daemon.go @@ -256,7 +256,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() @@ -364,11 +364,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 { diff --git a/daemon/cluster/executor/backend.go b/daemon/cluster/executor/backend.go index cbd9fe33e8670..87b9a9a5a1b27 100644 --- a/daemon/cluster/executor/backend.go +++ b/daemon/cluster/executor/backend.go @@ -35,8 +35,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 @@ -51,7 +51,7 @@ type Backend interface { SetContainerSecretReferences(name string, refs []*swarmtypes.SecretReference) error SetContainerConfigReferences(name string, refs []*swarmtypes.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() @@ -75,5 +75,5 @@ type VolumeBackend interface { type ImageBackend interface { PullImage(ctx context.Context, image, tag string, platform *specs.Platform, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error GetRepository(context.Context, reference.Named, *types.AuthConfig) (distribution.Repository, error) - GetImage(refOrID string, platform *specs.Platform) (retImg *image.Image, retErr error) + GetImage(ctx context.Context, refOrID string, platform *specs.Platform) (retImg *image.Image, retErr error) } diff --git a/daemon/cluster/executor/container/adapter.go b/daemon/cluster/executor/container/adapter.go index 925aa058abb64..1bfd217fcb9d8 100644 --- a/daemon/cluster/executor/container/adapter.go +++ b/daemon/cluster/executor/container/adapter.go @@ -74,7 +74,7 @@ func (c *containerAdapter) pullImage(ctx context.Context) error { named, err := reference.ParseNormalizedNamed(spec.Image) if err == nil { if _, ok := named.(reference.Canonical); ok { - _, err := c.imageBackend.GetImage(spec.Image, nil) + _, err := c.imageBackend.GetImage(ctx, spec.Image, nil) if err == nil { return nil } @@ -285,7 +285,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()), @@ -352,7 +352,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) { diff --git a/daemon/cluster/swarm.go b/daemon/cluster/swarm.go index 99d6ce17a360b..23478c8cd7dbf 100644 --- a/daemon/cluster/swarm.go +++ b/daemon/cluster/swarm.go @@ -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 { diff --git a/daemon/commit.go b/daemon/commit.go index 302e9a95d6fe5..7b7d4e4446391 100644 --- a/daemon/commit.go +++ b/daemon/commit.go @@ -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 } diff --git a/daemon/containerd/service.go b/daemon/containerd/service.go index e9dda770591f4..ff921b7d2b0d0 100644 --- a/daemon/containerd/service.go +++ b/daemon/containerd/service.go @@ -2,9 +2,15 @@ package containerd import ( "context" + "encoding/json" + "fmt" "io" + "regexp" "github.com/containerd/containerd" + "github.com/containerd/containerd/content" + cerrdefs "github.com/containerd/containerd/errdefs" + containerdimages "github.com/containerd/containerd/images" "github.com/containerd/containerd/platforms" "github.com/containerd/containerd/remotes" "github.com/containerd/containerd/remotes/docker" @@ -13,6 +19,7 @@ import ( "github.com/docker/distribution/reference" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/backend" + containertypes "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" imagetype "github.com/docker/docker/api/types/image" registrytypes "github.com/docker/docker/api/types/registry" @@ -25,8 +32,12 @@ import ( "github.com/opencontainers/go-digest" "github.com/opencontainers/image-spec/identity" ocispec "github.com/opencontainers/image-spec/specs-go/v1" + v1 "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" ) +var shortID = regexp.MustCompile(`^([a-f0-9]{4,64})$`) + type containerdStore struct { client *containerd.Client } @@ -228,7 +239,7 @@ func (cs *containerdStore) Cleanup() error { } func (cs *containerdStore) GraphDriverName() string { - return "" + return "containerd-snapshotter" } func (cs *containerdStore) CommitBuildStep(c backend.CommitConfig) (image.ID, error) { @@ -243,7 +254,7 @@ func (cs *containerdStore) GetImageAndReleasableLayer(ctx context.Context, refOr panic("not implemented") } -func (cs *containerdStore) MakeImageCache(sourceRefs []string) builder.ImageCache { +func (cs *containerdStore) MakeImageCache(ctx context.Context, cacheFrom []string) builder.ImageCache { panic("not implemented") } @@ -271,7 +282,7 @@ func (cs *containerdStore) ImagesPrune(ctx context.Context, pruneFilters filters panic("not implemented") } -func (cs *containerdStore) ImportImage(src string, repository string, platform *ocispec.Platform, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error { +func (cs *containerdStore) ImportImage(ctx context.Context, src string, repository string, platform *v1.Platform, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error { panic("not implemented") } @@ -315,8 +326,47 @@ func (cs *containerdStore) CommitImage(c backend.CommitConfig) (image.ID, error) panic("not implemented") } -func (cs *containerdStore) GetImage(refOrID string, platform *ocispec.Platform) (retImg *image.Image, retErr error) { - panic("not implemented") +func (cs *containerdStore) GetImage(ctx context.Context, refOrID string, platform *v1.Platform) (*image.Image, error) { + desc, err := cs.ResolveImage(ctx, refOrID) + if err != nil { + return nil, err + } + + ctrdimg, err := cs.resolveImageName2(ctx, refOrID) + if err != nil { + return nil, err + } + ii := containerd.NewImage(cs.client, ctrdimg) + provider := cs.client.ContentStore() + conf, err := ctrdimg.Config(ctx, provider, ii.Platform()) + if err != nil { + return nil, err + } + + var ociimage v1.Image + imageConfigBytes, err := content.ReadBlob(ctx, ii.ContentStore(), conf) + if err != nil { + return nil, err + } + + if err := json.Unmarshal(imageConfigBytes, &ociimage); err != nil { + return nil, err + } + + return &image.Image{ + V1Image: image.V1Image{ + ID: string(desc.Digest), + OS: ociimage.OS, + Architecture: ociimage.Architecture, + Config: &containertypes.Config{ + Entrypoint: ociimage.Config.Entrypoint, + Env: ociimage.Config.Env, + Cmd: ociimage.Config.Cmd, + User: ociimage.Config.User, + WorkingDir: ociimage.Config.WorkingDir, + }, + }, + }, nil } func (cs *containerdStore) CreateLayer(container *container.Container, initFunc layer.MountInit) (layer.RWLayer, error) { @@ -351,3 +401,159 @@ func (cs *containerdStore) UpdateConfig(maxDownloads, maxUploads int) { func (cs *containerdStore) Children(id image.ID) []image.ID { panic("not implemented") } + +// ResolveImage searches for an image based on the given +// reference or identifier. Returns the descriptor of +// the image, could be manifest list, manifest, or config. +func (cs *containerdStore) ResolveImage(ctx context.Context, refOrID string) (d ocispec.Descriptor, err error) { + d, _, err = cs.resolveImageName(ctx, refOrID) + return +} + +func (cs *containerdStore) resolveImageName2(ctx context.Context, refOrID string) (img containerdimages.Image, err error) { + parsed, err := reference.ParseAnyReference(refOrID) + if err != nil { + return img, errdefs.InvalidParameter(err) + } + + is := cs.client.ImageService() + + namedRef, ok := parsed.(reference.Named) + if !ok { + digested, ok := parsed.(reference.Digested) + if !ok { + return img, errdefs.InvalidParameter(errors.New("bad reference")) + } + + imgs, err := is.List(ctx, fmt.Sprintf("target.digest==%s", digested.Digest())) + if err != nil { + return img, errors.Wrap(err, "failed to lookup digest") + } + if len(imgs) == 0 { + return img, errdefs.NotFound(errors.New("image not found with digest")) + } + + return imgs[0], nil + } + + namedRef = reference.TagNameOnly(namedRef) + + // If the identifier could be a short ID, attempt to match + if shortID.MatchString(refOrID) { + ref := namedRef.String() + filters := []string{ + fmt.Sprintf("name==%q", ref), + fmt.Sprintf(`target.digest~=/sha256:%s[0-9a-fA-F]{%d}/`, refOrID, 64-len(refOrID)), + } + imgs, err := is.List(ctx, filters...) + if err != nil { + return img, err + } + + if len(imgs) == 0 { + return img, errdefs.NotFound(errors.New("list returned no images")) + } + if len(imgs) > 1 { + digests := map[digest.Digest]struct{}{} + for _, img := range imgs { + if img.Name == ref { + return img, nil + } + digests[img.Target.Digest] = struct{}{} + } + + if len(digests) > 1 { + return img, errdefs.NotFound(errors.New("ambiguous reference")) + } + } + + if imgs[0].Name != ref { + namedRef = nil + } + return imgs[0], nil + } + img, err = is.Get(ctx, namedRef.String()) + if err != nil { + // TODO(containerd): error translation can use common function + if !cerrdefs.IsNotFound(err) { + return img, err + } + return img, errdefs.NotFound(errors.New("id not found")) + } + + return img, nil +} + +func (cs *containerdStore) resolveImageName(ctx context.Context, refOrID string) (ocispec.Descriptor, reference.Named, error) { + parsed, err := reference.ParseAnyReference(refOrID) + if err != nil { + return ocispec.Descriptor{}, nil, errdefs.InvalidParameter(err) + } + + is := cs.client.ImageService() + + namedRef, ok := parsed.(reference.Named) + if !ok { + digested, ok := parsed.(reference.Digested) + if !ok { + return ocispec.Descriptor{}, nil, errdefs.InvalidParameter(errors.New("bad reference")) + } + + imgs, err := is.List(ctx, fmt.Sprintf("target.digest==%s", digested.Digest())) + if err != nil { + return ocispec.Descriptor{}, nil, errors.Wrap(err, "failed to lookup digest") + } + if len(imgs) == 0 { + return ocispec.Descriptor{}, nil, errdefs.NotFound(errors.New("image not found with digest")) + } + + return imgs[0].Target, nil, nil + } + + namedRef = reference.TagNameOnly(namedRef) + + // If the identifier could be a short ID, attempt to match + if shortID.MatchString(refOrID) { + ref := namedRef.String() + filters := []string{ + fmt.Sprintf("name==%q", ref), + fmt.Sprintf(`target.digest~=/sha256:%s[0-9a-fA-F]{%d}/`, refOrID, 64-len(refOrID)), + } + imgs, err := is.List(ctx, filters...) + if err != nil { + return ocispec.Descriptor{}, nil, err + } + + if len(imgs) == 0 { + return ocispec.Descriptor{}, nil, errdefs.NotFound(errors.New("list returned no images")) + } + if len(imgs) > 1 { + digests := map[digest.Digest]struct{}{} + for _, img := range imgs { + if img.Name == ref { + return img.Target, namedRef, nil + } + digests[img.Target.Digest] = struct{}{} + } + + if len(digests) > 1 { + return ocispec.Descriptor{}, nil, errdefs.NotFound(errors.New("ambiguous reference")) + } + } + + if imgs[0].Name != ref { + namedRef = nil + } + return imgs[0].Target, namedRef, nil + } + img, err := is.Get(ctx, namedRef.String()) + if err != nil { + // TODO(containerd): error translation can use common function + if !cerrdefs.IsNotFound(err) { + return ocispec.Descriptor{}, nil, err + } + return ocispec.Descriptor{}, nil, errdefs.NotFound(errors.New("id not found")) + } + + return img.Target, namedRef, nil +} diff --git a/daemon/create.go b/daemon/create.go index 4d44d01ca6e77..d2189c9607f03 100644 --- a/daemon/create.go +++ b/daemon/create.go @@ -1,6 +1,7 @@ package daemon // import "github.com/docker/docker/daemon" import ( + "context" "fmt" "net" "runtime" @@ -32,16 +33,16 @@ 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, ignoreImagesArgsEscaped: false}) } // 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, managed: false, ignoreImagesArgsEscaped: false}) @@ -49,14 +50,14 @@ func (daemon *Daemon) ContainerCreate(params types.ContainerCreateConfig) (conta // 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, managed: false, ignoreImagesArgsEscaped: true}) } -func (daemon *Daemon) containerCreate(opts createOpts) (containertypes.CreateResponse, error) { +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")) @@ -68,7 +69,7 @@ func (daemon *Daemon) containerCreate(opts createOpts) (containertypes.CreateRes } if opts.params.Platform == nil && opts.params.Config.Image != "" { - if img, _ := daemon.imageService.GetImage(opts.params.Config.Image, opts.params.Platform); img != nil { + if img, _ := daemon.imageService.GetImage(ctx, opts.params.Config.Image, opts.params.Platform); img != nil { p := maximumSpec() imgPlat := v1.Platform{ OS: img.OS, @@ -95,7 +96,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 } @@ -109,7 +110,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) { +func (daemon *Daemon) create(ctx context.Context, opts createOpts) (retC *container.Container, retErr error) { var ( ctr *container.Container img *image.Image @@ -119,7 +120,7 @@ func (daemon *Daemon) create(opts createOpts) (retC *container.Container, retErr ) if opts.params.Config.Image != "" { - img, err = daemon.imageService.GetImage(opts.params.Config.Image, opts.params.Platform) + img, err = daemon.imageService.GetImage(ctx, opts.params.Config.Image, opts.params.Platform) if err != nil { return nil, err } diff --git a/daemon/daemon.go b/daemon/daemon.go index 64128399a3718..d989ba5616c70 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -209,7 +209,7 @@ func (daemon *Daemon) RegistryHosts() docker.RegistryHosts { return resolver.NewRegistryConfig(m) } -func (daemon *Daemon) restore() error { +func (daemon *Daemon) restore(ctx context.Context) error { var mapLock sync.Mutex containers := make(map[string]*container.Container) @@ -530,7 +530,7 @@ func (daemon *Daemon) restore() error { } } - if err := daemon.containerStart(c, "", "", true); err != nil { + if err := daemon.containerStart(ctx, c, "", "", true); err != nil { log.WithError(err).Error("failed to start container") } close(chNotify) @@ -621,7 +621,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") } @@ -785,7 +785,7 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S // initialization defer func() { if err != nil { - if err := d.Shutdown(); err != nil { + if err := d.Shutdown(ctx); err != nil { logrus.Error(err) } } @@ -1107,7 +1107,7 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S return nil, err } - if err := d.restore(); err != nil { + if err := d.restore(ctx); err != nil { return nil, err } close(d.startupDone) @@ -1191,14 +1191,14 @@ 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 diff --git a/daemon/disk_usage.go b/daemon/disk_usage.go index 0af893b6055e9..c61234d6547e5 100644 --- a/daemon/disk_usage.go +++ b/daemon/disk_usage.go @@ -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(nil, &types.ContainerListOptions{ Size: true, All: true, }) diff --git a/daemon/image_service.go b/daemon/image_service.go index 7f43500b39e05..1afb733404df2 100644 --- a/daemon/image_service.go +++ b/daemon/image_service.go @@ -33,10 +33,10 @@ 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(refOrID string, platform *v1.Platform) (retImg *image.Image, retErr error) + GetImage(ctx context.Context, refOrID string, platform *v1.Platform) (*image.Image, error) ImageHistory(name string) ([]*imagetype.HistoryResponseItem, error) CommitImage(c backend.CommitConfig) (image.ID, error) SquashImage(id, parent string) (string, error) @@ -55,7 +55,7 @@ type ImageService interface { GetLayerFolders(img *image.Image, rwLayer layer.RWLayer) ([]string, error) // Build - MakeImageCache(sourceRefs []string) builder.ImageCache + MakeImageCache(ctx context.Context, cacheFrom []string) builder.ImageCache CommitBuildStep(c backend.CommitConfig) (image.ID, error) // Other diff --git a/daemon/images/cache.go b/daemon/images/cache.go index 445b1b9261831..000d73211861a 100644 --- a/daemon/images/cache.go +++ b/daemon/images/cache.go @@ -1,13 +1,15 @@ package images // import "github.com/docker/docker/daemon/images" import ( + "context" + "github.com/docker/docker/builder" "github.com/docker/docker/image/cache" "github.com/sirupsen/logrus" ) // MakeImageCache creates a stateful image cache. -func (i *ImageService) MakeImageCache(sourceRefs []string) builder.ImageCache { +func (i *ImageService) MakeImageCache(ctx context.Context, sourceRefs []string) builder.ImageCache { if len(sourceRefs) == 0 { return cache.NewLocal(i.imageStore) } @@ -15,7 +17,7 @@ func (i *ImageService) MakeImageCache(sourceRefs []string) builder.ImageCache { cache := cache.New(i.imageStore) for _, ref := range sourceRefs { - img, err := i.GetImage(ref, nil) + img, err := i.GetImage(ctx, ref, nil) if err != nil { logrus.Warnf("Could not look up %s for cache resolution, skipping: %+v", ref, err) continue diff --git a/daemon/images/image.go b/daemon/images/image.go index 2dd7759900bc9..625591fe8fd8d 100644 --- a/daemon/images/image.go +++ b/daemon/images/image.go @@ -148,7 +148,7 @@ func (i *ImageService) manifestMatchesPlatform(img *image.Image, platform specs. } // GetImage returns an image corresponding to the image referred to by refOrID. -func (i *ImageService) GetImage(refOrID string, platform *specs.Platform) (retImg *image.Image, retErr error) { +func (i *ImageService) GetImage(ctx context.Context, refOrID string, platform *specs.Platform) (retImg *image.Image, retErr error) { defer func() { if retErr != nil || retImg == nil || platform == nil { return diff --git a/daemon/images/image_builder.go b/daemon/images/image_builder.go index 52cd3d88ee60e..60da65a2d6e21 100644 --- a/daemon/images/image_builder.go +++ b/daemon/images/image_builder.go @@ -167,7 +167,7 @@ func (i *ImageService) pullForBuilder(ctx context.Context, name string, authConf return nil, err } - img, err := i.GetImage(name, platform) + img, err := i.GetImage(nil, name, platform) if errdefs.IsNotFound(err) && img != nil && platform != nil { imgPlat := specs.Platform{ OS: img.OS, @@ -211,7 +211,7 @@ func (i *ImageService) GetImageAndReleasableLayer(ctx context.Context, refOrID s } if opts.PullOption != backend.PullOptionForcePull { - image, err := i.GetImage(refOrID, opts.Platform) + image, err := i.GetImage(nil, refOrID, opts.Platform) if err != nil && opts.PullOption == backend.PullOptionNoPull { return nil, nil, err } diff --git a/daemon/images/image_delete.go b/daemon/images/image_delete.go index 1c1676d5859ed..c3a6576c80874 100644 --- a/daemon/images/image_delete.go +++ b/daemon/images/image_delete.go @@ -63,7 +63,7 @@ func (i *ImageService) ImageDelete(imageRef string, force, prune bool) ([]types. start := time.Now() records := []types.ImageDeleteResponseItem{} - img, err := i.GetImage(imageRef, nil) + img, err := i.GetImage(nil, imageRef, nil) if err != nil { return nil, err } diff --git a/daemon/images/image_events.go b/daemon/images/image_events.go index 1d8cfcd914dc8..e89a7c49c7e5e 100644 --- a/daemon/images/image_events.go +++ b/daemon/images/image_events.go @@ -11,7 +11,7 @@ func (i *ImageService) LogImageEvent(imageID, refName, action string) { // LogImageEventWithAttributes generates an event related to an image with specific given attributes. func (i *ImageService) LogImageEventWithAttributes(imageID, refName, action string, attributes map[string]string) { - img, err := i.GetImage(imageID, nil) + img, err := i.GetImage(nil, imageID, nil) if err == nil && img.Config != nil { // image has not been removed yet. // it could be missing if the event is `delete`. diff --git a/daemon/images/image_history.go b/daemon/images/image_history.go index c1f48829526dc..b092b2f76f5ff 100644 --- a/daemon/images/image_history.go +++ b/daemon/images/image_history.go @@ -13,7 +13,7 @@ import ( // name by walking the image lineage. func (i *ImageService) ImageHistory(name string) ([]*image.HistoryResponseItem, error) { start := time.Now() - img, err := i.GetImage(name, nil) + img, err := i.GetImage(nil, name, nil) if err != nil { return nil, err } @@ -69,7 +69,7 @@ func (i *ImageService) ImageHistory(name string) ([]*image.HistoryResponseItem, if id == "" { break } - histImg, err = i.GetImage(id.String(), nil) + histImg, err = i.GetImage(nil, id.String(), nil) if err != nil { break } diff --git a/daemon/images/image_import.go b/daemon/images/image_import.go index d732cf55fadd0..e0d246b52ee91 100644 --- a/daemon/images/image_import.go +++ b/daemon/images/image_import.go @@ -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 } diff --git a/daemon/images/image_pull.go b/daemon/images/image_pull.go index 596a43b3a9784..15abf08cab92c 100644 --- a/daemon/images/image_pull.go +++ b/daemon/images/image_pull.go @@ -63,7 +63,7 @@ func (i *ImageService) PullImage(ctx context.Context, image, tag string, platfor // we allow the image to have a non-matching architecture. The code // below checks for this situation, and returns a warning to the client, // as well as logging it to the daemon logs. - img, err := i.GetImage(image, platform) + img, err := i.GetImage(nil, image, platform) // Note that this is a special case where GetImage returns both an image // and an error: https://github.com/docker/docker/blob/v20.10.7/daemon/images/image.go#L175-L183 diff --git a/daemon/images/image_tag.go b/daemon/images/image_tag.go index becd2e2df3d77..7ffe481e7d4b0 100644 --- a/daemon/images/image_tag.go +++ b/daemon/images/image_tag.go @@ -8,7 +8,7 @@ import ( // TagImage creates the tag specified by newTag, pointing to the image named // imageName (alternatively, imageName can also be an image ID). func (i *ImageService) TagImage(imageName, repository, tag string) (string, error) { - img, err := i.GetImage(imageName, nil) + img, err := i.GetImage(nil, imageName, nil) if err != nil { return "", err } diff --git a/daemon/images/images.go b/daemon/images/images.go index 7f61c98013df4..3124defc11ab9 100644 --- a/daemon/images/images.go +++ b/daemon/images/images.go @@ -58,7 +58,7 @@ func (i *ImageService) Images(_ context.Context, opts types.ImageListOptions) ([ err error ) err = opts.Filters.WalkValues("before", func(value string) error { - beforeFilter, err = i.GetImage(value, nil) + beforeFilter, err = i.GetImage(nil, value, nil) return err }) if err != nil { @@ -66,7 +66,7 @@ func (i *ImageService) Images(_ context.Context, opts types.ImageListOptions) ([ } err = opts.Filters.WalkValues("since", func(value string) error { - sinceFilter, err = i.GetImage(value, nil) + sinceFilter, err = i.GetImage(nil, value, nil) return err }) if err != nil { diff --git a/daemon/list.go b/daemon/list.go index e3c4153582e52..dedf38febca9f 100644 --- a/daemon/list.go +++ b/daemon/list.go @@ -1,6 +1,7 @@ package daemon // import "github.com/docker/docker/daemon" import ( + "context" "fmt" "sort" "strconv" @@ -40,7 +41,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. @@ -104,8 +105,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, ctx *listContext) ([]container.Snapshot, error) { @@ -175,7 +176,7 @@ func (daemon *Daemon) filterByNameIDMatches(view container.View, ctx *listContex } // 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 } @@ -185,7 +186,7 @@ func (daemon *Daemon) reduceContainers(config *types.ContainerListOptions, reduc containers = []*types.Container{} ) - ctx, err := daemon.foldFilter(view, config) + filter, err := daemon.foldFilter(ctx, view, config) if err != nil { return nil, err } @@ -193,13 +194,13 @@ func (daemon *Daemon) reduceContainers(config *types.ContainerListOptions, reduc // fastpath to only look at a subset of containers if specific name // or ID matches were provided by the user--otherwise we potentially // end up querying many more containers than intended - containerList, err := daemon.filterByNameIDMatches(view, ctx) + containerList, err := daemon.filterByNameIDMatches(view, filter) if err != nil { return nil, err } for i := range containerList { - t, err := daemon.reducePsContainer(&containerList[i], ctx, reducer) + t, err := daemon.reducePsContainer(ctx, &containerList[i], filter, reducer) if err != nil { if err != errStopIteration { return nil, err @@ -208,7 +209,7 @@ func (daemon *Daemon) reduceContainers(config *types.ContainerListOptions, reduc } if t != nil { containers = append(containers, t) - ctx.idx++ + filter.idx++ } } @@ -216,9 +217,9 @@ 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, ctx *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, ctx) { + switch includeContainerInList(container, filter) { case excludeContainer: return nil, nil case stopIteration: @@ -226,13 +227,13 @@ func (daemon *Daemon) reducePsContainer(container *container.Snapshot, ctx *list } // transform internal container struct into api structs - newC, err := reducer(container, ctx) + newC, err := reducer(ctx, container, filter) if err != nil { return nil, err } // release lock because size calculation is slow - if ctx.Size { + if filter.Size { sizeRw, sizeRootFs := daemon.imageService.GetContainerLayerSize(newC.ID) newC.SizeRw = sizeRw newC.SizeRootFs = sizeRootFs @@ -241,7 +242,7 @@ func (daemon *Daemon) reducePsContainer(container *container.Snapshot, ctx *list } // foldFilter generates the container filter based on the user's filtering options. -func (daemon *Daemon) foldFilter(view container.View, config *types.ContainerListOptions) (*listContext, error) { +func (daemon *Daemon) foldFilter(ctx context.Context, view container.View, config *types.ContainerListOptions) (*listContext, error) { psFilters := config.Filters var filtExited []int @@ -317,7 +318,7 @@ func (daemon *Daemon) foldFilter(view container.View, config *types.ContainerLis if psFilters.Contains("ancestor") { ancestorFilter = true psFilters.WalkValues("ancestor", func(ancestor string) error { - img, err := daemon.imageService.GetImage(ancestor, nil) + img, err := daemon.imageService.GetImage(ctx, ancestor, nil) if err != nil { logrus.Warnf("Error while looking up for image %v", ancestor) return nil @@ -577,11 +578,11 @@ func includeContainerInList(container *container.Snapshot, ctx *listContext) ite } // 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, ctx *listContext) (*types.Container, error) { +func (daemon *Daemon) refreshImage(ctx context.Context, s *container.Snapshot, filter *listContext) (*types.Container, error) { c := s.Container image := s.Image // keep the original ref if still valid (hasn't changed) if image != s.ImageID { - img, err := daemon.imageService.GetImage(image, nil) + img, err := daemon.imageService.GetImage(ctx, image, nil) if _, isDNE := err.(images.ErrImageDoesNotExist); err != nil && !isDNE { return nil, err } diff --git a/daemon/list_test.go b/daemon/list_test.go index 955d137aa1a21..15e38abd0dbc5 100644 --- a/daemon/list_test.go +++ b/daemon/list_test.go @@ -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) diff --git a/daemon/monitor.go b/daemon/monitor.go index 36b82f17a7d60..c75984bbdd244 100644 --- a/daemon/monitor.go +++ b/daemon/monitor.go @@ -84,7 +84,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) } } diff --git a/daemon/oci_linux.go b/daemon/oci_linux.go index 8c9aca041010a..1fd4aed82510c 100644 --- a/daemon/oci_linux.go +++ b/daemon/oci_linux.go @@ -1011,7 +1011,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() diff --git a/daemon/oci_linux_test.go b/daemon/oci_linux_test.go index 42084c900d03d..d6297b99739a5 100644 --- a/daemon/oci_linux_test.go +++ b/daemon/oci_linux_test.go @@ -1,6 +1,7 @@ package daemon // import "github.com/docker/docker/daemon" import ( + "context" "os" "path/filepath" "testing" @@ -74,7 +75,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) } @@ -93,7 +94,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 @@ -123,7 +124,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) @@ -139,7 +140,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"]) @@ -147,7 +148,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) @@ -155,7 +156,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") } @@ -175,7 +176,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"], "") @@ -183,7 +184,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"]) } diff --git a/daemon/oci_windows.go b/daemon/oci_windows.go index 886be9ae2542d..432933965625a 100644 --- a/daemon/oci_windows.go +++ b/daemon/oci_windows.go @@ -1,6 +1,7 @@ package daemon // import "github.com/docker/docker/daemon" import ( + "context" "encoding/json" "fmt" "os" @@ -24,9 +25,9 @@ const ( credentialSpecFileLocation = "CredentialSpecs" ) -func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) { +func (daemon *Daemon) createSpec(ctx context.Context, c *container.Container) (*specs.Spec, error) { - img, err := daemon.imageService.GetImage(string(c.ImageID), nil) + img, err := daemon.imageService.GetImage(ctx, string(c.ImageID), nil) if err != nil { return nil, err } diff --git a/daemon/restart.go b/daemon/restart.go index c20e8cbb1085d..2ea17d57a2e37 100644 --- a/daemon/restart.go +++ b/daemon/restart.go @@ -71,7 +71,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 } diff --git a/daemon/start.go b/daemon/start.go index fc5aa5b55f5eb..718721451b761 100644 --- a/daemon/start.go +++ b/daemon/start.go @@ -14,7 +14,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")) } @@ -91,14 +91,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() @@ -150,7 +150,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) } @@ -176,15 +176,13 @@ func (daemon *Daemon) containerStart(container *container.Container, checkpoint return err } - ctx := context.TODO() - err = daemon.containerd.Create(ctx, container.ID, spec, shim, createOptions) if err != nil { if errdefs.IsConflict(err) { logrus.WithError(err).WithField("container", container.ID).Error("Container not cleaned up from containerd from previous run") // best effort to clean up old container object - daemon.containerd.DeleteTask(ctx, container.ID) - if err := daemon.containerd.Delete(ctx, container.ID); err != nil && !errdefs.IsNotFound(err) { + daemon.containerd.DeleteTask(context.Background(), container.ID) + if err := daemon.containerd.Delete(context.Background(), container.ID); err != nil && !errdefs.IsNotFound(err) { logrus.WithError(err).WithField("container", container.ID).Error("Error cleaning up stale containerd container object") } err = daemon.containerd.Create(ctx, container.ID, spec, shim, createOptions) @@ -195,11 +193,11 @@ func (daemon *Daemon) containerStart(container *container.Container, checkpoint } // TODO(mlaventure): we need to specify checkpoint options here - pid, err := daemon.containerd.Start(context.Background(), container.ID, checkpointDir, + pid, err := daemon.containerd.Start(ctx, container.ID, checkpointDir, container.StreamConfig.Stdin() != nil || container.Config.Tty, container.InitializeStdio) if err != nil { - if err := daemon.containerd.Delete(context.Background(), container.ID); err != nil { + if err := daemon.containerd.Delete(ctx, container.ID); err != nil { logrus.WithError(err).WithField("container", container.ID). Error("failed to delete failed start container") }