diff --git a/api/server/container.go b/api/server/container.go index c4ea19d9b2..b5838246b1 100644 --- a/api/server/container.go +++ b/api/server/container.go @@ -45,7 +45,7 @@ func (s *Server) getContainersJSON(ctx context.Context, w http.ResponseWriter, r config.Limit = limit } - containers, err := s.daemon.Containers(config) + containers, err := s.daemon.Containers(ctx, config) if err != nil { return err } @@ -83,7 +83,7 @@ func (s *Server) getContainersStats(ctx context.Context, w http.ResponseWriter, Version: version, } - return s.daemon.ContainerStats(vars["name"], config) + return s.daemon.ContainerStats(ctx, vars["name"], config) } func (s *Server) getContainersLogs(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { @@ -118,7 +118,7 @@ func (s *Server) getContainersLogs(ctx context.Context, w http.ResponseWriter, r closeNotifier = notifier.CloseNotify() } - c, err := s.daemon.Get(vars["name"]) + c, err := s.daemon.Get(ctx, vars["name"]) if err != nil { return err } @@ -140,7 +140,7 @@ func (s *Server) getContainersLogs(ctx context.Context, w http.ResponseWriter, r Stop: closeNotifier, } - if err := s.daemon.ContainerLogs(c, logsConfig); err != nil { + if err := s.daemon.ContainerLogs(ctx, c, logsConfig); err != nil { // The client may be expecting all of the data we're sending to // be multiplexed, so send it through OutStream, which will // have been set up to handle that if needed. @@ -155,7 +155,7 @@ func (s *Server) getContainersExport(ctx context.Context, w http.ResponseWriter, return fmt.Errorf("Missing parameter") } - return s.daemon.ContainerExport(vars["name"], w) + return s.daemon.ContainerExport(ctx, vars["name"], w) } func (s *Server) postContainersStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { @@ -183,7 +183,7 @@ func (s *Server) postContainersStart(ctx context.Context, w http.ResponseWriter, hostConfig = c } - if err := s.daemon.ContainerStart(vars["name"], hostConfig); err != nil { + if err := s.daemon.ContainerStart(ctx, vars["name"], hostConfig); err != nil { return err } w.WriteHeader(http.StatusNoContent) @@ -200,7 +200,7 @@ func (s *Server) postContainersStop(ctx context.Context, w http.ResponseWriter, seconds, _ := strconv.Atoi(r.Form.Get("t")) - if err := s.daemon.ContainerStop(vars["name"], seconds); err != nil { + if err := s.daemon.ContainerStop(ctx, vars["name"], seconds); err != nil { return err } w.WriteHeader(http.StatusNoContent) @@ -227,7 +227,7 @@ func (s *Server) postContainersKill(ctx context.Context, w http.ResponseWriter, } } - if err := s.daemon.ContainerKill(name, uint64(sig)); err != nil { + if err := s.daemon.ContainerKill(ctx, name, uint64(sig)); err != nil { theErr, isDerr := err.(errcode.ErrorCoder) isStopped := isDerr && theErr.ErrorCode() == derr.ErrorCodeNotRunning @@ -254,7 +254,7 @@ func (s *Server) postContainersRestart(ctx context.Context, w http.ResponseWrite timeout, _ := strconv.Atoi(r.Form.Get("t")) - if err := s.daemon.ContainerRestart(vars["name"], timeout); err != nil { + if err := s.daemon.ContainerRestart(ctx, vars["name"], timeout); err != nil { return err } @@ -271,7 +271,7 @@ func (s *Server) postContainersPause(ctx context.Context, w http.ResponseWriter, return err } - if err := s.daemon.ContainerPause(vars["name"]); err != nil { + if err := s.daemon.ContainerPause(ctx, vars["name"]); err != nil { return err } @@ -288,7 +288,7 @@ func (s *Server) postContainersUnpause(ctx context.Context, w http.ResponseWrite return err } - if err := s.daemon.ContainerUnpause(vars["name"]); err != nil { + if err := s.daemon.ContainerUnpause(ctx, vars["name"]); err != nil { return err } @@ -302,7 +302,7 @@ func (s *Server) postContainersWait(ctx context.Context, w http.ResponseWriter, return fmt.Errorf("Missing parameter") } - status, err := s.daemon.ContainerWait(vars["name"], -1*time.Second) + status, err := s.daemon.ContainerWait(ctx, vars["name"], -1*time.Second) if err != nil { return err } @@ -317,7 +317,7 @@ func (s *Server) getContainersChanges(ctx context.Context, w http.ResponseWriter return fmt.Errorf("Missing parameter") } - changes, err := s.daemon.ContainerChanges(vars["name"]) + changes, err := s.daemon.ContainerChanges(ctx, vars["name"]) if err != nil { return err } @@ -334,7 +334,7 @@ func (s *Server) getContainersTop(ctx context.Context, w http.ResponseWriter, r return err } - procList, err := s.daemon.ContainerTop(vars["name"], r.Form.Get("ps_args")) + procList, err := s.daemon.ContainerTop(ctx, vars["name"], r.Form.Get("ps_args")) if err != nil { return err } @@ -352,7 +352,7 @@ func (s *Server) postContainerRename(ctx context.Context, w http.ResponseWriter, name := vars["name"] newName := r.Form.Get("name") - if err := s.daemon.ContainerRename(name, newName); err != nil { + if err := s.daemon.ContainerRename(ctx, name, newName); err != nil { return err } w.WriteHeader(http.StatusNoContent) @@ -378,7 +378,7 @@ func (s *Server) postContainersCreate(ctx context.Context, w http.ResponseWriter version := ctx.Version() adjustCPUShares := version.LessThan("1.19") - container, warnings, err := s.daemon.ContainerCreate(name, config, hostConfig, adjustCPUShares) + container, warnings, err := s.daemon.ContainerCreate(ctx, name, config, hostConfig, adjustCPUShares) if err != nil { return err } @@ -404,7 +404,7 @@ func (s *Server) deleteContainers(ctx context.Context, w http.ResponseWriter, r RemoveLink: boolValue(r, "link"), } - if err := s.daemon.ContainerRm(name, config); err != nil { + if err := s.daemon.ContainerRm(ctx, name, config); err != nil { // Force a 404 for the empty string if strings.Contains(strings.ToLower(err.Error()), "prefix can't be empty") { return fmt.Errorf("no such id: \"\"") @@ -434,7 +434,7 @@ func (s *Server) postContainersResize(ctx context.Context, w http.ResponseWriter return err } - return s.daemon.ContainerResize(vars["name"], height, width) + return s.daemon.ContainerResize(ctx, vars["name"], height, width) } func (s *Server) postContainersAttach(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { @@ -446,7 +446,7 @@ func (s *Server) postContainersAttach(ctx context.Context, w http.ResponseWriter } containerName := vars["name"] - if !s.daemon.Exists(containerName) { + if !s.daemon.Exists(ctx, containerName) { return derr.ErrorCodeNoSuchContainer.WithArgs(containerName) } @@ -472,7 +472,7 @@ func (s *Server) postContainersAttach(ctx context.Context, w http.ResponseWriter Stream: boolValue(r, "stream"), } - if err := s.daemon.ContainerAttachWithLogs(containerName, attachWithLogsConfig); err != nil { + if err := s.daemon.ContainerAttachWithLogs(ctx, containerName, attachWithLogsConfig); err != nil { fmt.Fprintf(outStream, "Error attaching: %s\n", err) } @@ -488,7 +488,7 @@ func (s *Server) wsContainersAttach(ctx context.Context, w http.ResponseWriter, } containerName := vars["name"] - if !s.daemon.Exists(containerName) { + if !s.daemon.Exists(ctx, containerName) { return derr.ErrorCodeNoSuchContainer.WithArgs(containerName) } @@ -503,7 +503,7 @@ func (s *Server) wsContainersAttach(ctx context.Context, w http.ResponseWriter, Stream: boolValue(r, "stream"), } - if err := s.daemon.ContainerWsAttachWithLogs(containerName, wsAttachWithLogsConfig); err != nil { + if err := s.daemon.ContainerWsAttachWithLogs(ctx, containerName, wsAttachWithLogsConfig); err != nil { logrus.Errorf("Error attaching websocket: %s", err) } }) diff --git a/api/server/copy.go b/api/server/copy.go index b3d8ed320e..94d5a9154e 100644 --- a/api/server/copy.go +++ b/api/server/copy.go @@ -32,7 +32,7 @@ func (s *Server) postContainersCopy(ctx context.Context, w http.ResponseWriter, return fmt.Errorf("Path cannot be empty") } - data, err := s.daemon.ContainerCopy(vars["name"], cfg.Resource) + data, err := s.daemon.ContainerCopy(ctx, vars["name"], cfg.Resource) if err != nil { if strings.Contains(strings.ToLower(err.Error()), "no such id") { w.WriteHeader(http.StatusNotFound) @@ -74,7 +74,7 @@ func (s *Server) headContainersArchive(ctx context.Context, w http.ResponseWrite return err } - stat, err := s.daemon.ContainerStatPath(v.name, v.path) + stat, err := s.daemon.ContainerStatPath(ctx, v.name, v.path) if err != nil { return err } @@ -88,7 +88,7 @@ func (s *Server) getContainersArchive(ctx context.Context, w http.ResponseWriter return err } - tarArchive, stat, err := s.daemon.ContainerArchivePath(v.name, v.path) + tarArchive, stat, err := s.daemon.ContainerArchivePath(ctx, v.name, v.path) if err != nil { return err } @@ -111,5 +111,5 @@ func (s *Server) putContainersArchive(ctx context.Context, w http.ResponseWriter } noOverwriteDirNonDir := boolValue(r, "noOverwriteDirNonDir") - return s.daemon.ContainerExtractToDir(v.name, v.path, noOverwriteDirNonDir, r.Body) + return s.daemon.ContainerExtractToDir(ctx, v.name, v.path, noOverwriteDirNonDir, r.Body) } diff --git a/api/server/daemon.go b/api/server/daemon.go index b8ee0fa46e..171a9e2b2e 100644 --- a/api/server/daemon.go +++ b/api/server/daemon.go @@ -45,7 +45,7 @@ func (s *Server) getVersion(ctx context.Context, w http.ResponseWriter, r *http. } func (s *Server) getInfo(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { - info, err := s.daemon.SystemInfo() + info, err := s.daemon.SystemInfo(ctx) if err != nil { return err } @@ -120,7 +120,7 @@ func (s *Server) getEvents(ctx context.Context, w http.ResponseWriter, r *http.R enc := json.NewEncoder(outStream) getContainerID := func(cn string) string { - c, err := d.Get(cn) + c, err := d.Get(ctx, cn) if err != nil { return "" } diff --git a/api/server/exec.go b/api/server/exec.go index 46d46c58b7..504c55d6b5 100644 --- a/api/server/exec.go +++ b/api/server/exec.go @@ -19,7 +19,7 @@ func (s *Server) getExecByID(ctx context.Context, w http.ResponseWriter, r *http return fmt.Errorf("Missing parameter 'id'") } - eConfig, err := s.daemon.ContainerExecInspect(vars["id"]) + eConfig, err := s.daemon.ContainerExecInspect(ctx, vars["id"]) if err != nil { return err } @@ -47,7 +47,7 @@ func (s *Server) postContainerExecCreate(ctx context.Context, w http.ResponseWri } // Register an instance of Exec in container. - id, err := s.daemon.ContainerExecCreate(execConfig) + id, err := s.daemon.ContainerExecCreate(ctx, execConfig) if err != nil { logrus.Errorf("Error setting up exec command in container %s: %s", name, err) return err @@ -100,7 +100,7 @@ func (s *Server) postContainerExecStart(ctx context.Context, w http.ResponseWrit } // Now run the user process in container. - if err := s.daemon.ContainerExecStart(execName, stdin, stdout, stderr); err != nil { + if err := s.daemon.ContainerExecStart(ctx, execName, stdin, stdout, stderr); err != nil { fmt.Fprintf(outStream, "Error running exec in container: %v\n", err) } return nil @@ -123,5 +123,5 @@ func (s *Server) postContainerExecResize(ctx context.Context, w http.ResponseWri return err } - return s.daemon.ContainerExecResize(vars["name"], height, width) + return s.daemon.ContainerExecResize(ctx, vars["name"], height, width) } diff --git a/api/server/image.go b/api/server/image.go index 9a5718b07f..bb36d6ad21 100644 --- a/api/server/image.go +++ b/api/server/image.go @@ -55,7 +55,7 @@ func (s *Server) postCommit(ctx context.Context, w http.ResponseWriter, r *http. Config: c, } - imgID, err := builder.Commit(cname, s.daemon, commitCfg) + imgID, err := builder.Commit(ctx, cname, s.daemon, commitCfg) if err != nil { return err } @@ -112,7 +112,7 @@ func (s *Server) postImagesCreate(ctx context.Context, w http.ResponseWriter, r OutStream: output, } - err = s.daemon.Repositories().Pull(image, tag, imagePullConfig) + err = s.daemon.Repositories(ctx).Pull(ctx, image, tag, imagePullConfig) } else { //import if tag == "" { repo, tag = parsers.ParseRepositoryTag(repo) @@ -124,12 +124,12 @@ func (s *Server) postImagesCreate(ctx context.Context, w http.ResponseWriter, r // generated from the download to be available to the output // stream processing below var newConfig *runconfig.Config - newConfig, err = builder.BuildFromConfig(s.daemon, &runconfig.Config{}, r.Form["changes"]) + newConfig, err = builder.BuildFromConfig(ctx, s.daemon, &runconfig.Config{}, r.Form["changes"]) if err != nil { return err } - err = s.daemon.Repositories().Import(src, repo, tag, message, r.Body, output, newConfig) + err = s.daemon.Repositories(ctx).Import(ctx, src, repo, tag, message, r.Body, output, newConfig) } if err != nil { if !output.Flushed() { @@ -184,7 +184,7 @@ func (s *Server) postImagesPush(ctx context.Context, w http.ResponseWriter, r *h w.Header().Set("Content-Type", "application/json") - if err := s.daemon.Repositories().Push(name, imagePushConfig); err != nil { + if err := s.daemon.Repositories(ctx).Push(ctx, name, imagePushConfig); err != nil { if !output.Flushed() { return err } @@ -212,7 +212,7 @@ func (s *Server) getImagesGet(ctx context.Context, w http.ResponseWriter, r *htt names = r.Form["names"] } - if err := s.daemon.Repositories().ImageExport(names, output); err != nil { + if err := s.daemon.Repositories(ctx).ImageExport(names, output); err != nil { if !output.Flushed() { return err } @@ -223,7 +223,7 @@ func (s *Server) getImagesGet(ctx context.Context, w http.ResponseWriter, r *htt } func (s *Server) postImagesLoad(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { - return s.daemon.Repositories().Load(r.Body, w) + return s.daemon.Repositories(ctx).Load(r.Body, w) } func (s *Server) deleteImages(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { @@ -243,7 +243,7 @@ func (s *Server) deleteImages(ctx context.Context, w http.ResponseWriter, r *htt force := boolValue(r, "force") prune := !boolValue(r, "noprune") - list, err := s.daemon.ImageDelete(name, force, prune) + list, err := s.daemon.ImageDelete(ctx, name, force, prune) if err != nil { return err } @@ -256,7 +256,7 @@ func (s *Server) getImagesByName(ctx context.Context, w http.ResponseWriter, r * return fmt.Errorf("Missing parameter") } - imageInspect, err := s.daemon.Repositories().Lookup(vars["name"]) + imageInspect, err := s.daemon.Repositories(ctx).Lookup(vars["name"]) if err != nil { return err } @@ -346,7 +346,7 @@ func (s *Server) postBuild(ctx context.Context, w http.ResponseWriter, r *http.R }() } - if err := builder.Build(s.daemon, buildConfig); err != nil { + if err := builder.Build(ctx, s.daemon, buildConfig); err != nil { // Do not write the error in the http output if it's still empty. // This prevents from writing a 200(OK) when there is an interal error. if !output.Flushed() { @@ -364,7 +364,7 @@ func (s *Server) getImagesJSON(ctx context.Context, w http.ResponseWriter, r *ht } // FIXME: The filter parameter could just be a match filter - images, err := s.daemon.Repositories().Images(r.Form.Get("filters"), r.Form.Get("filter"), boolValue(r, "all")) + images, err := s.daemon.Repositories(ctx).Images(r.Form.Get("filters"), r.Form.Get("filter"), boolValue(r, "all")) if err != nil { return err } @@ -378,7 +378,7 @@ func (s *Server) getImagesHistory(ctx context.Context, w http.ResponseWriter, r } name := vars["name"] - history, err := s.daemon.Repositories().History(name) + history, err := s.daemon.Repositories(ctx).History(name) if err != nil { return err } @@ -398,10 +398,10 @@ func (s *Server) postImagesTag(ctx context.Context, w http.ResponseWriter, r *ht tag := r.Form.Get("tag") force := boolValue(r, "force") name := vars["name"] - if err := s.daemon.Repositories().Tag(repo, tag, name, force); err != nil { + if err := s.daemon.Repositories(ctx).Tag(repo, tag, name, force); err != nil { return err } - s.daemon.EventsService.Log("tag", utils.ImageReference(repo, tag), "") + s.daemon.EventsService.Log(ctx, "tag", utils.ImageReference(repo, tag), "") w.WriteHeader(http.StatusCreated) return nil } diff --git a/api/server/inspect.go b/api/server/inspect.go index 782ae4865c..4d61047dfd 100644 --- a/api/server/inspect.go +++ b/api/server/inspect.go @@ -20,11 +20,11 @@ func (s *Server) getContainersByName(ctx context.Context, w http.ResponseWriter, switch { case version.LessThan("1.20"): - json, err = s.daemon.ContainerInspectPre120(vars["name"]) + json, err = s.daemon.ContainerInspectPre120(ctx, vars["name"]) case version.Equal("1.20"): - json, err = s.daemon.ContainerInspect120(vars["name"]) + json, err = s.daemon.ContainerInspect120(ctx, vars["name"]) default: - json, err = s.daemon.ContainerInspect(vars["name"]) + json, err = s.daemon.ContainerInspect(ctx, vars["name"]) } if err != nil { diff --git a/api/server/server.go b/api/server/server.go index a2d927ceff..8f7d97999f 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -18,6 +18,7 @@ import ( "github.com/docker/docker/context" "github.com/docker/docker/daemon" "github.com/docker/docker/pkg/sockets" + "github.com/docker/docker/pkg/stringid" "github.com/docker/docker/utils" ) @@ -41,12 +42,12 @@ type Server struct { } // New returns a new instance of the server based on the specified configuration. -func New(cfg *Config) *Server { +func New(ctx context.Context, cfg *Config) *Server { srv := &Server{ cfg: cfg, start: make(chan struct{}), } - srv.router = createRouter(srv) + srv.router = createRouter(ctx, srv) return srv } @@ -290,7 +291,7 @@ func (s *Server) initTCPSocket(addr string) (l net.Listener, err error) { return } -func (s *Server) makeHTTPHandler(localMethod string, localRoute string, localHandler HTTPAPIFunc) http.HandlerFunc { +func (s *Server) makeHTTPHandler(ctx context.Context, localMethod string, localRoute string, localHandler HTTPAPIFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // log the handler generation logrus.Debugf("Calling %s %s", localMethod, localRoute) @@ -302,7 +303,8 @@ func (s *Server) makeHTTPHandler(localMethod string, localRoute string, localHan // apply to all requests. Data that is specific to the // immediate function being called should still be passed // as 'args' on the function call. - ctx := context.Background() + reqID := stringid.TruncateID(stringid.GenerateNonCryptoID()) + ctx = context.WithValue(ctx, context.RequestID, reqID) handlerFunc := s.handleWithGlobalMiddlewares(localHandler) if err := handlerFunc(ctx, w, r, mux.Vars(r)); err != nil { @@ -314,7 +316,7 @@ func (s *Server) makeHTTPHandler(localMethod string, localRoute string, localHan // createRouter initializes the main router the server uses. // we keep enableCors just for legacy usage, need to be removed in the future -func createRouter(s *Server) *mux.Router { +func createRouter(ctx context.Context, s *Server) *mux.Router { r := mux.NewRouter() if os.Getenv("DEBUG") != "" { profilerSetup(r, "/debug/") @@ -394,7 +396,7 @@ func createRouter(s *Server) *mux.Router { localMethod := method // build the handler function - f := s.makeHTTPHandler(localMethod, localRoute, localFct) + f := s.makeHTTPHandler(ctx, localMethod, localRoute, localFct) // add the new route if localRoute == "" { diff --git a/api/server/server_experimental_unix.go b/api/server/server_experimental_unix.go index b02e849a7f..e8e2c2948d 100644 --- a/api/server/server_experimental_unix.go +++ b/api/server/server_experimental_unix.go @@ -2,8 +2,12 @@ package server -func (s *Server) registerSubRouter() { - httpHandler := s.daemon.NetworkAPIRouter() +import ( + "github.com/docker/docker/context" +) + +func (s *Server) registerSubRouter(ctx context.Context) { + httpHandler := s.daemon.NetworkAPIRouter(ctx) subrouter := s.router.PathPrefix("/v{version:[0-9.]+}/networks").Subrouter() subrouter.Methods("GET", "POST", "PUT", "DELETE").HandlerFunc(httpHandler) diff --git a/api/server/server_stub.go b/api/server/server_stub.go index cae2849383..b899bb9a0a 100644 --- a/api/server/server_stub.go +++ b/api/server/server_stub.go @@ -2,5 +2,9 @@ package server -func (s *Server) registerSubRouter() { +import ( + "github.com/docker/docker/context" +) + +func (s *Server) registerSubRouter(ctx context.Context) { } diff --git a/api/server/server_unix.go b/api/server/server_unix.go index 2c1621f9b3..ec2ac9b4cd 100644 --- a/api/server/server_unix.go +++ b/api/server/server_unix.go @@ -8,6 +8,7 @@ import ( "net/http" "strconv" + "github.com/docker/docker/context" "github.com/docker/docker/daemon" "github.com/docker/docker/pkg/sockets" "github.com/docker/libnetwork/portallocator" @@ -63,10 +64,10 @@ func (s *Server) newServer(proto, addr string) ([]serverCloser, error) { // AcceptConnections allows clients to connect to the API server. // Referenced Daemon is notified about this server, and waits for the // daemon acknowledgement before the incoming connections are accepted. -func (s *Server) AcceptConnections(d *daemon.Daemon) { +func (s *Server) AcceptConnections(ctx context.Context, d *daemon.Daemon) { // Tell the init daemon we are accepting requests s.daemon = d - s.registerSubRouter() + s.registerSubRouter(ctx) go systemdDaemon.SdNotify("READY=1") // close the lock so the listeners start accepting connections select { diff --git a/api/server/server_windows.go b/api/server/server_windows.go index 8763ba04a8..0a04e39905 100644 --- a/api/server/server_windows.go +++ b/api/server/server_windows.go @@ -7,6 +7,7 @@ import ( "net" "net/http" + "github.com/docker/docker/context" "github.com/docker/docker/daemon" ) @@ -42,9 +43,9 @@ func (s *Server) newServer(proto, addr string) ([]serverCloser, error) { } // AcceptConnections allows router to start listening for the incoming requests. -func (s *Server) AcceptConnections(d *daemon.Daemon) { +func (s *Server) AcceptConnections(ctx context.Context, d *daemon.Daemon) { s.daemon = d - s.registerSubRouter() + s.registerSubRouter(ctx) // close the lock so the listeners start accepting connections select { case <-s.start: diff --git a/api/server/volume.go b/api/server/volume.go index cec3b820c4..9acaaac0e3 100644 --- a/api/server/volume.go +++ b/api/server/volume.go @@ -13,7 +13,7 @@ func (s *Server) getVolumesList(ctx context.Context, w http.ResponseWriter, r *h return err } - volumes, err := s.daemon.Volumes(r.Form.Get("filters")) + volumes, err := s.daemon.Volumes(ctx, r.Form.Get("filters")) if err != nil { return err } @@ -25,7 +25,7 @@ func (s *Server) getVolumeByName(ctx context.Context, w http.ResponseWriter, r * return err } - v, err := s.daemon.VolumeInspect(vars["name"]) + v, err := s.daemon.VolumeInspect(ctx, vars["name"]) if err != nil { return err } @@ -46,7 +46,7 @@ func (s *Server) postVolumesCreate(ctx context.Context, w http.ResponseWriter, r return err } - volume, err := s.daemon.VolumeCreate(req.Name, req.Driver, req.DriverOpts) + volume, err := s.daemon.VolumeCreate(ctx, req.Name, req.Driver, req.DriverOpts) if err != nil { return err } @@ -57,7 +57,7 @@ func (s *Server) deleteVolumes(ctx context.Context, w http.ResponseWriter, r *ht if err := parseForm(r); err != nil { return err } - if err := s.daemon.VolumeRm(vars["name"]); err != nil { + if err := s.daemon.VolumeRm(ctx, vars["name"]); err != nil { return err } w.WriteHeader(http.StatusNoContent) diff --git a/builder/dispatchers.go b/builder/dispatchers.go index a414212281..42ae01dd4c 100644 --- a/builder/dispatchers.go +++ b/builder/dispatchers.go @@ -18,6 +18,7 @@ import ( "strings" "github.com/Sirupsen/logrus" + "github.com/docker/docker/context" derr "github.com/docker/docker/errors" flag "github.com/docker/docker/pkg/mflag" "github.com/docker/docker/pkg/nat" @@ -43,7 +44,7 @@ func nullDispatch(b *builder, args []string, attributes map[string]bool, origina // Sets the environment variable foo to bar, also makes interpolation // in the dockerfile available from the next statement on via ${foo}. // -func env(b *builder, args []string, attributes map[string]bool, original string) error { +func env(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error { if len(args) == 0 { return derr.ErrorCodeAtLeastOneArg.WithArgs("ENV") } @@ -96,13 +97,13 @@ func env(b *builder, args []string, attributes map[string]bool, original string) j++ } - return b.commit("", b.Config.Cmd, commitStr) + return b.commit(ctx, "", b.Config.Cmd, commitStr) } // MAINTAINER some text // // Sets the maintainer metadata. -func maintainer(b *builder, args []string, attributes map[string]bool, original string) error { +func maintainer(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error { if len(args) != 1 { return derr.ErrorCodeExactlyOneArg.WithArgs("MAINTAINER") } @@ -112,14 +113,14 @@ func maintainer(b *builder, args []string, attributes map[string]bool, original } b.maintainer = args[0] - return b.commit("", b.Config.Cmd, fmt.Sprintf("MAINTAINER %s", b.maintainer)) + return b.commit(ctx, "", b.Config.Cmd, fmt.Sprintf("MAINTAINER %s", b.maintainer)) } // LABEL some json data describing the image // // Sets the Label variable foo to bar, // -func label(b *builder, args []string, attributes map[string]bool, original string) error { +func label(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error { if len(args) == 0 { return derr.ErrorCodeAtLeastOneArg.WithArgs("LABEL") } @@ -147,7 +148,7 @@ func label(b *builder, args []string, attributes map[string]bool, original strin b.Config.Labels[args[j]] = args[j+1] j++ } - return b.commit("", b.Config.Cmd, commitStr) + return b.commit(ctx, "", b.Config.Cmd, commitStr) } // ADD foo /path @@ -155,7 +156,7 @@ func label(b *builder, args []string, attributes map[string]bool, original strin // Add the file 'foo' to '/path'. Tarball and Remote URL (git, http) handling // exist here. If you do not wish to have this automatic handling, use COPY. // -func add(b *builder, args []string, attributes map[string]bool, original string) error { +func add(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error { if len(args) < 2 { return derr.ErrorCodeAtLeastTwoArgs.WithArgs("ADD") } @@ -164,14 +165,14 @@ func add(b *builder, args []string, attributes map[string]bool, original string) return err } - return b.runContextCommand(args, true, true, "ADD") + return b.runContextCommand(ctx, args, true, true, "ADD") } // COPY foo /path // // Same as 'ADD' but without the tar and remote url handling. // -func dispatchCopy(b *builder, args []string, attributes map[string]bool, original string) error { +func dispatchCopy(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error { if len(args) < 2 { return derr.ErrorCodeAtLeastTwoArgs.WithArgs("COPY") } @@ -180,14 +181,14 @@ func dispatchCopy(b *builder, args []string, attributes map[string]bool, origina return err } - return b.runContextCommand(args, false, false, "COPY") + return b.runContextCommand(ctx, args, false, false, "COPY") } // FROM imagename // // This sets the image the dockerfile will build on top of. // -func from(b *builder, args []string, attributes map[string]bool, original string) error { +func from(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error { if len(args) != 1 { return derr.ErrorCodeExactlyOneArg.WithArgs("FROM") } @@ -208,16 +209,16 @@ func from(b *builder, args []string, attributes map[string]bool, original string return nil } - image, err := b.Daemon.Repositories().LookupImage(name) + image, err := b.Daemon.Repositories(ctx).LookupImage(name) if b.Pull { - image, err = b.pullImage(name) + image, err = b.pullImage(ctx, name) if err != nil { return err } } if err != nil { - if b.Daemon.Graph().IsNotExist(err, name) { - image, err = b.pullImage(name) + if b.Daemon.Graph(ctx).IsNotExist(err, name) { + image, err = b.pullImage(ctx, name) } // note that the top level err will still be !nil here if IsNotExist is @@ -227,7 +228,7 @@ func from(b *builder, args []string, attributes map[string]bool, original string } } - return b.processImageFrom(image) + return b.processImageFrom(ctx, image) } // ONBUILD RUN echo yo @@ -239,7 +240,7 @@ func from(b *builder, args []string, attributes map[string]bool, original string // special cases. search for 'OnBuild' in internals.go for additional special // cases. // -func onbuild(b *builder, args []string, attributes map[string]bool, original string) error { +func onbuild(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error { if len(args) == 0 { return derr.ErrorCodeAtLeastOneArg.WithArgs("ONBUILD") } @@ -259,14 +260,14 @@ func onbuild(b *builder, args []string, attributes map[string]bool, original str original = regexp.MustCompile(`(?i)^\s*ONBUILD\s*`).ReplaceAllString(original, "") b.Config.OnBuild = append(b.Config.OnBuild, original) - return b.commit("", b.Config.Cmd, fmt.Sprintf("ONBUILD %s", original)) + return b.commit(ctx, "", b.Config.Cmd, fmt.Sprintf("ONBUILD %s", original)) } // WORKDIR /tmp // // Set the working directory for future RUN/CMD/etc statements. // -func workdir(b *builder, args []string, attributes map[string]bool, original string) error { +func workdir(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error { if len(args) != 1 { return derr.ErrorCodeExactlyOneArg.WithArgs("WORKDIR") } @@ -286,7 +287,7 @@ func workdir(b *builder, args []string, attributes map[string]bool, original str b.Config.WorkingDir = workdir - return b.commit("", b.Config.Cmd, fmt.Sprintf("WORKDIR %v", workdir)) + return b.commit(ctx, "", b.Config.Cmd, fmt.Sprintf("WORKDIR %v", workdir)) } // RUN some command yo @@ -299,7 +300,7 @@ func workdir(b *builder, args []string, attributes map[string]bool, original str // RUN echo hi # cmd /S /C echo hi (Windows) // RUN [ "echo", "hi" ] # echo hi // -func run(b *builder, args []string, attributes map[string]bool, original string) error { +func run(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error { if b.image == "" && !b.noBaseImage { return derr.ErrorCodeMissingFrom } @@ -380,7 +381,7 @@ func run(b *builder, args []string, attributes map[string]bool, original string) } b.Config.Cmd = saveCmd - hit, err := b.probeCache() + hit, err := b.probeCache(ctx) if err != nil { return err } @@ -395,17 +396,17 @@ func run(b *builder, args []string, attributes map[string]bool, original string) logrus.Debugf("[BUILDER] Command to be executed: %v", b.Config.Cmd) - c, err := b.create() + c, err := b.create(ctx) if err != nil { return err } // Ensure that we keep the container mounted until the commit // to avoid unmounting and then mounting directly again - c.Mount() - defer c.Unmount() + c.Mount(ctx) + defer c.Unmount(ctx) - err = b.run(c) + err = b.run(ctx, c) if err != nil { return err } @@ -415,7 +416,7 @@ func run(b *builder, args []string, attributes map[string]bool, original string) // properly match it. b.Config.Env = env b.Config.Cmd = saveCmd - if err := b.commit(c.ID, cmd, "run"); err != nil { + if err := b.commit(ctx, c.ID, cmd, "run"); err != nil { return err } @@ -427,7 +428,7 @@ func run(b *builder, args []string, attributes map[string]bool, original string) // Set the default command to run in the container (which may be empty). // Argument handling is the same as RUN. // -func cmd(b *builder, args []string, attributes map[string]bool, original string) error { +func cmd(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error { if err := b.BuilderFlags.Parse(); err != nil { return err } @@ -444,7 +445,7 @@ func cmd(b *builder, args []string, attributes map[string]bool, original string) b.Config.Cmd = stringutils.NewStrSlice(cmdSlice...) - if err := b.commit("", b.Config.Cmd, fmt.Sprintf("CMD %q", cmdSlice)); err != nil { + if err := b.commit(ctx, "", b.Config.Cmd, fmt.Sprintf("CMD %q", cmdSlice)); err != nil { return err } @@ -463,7 +464,7 @@ func cmd(b *builder, args []string, attributes map[string]bool, original string) // Handles command processing similar to CMD and RUN, only b.Config.Entrypoint // is initialized at NewBuilder time instead of through argument parsing. // -func entrypoint(b *builder, args []string, attributes map[string]bool, original string) error { +func entrypoint(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error { if err := b.BuilderFlags.Parse(); err != nil { return err } @@ -492,7 +493,7 @@ func entrypoint(b *builder, args []string, attributes map[string]bool, original b.Config.Cmd = nil } - if err := b.commit("", b.Config.Cmd, fmt.Sprintf("ENTRYPOINT %q", b.Config.Entrypoint)); err != nil { + if err := b.commit(ctx, "", b.Config.Cmd, fmt.Sprintf("ENTRYPOINT %q", b.Config.Entrypoint)); err != nil { return err } @@ -504,7 +505,7 @@ func entrypoint(b *builder, args []string, attributes map[string]bool, original // Expose ports for links and port mappings. This all ends up in // b.Config.ExposedPorts for runconfig. // -func expose(b *builder, args []string, attributes map[string]bool, original string) error { +func expose(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error { portsTab := args if len(args) == 0 { @@ -537,7 +538,7 @@ func expose(b *builder, args []string, attributes map[string]bool, original stri i++ } sort.Strings(portList) - return b.commit("", b.Config.Cmd, fmt.Sprintf("EXPOSE %s", strings.Join(portList, " "))) + return b.commit(ctx, "", b.Config.Cmd, fmt.Sprintf("EXPOSE %s", strings.Join(portList, " "))) } // USER foo @@ -545,7 +546,7 @@ func expose(b *builder, args []string, attributes map[string]bool, original stri // Set the user to 'foo' for future commands and when running the // ENTRYPOINT/CMD at container run time. // -func user(b *builder, args []string, attributes map[string]bool, original string) error { +func user(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error { if len(args) != 1 { return derr.ErrorCodeExactlyOneArg.WithArgs("USER") } @@ -555,14 +556,14 @@ func user(b *builder, args []string, attributes map[string]bool, original string } b.Config.User = args[0] - return b.commit("", b.Config.Cmd, fmt.Sprintf("USER %v", args)) + return b.commit(ctx, "", b.Config.Cmd, fmt.Sprintf("USER %v", args)) } // VOLUME /foo // // Expose the volume /foo for use. Will also accept the JSON array form. // -func volume(b *builder, args []string, attributes map[string]bool, original string) error { +func volume(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error { if len(args) == 0 { return derr.ErrorCodeAtLeastOneArg.WithArgs("VOLUME") } @@ -581,7 +582,7 @@ func volume(b *builder, args []string, attributes map[string]bool, original stri } b.Config.Volumes[v] = struct{}{} } - if err := b.commit("", b.Config.Cmd, fmt.Sprintf("VOLUME %v", args)); err != nil { + if err := b.commit(ctx, "", b.Config.Cmd, fmt.Sprintf("VOLUME %v", args)); err != nil { return err } return nil @@ -590,7 +591,7 @@ func volume(b *builder, args []string, attributes map[string]bool, original stri // STOPSIGNAL signal // // Set the signal that will be used to kill the container. -func stopSignal(b *builder, args []string, attributes map[string]bool, original string) error { +func stopSignal(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error { if len(args) != 1 { return fmt.Errorf("STOPSIGNAL requires exactly one argument") } @@ -602,7 +603,7 @@ func stopSignal(b *builder, args []string, attributes map[string]bool, original } b.Config.StopSignal = sig - return b.commit("", b.Config.Cmd, fmt.Sprintf("STOPSIGNAL %v", args)) + return b.commit(ctx, "", b.Config.Cmd, fmt.Sprintf("STOPSIGNAL %v", args)) } // ARG name[=value] @@ -610,7 +611,7 @@ func stopSignal(b *builder, args []string, attributes map[string]bool, original // Adds the variable foo to the trusted list of variables that can be passed // to builder using the --build-arg flag for expansion/subsitution or passing to 'run'. // Dockerfile author may optionally set a default value of this variable. -func arg(b *builder, args []string, attributes map[string]bool, original string) error { +func arg(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error { if len(args) != 1 { return fmt.Errorf("ARG requires exactly one argument definition") } @@ -646,5 +647,5 @@ func arg(b *builder, args []string, attributes map[string]bool, original string) b.buildArgs[name] = value } - return b.commit("", b.Config.Cmd, fmt.Sprintf("ARG %s", arg)) + return b.commit(ctx, "", b.Config.Cmd, fmt.Sprintf("ARG %s", arg)) } diff --git a/builder/evaluator.go b/builder/evaluator.go index b798ad2dba..8f487dae4a 100644 --- a/builder/evaluator.go +++ b/builder/evaluator.go @@ -32,6 +32,7 @@ import ( "github.com/docker/docker/builder/command" "github.com/docker/docker/builder/parser" "github.com/docker/docker/cliconfig" + "github.com/docker/docker/context" "github.com/docker/docker/daemon" "github.com/docker/docker/pkg/fileutils" "github.com/docker/docker/pkg/streamformatter" @@ -57,10 +58,10 @@ var replaceEnvAllowed = map[string]struct{}{ command.Arg: {}, } -var evaluateTable map[string]func(*builder, []string, map[string]bool, string) error +var evaluateTable map[string]func(context.Context, *builder, []string, map[string]bool, string) error func init() { - evaluateTable = map[string]func(*builder, []string, map[string]bool, string) error{ + evaluateTable = map[string]func(context.Context, *builder, []string, map[string]bool, string) error{ command.Env: env, command.Label: label, command.Maintainer: maintainer, @@ -158,7 +159,7 @@ type builder struct { // processing. // * Print a happy message and return the image ID. // -func (b *builder) Run(context io.Reader) (string, error) { +func (b *builder) Run(ctx context.Context, context io.Reader) (string, error) { if err := b.readContext(context); err != nil { return "", err } @@ -187,15 +188,15 @@ func (b *builder) Run(context io.Reader) (string, error) { default: // Not cancelled yet, keep going... } - if err := b.dispatch(i, n); err != nil { + if err := b.dispatch(ctx, i, n); err != nil { if b.ForceRemove { - b.clearTmp() + b.clearTmp(ctx) } return "", err } fmt.Fprintf(b.OutStream, " ---> %s\n", stringid.TruncateID(b.image)) if b.Remove { - b.clearTmp() + b.clearTmp(ctx) } } @@ -311,7 +312,7 @@ func (b *builder) isBuildArgAllowed(arg string) bool { // such as `RUN` in ONBUILD RUN foo. There is special case logic in here to // deal with that, at least until it becomes more of a general concern with new // features. -func (b *builder) dispatch(stepN int, ast *parser.Node) error { +func (b *builder) dispatch(ctx context.Context, stepN int, ast *parser.Node) error { cmd := ast.Value // To ensure the user is give a decent error message if the platform @@ -404,7 +405,7 @@ func (b *builder) dispatch(stepN int, ast *parser.Node) error { if f, ok := evaluateTable[cmd]; ok { b.BuilderFlags = NewBFlags() b.BuilderFlags.Args = flags - return f(b, strList, attrs, original) + return f(ctx, b, strList, attrs, original) } return fmt.Errorf("Unknown instruction: %s", strings.ToUpper(cmd)) diff --git a/builder/internals.go b/builder/internals.go index 5d8a448a42..ec0e955e57 100644 --- a/builder/internals.go +++ b/builder/internals.go @@ -22,6 +22,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/builder/parser" "github.com/docker/docker/cliconfig" + "github.com/docker/docker/context" "github.com/docker/docker/daemon" "github.com/docker/docker/graph" "github.com/docker/docker/image" @@ -75,7 +76,7 @@ func (b *builder) readContext(context io.Reader) (err error) { return } -func (b *builder) commit(id string, autoCmd *stringutils.StrSlice, comment string) error { +func (b *builder) commit(ctx context.Context, id string, autoCmd *stringutils.StrSlice, comment string) error { if b.disableCommit { return nil } @@ -92,7 +93,7 @@ func (b *builder) commit(id string, autoCmd *stringutils.StrSlice, comment strin } defer func(cmd *stringutils.StrSlice) { b.Config.Cmd = cmd }(cmd) - hit, err := b.probeCache() + hit, err := b.probeCache(ctx) if err != nil { return err } @@ -100,18 +101,18 @@ func (b *builder) commit(id string, autoCmd *stringutils.StrSlice, comment strin return nil } - container, err := b.create() + container, err := b.create(ctx) if err != nil { return err } id = container.ID - if err := container.Mount(); err != nil { + if err := container.Mount(ctx); err != nil { return err } - defer container.Unmount() + defer container.Unmount(ctx) } - container, err := b.Daemon.Get(id) + container, err := b.Daemon.Get(ctx, id) if err != nil { return err } @@ -127,11 +128,11 @@ func (b *builder) commit(id string, autoCmd *stringutils.StrSlice, comment strin } // Commit the container - image, err := b.Daemon.Commit(container, commitCfg) + image, err := b.Daemon.Commit(ctx, container, commitCfg) if err != nil { return err } - b.Daemon.Graph().Retain(b.id, image.ID) + b.Daemon.Graph(ctx).Retain(b.id, image.ID) b.activeImages = append(b.activeImages, image.ID) b.image = image.ID return nil @@ -145,7 +146,7 @@ type copyInfo struct { tmpDir string } -func (b *builder) runContextCommand(args []string, allowRemote bool, allowDecompression bool, cmdName string) error { +func (b *builder) runContextCommand(ctx context.Context, args []string, allowRemote bool, allowDecompression bool, cmdName string) error { if b.context == nil { return fmt.Errorf("No context given. Impossible to use %s", cmdName) } @@ -223,7 +224,7 @@ func (b *builder) runContextCommand(args []string, allowRemote bool, allowDecomp } defer func(cmd *stringutils.StrSlice) { b.Config.Cmd = cmd }(cmd) - hit, err := b.probeCache() + hit, err := b.probeCache(ctx) if err != nil { return err } @@ -232,16 +233,16 @@ func (b *builder) runContextCommand(args []string, allowRemote bool, allowDecomp return nil } - container, _, err := b.Daemon.ContainerCreate("", b.Config, nil, true) + container, _, err := b.Daemon.ContainerCreate(ctx, "", b.Config, nil, true) if err != nil { return err } b.TmpContainers[container.ID] = struct{}{} - if err := container.Mount(); err != nil { + if err := container.Mount(ctx); err != nil { return err } - defer container.Unmount() + defer container.Unmount(ctx) for _, ci := range copyInfos { if err := b.addContext(container, ci.origPath, ci.destPath, ci.decompress); err != nil { @@ -249,7 +250,7 @@ func (b *builder) runContextCommand(args []string, allowRemote bool, allowDecomp } } - if err := b.commit(container.ID, cmd, fmt.Sprintf("%s %s in %s", cmdName, origPaths, dest)); err != nil { + if err := b.commit(ctx, container.ID, cmd, fmt.Sprintf("%s %s in %s", cmdName, origPaths, dest)); err != nil { return err } return nil @@ -484,7 +485,7 @@ func containsWildcards(name string) bool { return false } -func (b *builder) pullImage(name string) (*image.Image, error) { +func (b *builder) pullImage(ctx context.Context, name string) (*image.Image, error) { remote, tag := parsers.ParseRepositoryTag(name) if tag == "" { tag = "latest" @@ -510,11 +511,11 @@ func (b *builder) pullImage(name string) (*image.Image, error) { OutStream: ioutils.NopWriteCloser(b.OutOld), } - if err := b.Daemon.Repositories().Pull(remote, tag, imagePullConfig); err != nil { + if err := b.Daemon.Repositories(ctx).Pull(ctx, remote, tag, imagePullConfig); err != nil { return nil, err } - image, err := b.Daemon.Repositories().LookupImage(name) + image, err := b.Daemon.Repositories(ctx).LookupImage(name) if err != nil { return nil, err } @@ -522,7 +523,7 @@ func (b *builder) pullImage(name string) (*image.Image, error) { return image, nil } -func (b *builder) processImageFrom(img *image.Image) error { +func (b *builder) processImageFrom(ctx context.Context, img *image.Image) error { b.image = img.ID if img.Config != nil { @@ -562,7 +563,7 @@ func (b *builder) processImageFrom(img *image.Image) error { return fmt.Errorf("%s isn't allowed as an ONBUILD trigger", n.Value) } - if err := b.dispatch(i, n); err != nil { + if err := b.dispatch(ctx, i, n); err != nil { return err } } @@ -576,12 +577,12 @@ func (b *builder) processImageFrom(img *image.Image) error { // in the current server `b.Daemon`. If an image is found, probeCache returns // `(true, nil)`. If no image is found, it returns `(false, nil)`. If there // is any error, it returns `(false, err)`. -func (b *builder) probeCache() (bool, error) { +func (b *builder) probeCache(ctx context.Context) (bool, error) { if !b.UtilizeCache || b.cacheBusted { return false, nil } - cache, err := b.Daemon.ImageGetCached(b.image, b.Config) + cache, err := b.Daemon.ImageGetCached(ctx, b.image, b.Config) if err != nil { return false, err } @@ -594,12 +595,12 @@ func (b *builder) probeCache() (bool, error) { fmt.Fprintf(b.OutStream, " ---> Using cache\n") logrus.Debugf("[BUILDER] Use cached version") b.image = cache.ID - b.Daemon.Graph().Retain(b.id, cache.ID) + b.Daemon.Graph(ctx).Retain(b.id, cache.ID) b.activeImages = append(b.activeImages, cache.ID) return true, nil } -func (b *builder) create() (*daemon.Container, error) { +func (b *builder) create(ctx context.Context) (*daemon.Container, error) { if b.image == "" && !b.noBaseImage { return nil, fmt.Errorf("Please provide a source image with `from` prior to run") } @@ -620,7 +621,7 @@ func (b *builder) create() (*daemon.Container, error) { config := *b.Config // Create the container - c, warnings, err := b.Daemon.ContainerCreate("", b.Config, hostConfig, true) + c, warnings, err := b.Daemon.ContainerCreate(ctx, "", b.Config, hostConfig, true) if err != nil { return nil, err } @@ -643,14 +644,14 @@ func (b *builder) create() (*daemon.Container, error) { return c, nil } -func (b *builder) run(c *daemon.Container) error { +func (b *builder) run(ctx context.Context, c *daemon.Container) error { var errCh chan error if b.Verbose { errCh = c.Attach(nil, b.OutStream, b.ErrStream) } //start the container - if err := c.Start(); err != nil { + if err := c.Start(ctx); err != nil { return err } @@ -660,7 +661,7 @@ func (b *builder) run(c *daemon.Container) error { select { case <-b.cancelled: logrus.Debugln("Build cancelled, killing container:", c.ID) - c.Kill() + c.Kill(ctx) case <-finished: } }() @@ -791,13 +792,13 @@ func copyAsDirectory(source, destination string, destExisted bool) error { return fixPermissions(source, destination, 0, 0, destExisted) } -func (b *builder) clearTmp() { +func (b *builder) clearTmp(ctx context.Context) { for c := range b.TmpContainers { rmConfig := &daemon.ContainerRmConfig{ ForceRemove: true, RemoveVolume: true, } - if err := b.Daemon.ContainerRm(c, rmConfig); err != nil { + if err := b.Daemon.ContainerRm(ctx, c, rmConfig); err != nil { fmt.Fprintf(b.OutStream, "Error removing intermediate container %s: %v\n", stringid.TruncateID(c), err) return } diff --git a/builder/job.go b/builder/job.go index de62666608..8baeb7c1c8 100644 --- a/builder/job.go +++ b/builder/job.go @@ -14,6 +14,7 @@ import ( "github.com/docker/docker/api" "github.com/docker/docker/builder/parser" "github.com/docker/docker/cliconfig" + "github.com/docker/docker/context" "github.com/docker/docker/daemon" "github.com/docker/docker/graph/tags" "github.com/docker/docker/pkg/archive" @@ -112,7 +113,7 @@ func NewBuildConfig() *Config { // Build is the main interface of the package, it gathers the Builder // struct and calls builder.Run() to do all the real build job. -func Build(d *daemon.Daemon, buildConfig *Config) error { +func Build(ctx context.Context, d *daemon.Daemon, buildConfig *Config) error { var ( repoName string tag string @@ -229,15 +230,15 @@ func Build(d *daemon.Daemon, buildConfig *Config) error { } defer func() { - builder.Daemon.Graph().Release(builder.id, builder.activeImages...) + builder.Daemon.Graph(ctx).Release(builder.id, builder.activeImages...) }() - id, err := builder.Run(context) + id, err := builder.Run(ctx, context) if err != nil { return err } if repoName != "" { - return d.Repositories().Tag(repoName, tag, id, true) + return d.Repositories(ctx).Tag(repoName, tag, id, true) } return nil } @@ -247,7 +248,7 @@ func Build(d *daemon.Daemon, buildConfig *Config) error { // // - call parse.Parse() to get AST root from Dockerfile entries // - do build by calling builder.dispatch() to call all entries' handling routines -func BuildFromConfig(d *daemon.Daemon, c *runconfig.Config, changes []string) (*runconfig.Config, error) { +func BuildFromConfig(ctx context.Context, d *daemon.Daemon, c *runconfig.Config, changes []string) (*runconfig.Config, error) { ast, err := parser.Parse(bytes.NewBufferString(strings.Join(changes, "\n"))) if err != nil { return nil, err @@ -269,7 +270,7 @@ func BuildFromConfig(d *daemon.Daemon, c *runconfig.Config, changes []string) (* } for i, n := range ast.Children { - if err := builder.dispatch(i, n); err != nil { + if err := builder.dispatch(ctx, i, n); err != nil { return nil, err } } @@ -289,8 +290,8 @@ type CommitConfig struct { } // Commit will create a new image from a container's changes -func Commit(name string, d *daemon.Daemon, c *CommitConfig) (string, error) { - container, err := d.Get(name) +func Commit(ctx context.Context, name string, d *daemon.Daemon, c *CommitConfig) (string, error) { + container, err := d.Get(ctx, name) if err != nil { return "", err } @@ -304,7 +305,7 @@ func Commit(name string, d *daemon.Daemon, c *CommitConfig) (string, error) { c.Config = &runconfig.Config{} } - newConfig, err := BuildFromConfig(d, c.Config, c.Changes) + newConfig, err := BuildFromConfig(ctx, d, c.Config, c.Changes) if err != nil { return "", err } @@ -322,7 +323,7 @@ func Commit(name string, d *daemon.Daemon, c *CommitConfig) (string, error) { Config: newConfig, } - img, err := d.Commit(container, commitCfg) + img, err := d.Commit(ctx, container, commitCfg) if err != nil { return "", err } diff --git a/daemon/archive.go b/daemon/archive.go index a5db99e211..fa1378989b 100644 --- a/daemon/archive.go +++ b/daemon/archive.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/docker/docker/api/types" + "github.com/docker/docker/context" "github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/chrootarchive" "github.com/docker/docker/pkg/ioutils" @@ -20,8 +21,8 @@ var ErrExtractPointNotDirectory = errors.New("extraction point is not a director // ContainerCopy performs a deprecated operation of archiving the resource at // the specified path in the conatiner identified by the given name. -func (daemon *Daemon) ContainerCopy(name string, res string) (io.ReadCloser, error) { - container, err := daemon.Get(name) +func (daemon *Daemon) ContainerCopy(ctx context.Context, name string, res string) (io.ReadCloser, error) { + container, err := daemon.Get(ctx, name) if err != nil { return nil, err } @@ -30,30 +31,30 @@ func (daemon *Daemon) ContainerCopy(name string, res string) (io.ReadCloser, err res = res[1:] } - return container.copy(res) + return container.copy(ctx, res) } // ContainerStatPath stats the filesystem resource at the specified path in the // container identified by the given name. -func (daemon *Daemon) ContainerStatPath(name string, path string) (stat *types.ContainerPathStat, err error) { - container, err := daemon.Get(name) +func (daemon *Daemon) ContainerStatPath(ctx context.Context, name string, path string) (stat *types.ContainerPathStat, err error) { + container, err := daemon.Get(ctx, name) if err != nil { return nil, err } - return container.StatPath(path) + return container.StatPath(ctx, path) } // ContainerArchivePath creates an archive of the filesystem resource at the // specified path in the container identified by the given name. Returns a // tar archive of the resource and whether it was a directory or a single file. -func (daemon *Daemon) ContainerArchivePath(name string, path string) (content io.ReadCloser, stat *types.ContainerPathStat, err error) { - container, err := daemon.Get(name) +func (daemon *Daemon) ContainerArchivePath(ctx context.Context, name string, path string) (content io.ReadCloser, stat *types.ContainerPathStat, err error) { + container, err := daemon.Get(ctx, name) if err != nil { return nil, nil, err } - return container.ArchivePath(path) + return container.ArchivePath(ctx, path) } // ContainerExtractToDir extracts the given archive to the specified location @@ -62,13 +63,13 @@ func (daemon *Daemon) ContainerArchivePath(name string, path string) (content io // be ErrExtractPointNotDirectory. If noOverwriteDirNonDir is true then it will // be an error if unpacking the given content would cause an existing directory // to be replaced with a non-directory and vice versa. -func (daemon *Daemon) ContainerExtractToDir(name, path string, noOverwriteDirNonDir bool, content io.Reader) error { - container, err := daemon.Get(name) +func (daemon *Daemon) ContainerExtractToDir(ctx context.Context, name, path string, noOverwriteDirNonDir bool, content io.Reader) error { + container, err := daemon.Get(ctx, name) if err != nil { return err } - return container.ExtractToDir(path, noOverwriteDirNonDir, content) + return container.ExtractToDir(ctx, path, noOverwriteDirNonDir, content) } // resolvePath resolves the given path in the container to a resource on the @@ -133,14 +134,14 @@ func (container *Container) statPath(resolvedPath, absPath string) (stat *types. // StatPath stats the filesystem resource at the specified path in this // container. Returns stat info about the resource. -func (container *Container) StatPath(path string) (stat *types.ContainerPathStat, err error) { +func (container *Container) StatPath(ctx context.Context, path string) (stat *types.ContainerPathStat, err error) { container.Lock() defer container.Unlock() - if err = container.Mount(); err != nil { + if err = container.Mount(ctx); err != nil { return nil, err } - defer container.Unmount() + defer container.Unmount(ctx) err = container.mountVolumes() defer container.unmountVolumes(true) @@ -159,7 +160,7 @@ func (container *Container) StatPath(path string) (stat *types.ContainerPathStat // ArchivePath creates an archive of the filesystem resource at the specified // path in this container. Returns a tar archive of the resource and stat info // about the resource. -func (container *Container) ArchivePath(path string) (content io.ReadCloser, stat *types.ContainerPathStat, err error) { +func (container *Container) ArchivePath(ctx context.Context, path string) (content io.ReadCloser, stat *types.ContainerPathStat, err error) { container.Lock() defer func() { @@ -171,7 +172,7 @@ func (container *Container) ArchivePath(path string) (content io.ReadCloser, sta } }() - if err = container.Mount(); err != nil { + if err = container.Mount(ctx); err != nil { return nil, nil, err } @@ -180,7 +181,7 @@ func (container *Container) ArchivePath(path string) (content io.ReadCloser, sta // unmount any volumes container.unmountVolumes(true) // unmount the container's rootfs - container.Unmount() + container.Unmount(ctx) } }() @@ -214,12 +215,12 @@ func (container *Container) ArchivePath(path string) (content io.ReadCloser, sta content = ioutils.NewReadCloserWrapper(data, func() error { err := data.Close() container.unmountVolumes(true) - container.Unmount() + container.Unmount(ctx) container.Unlock() return err }) - container.logEvent("archive-path") + container.logEvent(ctx, "archive-path") return content, stat, nil } @@ -230,14 +231,14 @@ func (container *Container) ArchivePath(path string) (content io.ReadCloser, sta // noOverwriteDirNonDir is true then it will be an error if unpacking the // given content would cause an existing directory to be replaced with a non- // directory and vice versa. -func (container *Container) ExtractToDir(path string, noOverwriteDirNonDir bool, content io.Reader) (err error) { +func (container *Container) ExtractToDir(ctx context.Context, path string, noOverwriteDirNonDir bool, content io.Reader) (err error) { container.Lock() defer container.Unlock() - if err = container.Mount(); err != nil { + if err = container.Mount(ctx); err != nil { return err } - defer container.Unmount() + defer container.Unmount(ctx) err = container.mountVolumes() defer container.unmountVolumes(true) @@ -318,7 +319,7 @@ func (container *Container) ExtractToDir(path string, noOverwriteDirNonDir bool, return err } - container.logEvent("extract-to-dir") + container.logEvent(ctx, "extract-to-dir") return nil } diff --git a/daemon/attach.go b/daemon/attach.go index 3ffc6d6be1..e67e1aaf14 100644 --- a/daemon/attach.go +++ b/daemon/attach.go @@ -3,6 +3,7 @@ package daemon import ( "io" + "github.com/docker/docker/context" "github.com/docker/docker/pkg/stdcopy" ) @@ -15,8 +16,8 @@ type ContainerAttachWithLogsConfig struct { } // ContainerAttachWithLogs attaches to logs according to the config passed in. See ContainerAttachWithLogsConfig. -func (daemon *Daemon) ContainerAttachWithLogs(prefixOrName string, c *ContainerAttachWithLogsConfig) error { - container, err := daemon.Get(prefixOrName) +func (daemon *Daemon) ContainerAttachWithLogs(ctx context.Context, prefixOrName string, c *ContainerAttachWithLogsConfig) error { + container, err := daemon.Get(ctx, prefixOrName) if err != nil { return err } @@ -43,7 +44,7 @@ func (daemon *Daemon) ContainerAttachWithLogs(prefixOrName string, c *ContainerA stderr = errStream } - return container.attachWithLogs(stdin, stdout, stderr, c.Logs, c.Stream) + return container.attachWithLogs(ctx, stdin, stdout, stderr, c.Logs, c.Stream) } // ContainerWsAttachWithLogsConfig attach with websockets, since all @@ -55,10 +56,10 @@ type ContainerWsAttachWithLogsConfig struct { } // ContainerWsAttachWithLogs websocket connection -func (daemon *Daemon) ContainerWsAttachWithLogs(prefixOrName string, c *ContainerWsAttachWithLogsConfig) error { - container, err := daemon.Get(prefixOrName) +func (daemon *Daemon) ContainerWsAttachWithLogs(ctx context.Context, prefixOrName string, c *ContainerWsAttachWithLogsConfig) error { + container, err := daemon.Get(ctx, prefixOrName) if err != nil { return err } - return container.attachWithLogs(c.InStream, c.OutStream, c.ErrStream, c.Logs, c.Stream) + return container.attachWithLogs(ctx, c.InStream, c.OutStream, c.ErrStream, c.Logs, c.Stream) } diff --git a/daemon/changes.go b/daemon/changes.go index 0748fa9c02..5efb819535 100644 --- a/daemon/changes.go +++ b/daemon/changes.go @@ -1,10 +1,13 @@ package daemon -import "github.com/docker/docker/pkg/archive" +import ( + "github.com/docker/docker/context" + "github.com/docker/docker/pkg/archive" +) // ContainerChanges returns a list of container fs changes -func (daemon *Daemon) ContainerChanges(name string) ([]archive.Change, error) { - container, err := daemon.Get(name) +func (daemon *Daemon) ContainerChanges(ctx context.Context, name string) ([]archive.Change, error) { + container, err := daemon.Get(ctx, name) if err != nil { return nil, err } diff --git a/daemon/commit.go b/daemon/commit.go index 62c9a458f4..0cbd16885f 100644 --- a/daemon/commit.go +++ b/daemon/commit.go @@ -1,6 +1,7 @@ package daemon import ( + "github.com/docker/docker/context" "github.com/docker/docker/image" "github.com/docker/docker/runconfig" ) @@ -18,10 +19,10 @@ type ContainerCommitConfig struct { // Commit creates a new filesystem image from the current state of a container. // The image can optionally be tagged into a repository. -func (daemon *Daemon) Commit(container *Container, c *ContainerCommitConfig) (*image.Image, error) { +func (daemon *Daemon) Commit(ctx context.Context, container *Container, c *ContainerCommitConfig) (*image.Image, error) { if c.Pause && !container.isPaused() { - container.pause() - defer container.unpause() + container.pause(ctx) + defer container.unpause(ctx) } rwTar, err := container.exportContainerRw() @@ -46,6 +47,6 @@ func (daemon *Daemon) Commit(container *Container, c *ContainerCommitConfig) (*i return img, err } } - container.logEvent("commit") + container.logEvent(ctx, "commit") return img, nil } diff --git a/daemon/container.go b/daemon/container.go index d3e0763c68..3ae768ef15 100644 --- a/daemon/container.go +++ b/daemon/container.go @@ -15,6 +15,7 @@ import ( "github.com/opencontainers/runc/libcontainer/label" "github.com/Sirupsen/logrus" + "github.com/docker/docker/context" "github.com/docker/docker/daemon/execdriver" "github.com/docker/docker/daemon/logger" "github.com/docker/docker/daemon/logger/jsonfilelog" @@ -170,9 +171,10 @@ func (container *Container) writeHostConfig() error { return ioutil.WriteFile(pth, data, 0666) } -func (container *Container) logEvent(action string) { +func (container *Container) logEvent(ctx context.Context, action string) { d := container.daemon d.EventsService.Log( + ctx, action, container.ID, container.Config.Image, @@ -238,7 +240,7 @@ func (container *Container) exportContainerRw() (archive.Archive, error) { // 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 (container *Container) Start() (err error) { +func (container *Container) Start(ctx context.Context) (err error) { container.Lock() defer container.Unlock() @@ -260,12 +262,12 @@ func (container *Container) Start() (err error) { container.ExitCode = 128 } container.toDisk() - container.cleanup() - container.logEvent("die") + container.cleanup(ctx) + container.logEvent(ctx, "die") } }() - if err := container.Mount(); err != nil { + if err := container.Mount(ctx); err != nil { return err } @@ -273,10 +275,10 @@ func (container *Container) Start() (err error) { // backwards API compatibility. container.hostConfig = runconfig.SetDefaultNetModeIfBlank(container.hostConfig) - if err := container.initializeNetworking(); err != nil { + if err := container.initializeNetworking(ctx); err != nil { return err } - linkedEnv, err := container.setupLinkedContainers() + linkedEnv, err := container.setupLinkedContainers(ctx) if err != nil { return err } @@ -284,7 +286,7 @@ func (container *Container) Start() (err error) { return err } env := container.createDaemonEnvironment(linkedEnv) - if err := populateCommand(container, env); err != nil { + if err := populateCommand(ctx, container, env); err != nil { return err } @@ -301,7 +303,7 @@ func (container *Container) Start() (err error) { mounts = append(mounts, container.ipcMounts()...) container.command.Mounts = mounts - return container.waitForStart() + return container.waitForStart(ctx) } // streamConfig.StdinPipe returns a WriteCloser which can be used to feed data @@ -334,14 +336,14 @@ func (container *Container) isNetworkAllocated() bool { // cleanup releases any network resources allocated to the container along with any rules // around how containers are linked together. It also unmounts the container's root filesystem. -func (container *Container) cleanup() { +func (container *Container) cleanup(ctx context.Context) { container.releaseNetwork() if err := container.unmountIpcMounts(); err != nil { logrus.Errorf("%s: Failed to umount ipc filesystems: %v", container.ID, err) } - if err := container.Unmount(); err != nil { + if err := container.Unmount(ctx); err != nil { logrus.Errorf("%s: Failed to umount filesystem: %v", container.ID, err) } @@ -357,7 +359,7 @@ func (container *Container) cleanup() { // to send the signal. An error is returned if the container is paused // or not running, or if there is a problem returned from the // underlying kill command. -func (container *Container) killSig(sig int) error { +func (container *Container) killSig(ctx context.Context, sig int) error { logrus.Debugf("Sending %d to %s", sig, container.ID) container.Lock() defer container.Unlock() @@ -385,13 +387,13 @@ func (container *Container) killSig(sig int) error { if err := container.daemon.kill(container, sig); err != nil { return err } - container.logEvent("kill") + container.logEvent(ctx, "kill") return nil } // Wrapper aroung killSig() suppressing "no such process" error. -func (container *Container) killPossiblyDeadProcess(sig int) error { - err := container.killSig(sig) +func (container *Container) killPossiblyDeadProcess(ctx context.Context, sig int) error { + err := container.killSig(ctx, sig) if err == syscall.ESRCH { logrus.Debugf("Cannot kill process (pid=%d) with signal %d: no such process.", container.getPID(), sig) return nil @@ -399,7 +401,7 @@ func (container *Container) killPossiblyDeadProcess(sig int) error { return err } -func (container *Container) pause() error { +func (container *Container) pause(ctx context.Context) error { container.Lock() defer container.Unlock() @@ -417,11 +419,11 @@ func (container *Container) pause() error { return err } container.Paused = true - container.logEvent("pause") + container.logEvent(ctx, "pause") return nil } -func (container *Container) unpause() error { +func (container *Container) unpause(ctx context.Context) error { container.Lock() defer container.Unlock() @@ -439,18 +441,18 @@ func (container *Container) unpause() error { return err } container.Paused = false - container.logEvent("unpause") + container.logEvent(ctx, "unpause") return nil } // Kill forcefully terminates a container. -func (container *Container) Kill() error { +func (container *Container) Kill(ctx context.Context) error { if !container.IsRunning() { return derr.ErrorCodeNotRunning.WithArgs(container.ID) } // 1. Send SIGKILL - if err := container.killPossiblyDeadProcess(int(syscall.SIGKILL)); err != nil { + if err := container.killPossiblyDeadProcess(ctx, int(syscall.SIGKILL)); err != nil { // While normally we might "return err" here we're not going to // because if we can't stop the container by this point then // its probably because its already stopped. Meaning, between @@ -484,15 +486,15 @@ func (container *Container) Kill() error { // process to exit. If a negative duration is given, Stop will wait // for the initial signal forever. If the container is not running Stop returns // immediately. -func (container *Container) Stop(seconds int) error { +func (container *Container) Stop(ctx context.Context, seconds int) error { if !container.IsRunning() { return nil } // 1. Send a SIGTERM - if err := container.killPossiblyDeadProcess(container.stopSignal()); err != nil { + if err := container.killPossiblyDeadProcess(ctx, container.stopSignal()); err != nil { logrus.Infof("Failed to send SIGTERM to the process, force killing") - if err := container.killPossiblyDeadProcess(9); err != nil { + if err := container.killPossiblyDeadProcess(ctx, 9); err != nil { return err } } @@ -501,13 +503,13 @@ func (container *Container) Stop(seconds int) error { if _, err := container.WaitStop(time.Duration(seconds) * time.Second); err != nil { logrus.Infof("Container %v failed to exit within %d seconds of SIGTERM - using the force", container.ID, seconds) // 3. If it doesn't, then send SIGKILL - if err := container.Kill(); err != nil { + if err := container.Kill(ctx); err != nil { container.WaitStop(-1 * time.Second) return err } } - container.logEvent("stop") + container.logEvent(ctx, "stop") return nil } @@ -515,61 +517,61 @@ func (container *Container) Stop(seconds int) error { // container. When stopping, wait for the given duration in seconds to // gracefully stop, before forcefully terminating the container. If // given a negative duration, wait forever for a graceful stop. -func (container *Container) Restart(seconds int) error { +func (container *Container) Restart(ctx context.Context, seconds int) error { // Avoid unnecessarily unmounting and then directly mounting // the container when the container stops and then starts // again - if err := container.Mount(); err == nil { - defer container.Unmount() + if err := container.Mount(ctx); err == nil { + defer container.Unmount(ctx) } - if err := container.Stop(seconds); err != nil { + if err := container.Stop(ctx, seconds); err != nil { return err } - if err := container.Start(); err != nil { + if err := container.Start(ctx); err != nil { return err } - container.logEvent("restart") + container.logEvent(ctx, "restart") return nil } // Resize changes the TTY of the process running inside the container // to the given height and width. The container must be running. -func (container *Container) Resize(h, w int) error { +func (container *Container) Resize(ctx context.Context, h, w int) error { if !container.IsRunning() { return derr.ErrorCodeNotRunning.WithArgs(container.ID) } if err := container.command.ProcessConfig.Terminal.Resize(h, w); err != nil { return err } - container.logEvent("resize") + container.logEvent(ctx, "resize") return nil } -func (container *Container) export() (archive.Archive, error) { - if err := container.Mount(); err != nil { +func (container *Container) export(ctx context.Context) (archive.Archive, error) { + if err := container.Mount(ctx); err != nil { return nil, err } archive, err := archive.Tar(container.basefs, archive.Uncompressed) if err != nil { - container.Unmount() + container.Unmount(ctx) return nil, err } arch := ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() - container.Unmount() + container.Unmount(ctx) return err }) - container.logEvent("export") + container.logEvent(ctx, "export") return arch, err } // Mount sets container.basefs -func (container *Container) Mount() error { - return container.daemon.Mount(container) +func (container *Container) Mount(ctx context.Context) error { + return container.daemon.Mount(ctx, container) } func (container *Container) changes() ([]archive.Change, error) { @@ -578,7 +580,7 @@ func (container *Container) changes() ([]archive.Change, error) { return container.daemon.changes(container) } -func (container *Container) getImage() (*image.Image, error) { +func (container *Container) getImage(ctx context.Context) (*image.Image, error) { if container.daemon == nil { return nil, derr.ErrorCodeImageUnregContainer } @@ -587,7 +589,7 @@ func (container *Container) getImage() (*image.Image, error) { // Unmount asks the daemon to release the layered filesystems that are // mounted by the container. -func (container *Container) Unmount() error { +func (container *Container) Unmount(ctx context.Context) error { return container.daemon.unmount(container) } @@ -612,7 +614,7 @@ func validateID(id string) error { return nil } -func (container *Container) copy(resource string) (rc io.ReadCloser, err error) { +func (container *Container) copy(ctx context.Context, resource string) (rc io.ReadCloser, err error) { container.Lock() defer func() { @@ -624,7 +626,7 @@ func (container *Container) copy(resource string) (rc io.ReadCloser, err error) } }() - if err := container.Mount(); err != nil { + if err := container.Mount(ctx); err != nil { return nil, err } @@ -633,7 +635,7 @@ func (container *Container) copy(resource string) (rc io.ReadCloser, err error) // unmount any volumes container.unmountVolumes(true) // unmount the container's rootfs - container.Unmount() + container.Unmount(ctx) } }() @@ -669,11 +671,11 @@ func (container *Container) copy(resource string) (rc io.ReadCloser, err error) reader := ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() container.unmountVolumes(true) - container.Unmount() + container.Unmount(ctx) container.Unlock() return err }) - container.logEvent("copy") + container.logEvent(ctx, "copy") return reader, nil } @@ -752,14 +754,14 @@ func (container *Container) startLogging() error { return nil } -func (container *Container) waitForStart() error { +func (container *Container) waitForStart(ctx context.Context) error { container.monitor = newContainerMonitor(container, container.hostConfig.RestartPolicy) // block until we either receive an error from the initial start of the container's // process or until the process is running in the container select { case <-container.monitor.startSignal: - case err := <-promise.Go(container.monitor.Start): + case err := <-promise.Go(func() error { return container.monitor.Start(ctx) }): return err } @@ -790,11 +792,11 @@ func (container *Container) getExecIDs() []string { return container.execCommands.List() } -func (container *Container) exec(ExecConfig *ExecConfig) error { +func (container *Container) exec(ctx context.Context, ExecConfig *ExecConfig) error { container.Lock() defer container.Unlock() - callback := func(processConfig *execdriver.ProcessConfig, pid int, chOOM <-chan struct{}) error { + callback := func(ctx context.Context, processConfig *execdriver.ProcessConfig, pid int, chOOM <-chan struct{}) error { if processConfig.Tty { // The callback is called after the process Start() // so we are in the parent process. In TTY mode, stdin/out/err is the PtySlave @@ -809,7 +811,7 @@ func (container *Container) exec(ExecConfig *ExecConfig) error { // We use a callback here instead of a goroutine and an chan for // synchronization purposes - cErr := promise.Go(func() error { return container.monitorExec(ExecConfig, callback) }) + cErr := promise.Go(func() error { return container.monitorExec(ctx, ExecConfig, callback) }) // Exec should not return until the process is actually running select { @@ -821,13 +823,13 @@ func (container *Container) exec(ExecConfig *ExecConfig) error { return nil } -func (container *Container) monitorExec(ExecConfig *ExecConfig, callback execdriver.DriverCallback) error { +func (container *Container) monitorExec(ctx context.Context, ExecConfig *ExecConfig, callback execdriver.DriverCallback) error { var ( err error exitCode int ) pipes := execdriver.NewPipes(ExecConfig.streamConfig.stdin, ExecConfig.streamConfig.stdout, ExecConfig.streamConfig.stderr, ExecConfig.OpenStdin) - exitCode, err = container.daemon.Exec(container, ExecConfig, pipes, callback) + exitCode, err = container.daemon.Exec(ctx, container, ExecConfig, pipes, callback) if err != nil { logrus.Errorf("Error running command in existing container %s: %s", container.ID, err) } @@ -860,7 +862,7 @@ func (container *Container) Attach(stdin io.ReadCloser, stdout io.Writer, stderr return attach(&container.streamConfig, container.Config.OpenStdin, container.Config.StdinOnce, container.Config.Tty, stdin, stdout, stderr) } -func (container *Container) attachWithLogs(stdin io.ReadCloser, stdout, stderr io.Writer, logs, stream bool) error { +func (container *Container) attachWithLogs(ctx context.Context, stdin io.ReadCloser, stdout, stderr io.Writer, logs, stream bool) error { if logs { logDriver, err := container.getLogger() if err != nil { @@ -892,7 +894,7 @@ func (container *Container) attachWithLogs(stdin io.ReadCloser, stdout, stderr i } } - container.logEvent("attach") + container.logEvent(ctx, "attach") //stream if stream { diff --git a/daemon/container_unix.go b/daemon/container_unix.go index a3fab427de..dafdf60481 100644 --- a/daemon/container_unix.go +++ b/daemon/container_unix.go @@ -15,6 +15,7 @@ import ( "time" "github.com/Sirupsen/logrus" + "github.com/docker/docker/context" "github.com/docker/docker/daemon/execdriver" "github.com/docker/docker/daemon/links" "github.com/docker/docker/daemon/network" @@ -77,12 +78,12 @@ func killProcessDirectly(container *Container) error { return nil } -func (container *Container) setupLinkedContainers() ([]string, error) { +func (container *Container) setupLinkedContainers(ctx context.Context) ([]string, error) { var ( env []string daemon = container.daemon ) - children, err := daemon.children(container.Name) + children, err := daemon.children(ctx, container.Name) if err != nil { return nil, err } @@ -175,7 +176,7 @@ func getDevicesFromPath(deviceMapping runconfig.DeviceMapping) (devs []*configs. return devs, derr.ErrorCodeDeviceInfo.WithArgs(deviceMapping.PathOnHost, err) } -func populateCommand(c *Container, env []string) error { +func populateCommand(ctx context.Context, c *Container, env []string) error { var en *execdriver.Network if !c.Config.NetworkDisabled { en = &execdriver.Network{} @@ -185,7 +186,7 @@ func populateCommand(c *Container, env []string) error { parts := strings.SplitN(string(c.hostConfig.NetworkMode), ":", 2) if parts[0] == "container" { - nc, err := c.getNetworkedContainer() + nc, err := c.getNetworkedContainer(ctx) if err != nil { return err } @@ -206,7 +207,7 @@ func populateCommand(c *Container, env []string) error { } if c.hostConfig.IpcMode.IsContainer() { - ic, err := c.getIpcContainer() + ic, err := c.getIpcContainer(ctx) if err != nil { return err } @@ -348,18 +349,18 @@ func mergeDevices(defaultDevices, userDevices []*configs.Device) []*configs.Devi } // GetSize returns the real size & virtual size of the container. -func (container *Container) getSize() (int64, int64) { +func (container *Container) getSize(ctx context.Context) (int64, int64) { var ( sizeRw, sizeRootfs int64 err error driver = container.daemon.driver ) - if err := container.Mount(); err != nil { + if err := container.Mount(ctx); err != nil { logrus.Errorf("Failed to compute size of container rootfs %s: %s", container.ID, err) return sizeRw, sizeRootfs } - defer container.Unmount() + defer container.Unmount(ctx) initID := fmt.Sprintf("%s-init", container.ID) sizeRw, err = driver.DiffSize(container.ID, initID) @@ -411,7 +412,7 @@ func (container *Container) buildHostnameFile() error { return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644) } -func (container *Container) buildSandboxOptions() ([]libnetwork.SandboxOption, error) { +func (container *Container) buildSandboxOptions(ctx context.Context) ([]libnetwork.SandboxOption, error) { var ( sboxOptions []libnetwork.SandboxOption err error @@ -488,7 +489,7 @@ func (container *Container) buildSandboxOptions() ([]libnetwork.SandboxOption, e var childEndpoints, parentEndpoints []string - children, err := container.daemon.children(container.Name) + children, err := container.daemon.children(ctx, container.Name) if err != nil { return nil, err } @@ -519,7 +520,7 @@ func (container *Container) buildSandboxOptions() ([]libnetwork.SandboxOption, e continue } - c, err := container.daemon.Get(ref.ParentID) + c, err := container.daemon.Get(ctx, ref.ParentID) if err != nil { logrus.Error(err) } @@ -678,7 +679,7 @@ func (container *Container) updateSandboxNetworkSettings(sb libnetwork.Sandbox) // UpdateNetwork is used to update the container's network (e.g. when linked containers // get removed/unlinked). -func (container *Container) updateNetwork() error { +func (container *Container) updateNetwork(ctx context.Context) error { ctrl := container.daemon.netController sid := container.NetworkSettings.SandboxID @@ -687,7 +688,7 @@ func (container *Container) updateNetwork() error { return derr.ErrorCodeNoSandbox.WithArgs(sid, err) } - options, err := container.buildSandboxOptions() + options, err := container.buildSandboxOptions(ctx) if err != nil { return derr.ErrorCodeNetworkUpdate.WithArgs(err) } @@ -811,7 +812,7 @@ func createNetwork(controller libnetwork.NetworkController, dnet string, driver return controller.NewNetwork(driver, dnet, createOptions...) } -func (container *Container) secondaryNetworkRequired(primaryNetworkType string) bool { +func (container *Container) secondaryNetworkRequired(ctx context.Context, primaryNetworkType string) bool { switch primaryNetworkType { case "bridge", "none", "host", "container": return false @@ -830,7 +831,7 @@ func (container *Container) secondaryNetworkRequired(primaryNetworkType string) return false } -func (container *Container) allocateNetwork() error { +func (container *Container) allocateNetwork(ctx context.Context) error { mode := container.hostConfig.NetworkMode controller := container.daemon.netController if container.Config.NetworkDisabled || mode.IsContainer() { @@ -864,21 +865,21 @@ func (container *Container) allocateNetwork() error { service = strings.Replace(service, "/", "", -1) } - if container.secondaryNetworkRequired(networkDriver) { + if container.secondaryNetworkRequired(ctx, networkDriver) { // Configure Bridge as secondary network for port binding purposes - if err := container.configureNetwork("bridge", service, "bridge", false); err != nil { + if err := container.configureNetwork(ctx, "bridge", service, "bridge", false); err != nil { return err } } - if err := container.configureNetwork(networkName, service, networkDriver, mode.IsDefault()); err != nil { + if err := container.configureNetwork(ctx, networkName, service, networkDriver, mode.IsDefault()); err != nil { return err } return container.writeHostConfig() } -func (container *Container) configureNetwork(networkName, service, networkDriver string, canCreateNetwork bool) error { +func (container *Container) configureNetwork(ctx context.Context, networkName, service, networkDriver string, canCreateNetwork bool) error { controller := container.daemon.netController n, err := controller.NetworkByName(networkName) @@ -922,7 +923,7 @@ func (container *Container) configureNetwork(networkName, service, networkDriver return false }) if sb == nil { - options, err := container.buildSandboxOptions() + options, err := container.buildSandboxOptions(ctx) if err != nil { return err } @@ -945,12 +946,12 @@ func (container *Container) configureNetwork(networkName, service, networkDriver return nil } -func (container *Container) initializeNetworking() error { +func (container *Container) initializeNetworking(ctx context.Context) error { var err error if container.hostConfig.NetworkMode.IsContainer() { // we need to get the hosts files from the container to join - nc, err := container.getNetworkedContainer() + nc, err := container.getNetworkedContainer(ctx) if err != nil { return err } @@ -976,7 +977,7 @@ func (container *Container) initializeNetworking() error { } - if err := container.allocateNetwork(); err != nil { + if err := container.allocateNetwork(ctx); err != nil { return err } @@ -997,9 +998,9 @@ func (container *Container) setNetworkNamespaceKey(pid int) error { return sandbox.SetKey(path) } -func (container *Container) getIpcContainer() (*Container, error) { +func (container *Container) getIpcContainer(ctx context.Context) (*Container, error) { containerID := container.hostConfig.IpcMode.Container() - c, err := container.daemon.Get(containerID) + c, err := container.daemon.Get(ctx, containerID) if err != nil { return nil, err } @@ -1035,14 +1036,14 @@ func (container *Container) setupWorkingDirectory() error { return nil } -func (container *Container) getNetworkedContainer() (*Container, error) { +func (container *Container) getNetworkedContainer(ctx context.Context) (*Container, error) { parts := strings.SplitN(string(container.hostConfig.NetworkMode), ":", 2) switch parts[0] { case "container": if len(parts) != 2 { return nil, derr.ErrorCodeParseContainer } - nc, err := container.daemon.Get(parts[1]) + nc, err := container.daemon.Get(ctx, parts[1]) if err != nil { return nil, err } diff --git a/daemon/container_windows.go b/daemon/container_windows.go index 38e0a120c5..e56b7e2d1a 100644 --- a/daemon/container_windows.go +++ b/daemon/container_windows.go @@ -5,6 +5,7 @@ package daemon import ( "strings" + "github.com/docker/docker/context" "github.com/docker/docker/daemon/execdriver" derr "github.com/docker/docker/errors" ) @@ -25,7 +26,7 @@ func killProcessDirectly(container *Container) error { return nil } -func (container *Container) setupLinkedContainers() ([]string, error) { +func (container *Container) setupLinkedContainers(ctx context.Context) ([]string, error) { return nil, nil } @@ -34,7 +35,7 @@ func (container *Container) createDaemonEnvironment(linkedEnv []string) []string return container.Config.Env } -func (container *Container) initializeNetworking() error { +func (container *Container) initializeNetworking(ctx context.Context) error { return nil } @@ -42,7 +43,7 @@ func (container *Container) setupWorkingDirectory() error { return nil } -func populateCommand(c *Container, env []string) error { +func populateCommand(ctx context.Context, c *Container, env []string) error { en := &execdriver.Network{ Interface: nil, } @@ -135,7 +136,7 @@ func populateCommand(c *Container, env []string) error { } // GetSize returns real size & virtual size -func (container *Container) getSize() (int64, int64) { +func (container *Container) getSize(ctx context.Context) (int64, int64) { // TODO Windows return 0, 0 } @@ -150,7 +151,7 @@ func (container *Container) allocateNetwork() error { return nil } -func (container *Container) updateNetwork() error { +func (container *Container) updateNetwork(ctx context.Context) error { return nil } diff --git a/daemon/create.go b/daemon/create.go index 76b014a34c..f38a04b954 100644 --- a/daemon/create.go +++ b/daemon/create.go @@ -5,6 +5,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/api/types" + "github.com/docker/docker/context" derr "github.com/docker/docker/errors" "github.com/docker/docker/graph/tags" "github.com/docker/docker/image" @@ -15,21 +16,21 @@ import ( ) // ContainerCreate takes configs and creates a container. -func (daemon *Daemon) ContainerCreate(name string, config *runconfig.Config, hostConfig *runconfig.HostConfig, adjustCPUShares bool) (*Container, []string, error) { +func (daemon *Daemon) ContainerCreate(ctx context.Context, name string, config *runconfig.Config, hostConfig *runconfig.HostConfig, adjustCPUShares bool) (*Container, []string, error) { if config == nil { return nil, nil, derr.ErrorCodeEmptyConfig } - warnings, err := daemon.verifyContainerSettings(hostConfig, config) + warnings, err := daemon.verifyContainerSettings(ctx, hostConfig, config) if err != nil { return nil, warnings, err } daemon.adaptContainerSettings(hostConfig, adjustCPUShares) - container, buildWarnings, err := daemon.Create(config, hostConfig, name) + container, buildWarnings, err := daemon.Create(ctx, config, hostConfig, name) if err != nil { - if daemon.Graph().IsNotExist(err, config.Image) { + if daemon.Graph(ctx).IsNotExist(err, config.Image) { if strings.Contains(config.Image, "@") { return nil, warnings, derr.ErrorCodeNoSuchImageHash.WithArgs(config.Image) } @@ -48,7 +49,7 @@ func (daemon *Daemon) ContainerCreate(name string, config *runconfig.Config, hos } // Create creates a new container from the given configuration with a given name. -func (daemon *Daemon) Create(config *runconfig.Config, hostConfig *runconfig.HostConfig, name string) (retC *Container, retS []string, retErr error) { +func (daemon *Daemon) Create(ctx context.Context, config *runconfig.Config, hostConfig *runconfig.HostConfig, name string) (retC *Container, retS []string, retErr error) { var ( container *Container warnings []string @@ -76,29 +77,29 @@ func (daemon *Daemon) Create(config *runconfig.Config, hostConfig *runconfig.Hos hostConfig = &runconfig.HostConfig{} } if hostConfig.SecurityOpt == nil { - hostConfig.SecurityOpt, err = daemon.generateSecurityOpt(hostConfig.IpcMode, hostConfig.PidMode) + hostConfig.SecurityOpt, err = daemon.generateSecurityOpt(ctx, hostConfig.IpcMode, hostConfig.PidMode) if err != nil { return nil, nil, err } } - if container, err = daemon.newContainer(name, config, imgID); err != nil { + if container, err = daemon.newContainer(ctx, name, config, imgID); err != nil { return nil, nil, err } defer func() { if retErr != nil { - if err := daemon.rm(container, false); err != nil { + if err := daemon.rm(ctx, container, false); err != nil { logrus.Errorf("Clean up Error! Cannot destroy container %s: %v", container.ID, err) } } }() - if err := daemon.Register(container); err != nil { + if err := daemon.Register(ctx, container); err != nil { return nil, nil, err } if err := daemon.createRootfs(container); err != nil { return nil, nil, err } - if err := daemon.setHostConfig(container, hostConfig); err != nil { + if err := daemon.setHostConfig(ctx, container, hostConfig); err != nil { return nil, nil, err } defer func() { @@ -108,10 +109,10 @@ func (daemon *Daemon) Create(config *runconfig.Config, hostConfig *runconfig.Hos } } }() - if err := container.Mount(); err != nil { + if err := container.Mount(ctx); err != nil { return nil, nil, err } - defer container.Unmount() + defer container.Unmount(ctx) if err := createContainerPlatformSpecificSettings(container, config, hostConfig, img); err != nil { return nil, nil, err @@ -121,16 +122,16 @@ func (daemon *Daemon) Create(config *runconfig.Config, hostConfig *runconfig.Hos logrus.Errorf("Error saving new container to disk: %v", err) return nil, nil, err } - container.logEvent("create") + container.logEvent(ctx, "create") return container, warnings, nil } -func (daemon *Daemon) generateSecurityOpt(ipcMode runconfig.IpcMode, pidMode runconfig.PidMode) ([]string, error) { +func (daemon *Daemon) generateSecurityOpt(ctx context.Context, ipcMode runconfig.IpcMode, pidMode runconfig.PidMode) ([]string, error) { if ipcMode.IsHost() || pidMode.IsHost() { return label.DisableSecOpt(), nil } if ipcContainer := ipcMode.Container(); ipcContainer != "" { - c, err := daemon.Get(ipcContainer) + c, err := daemon.Get(ctx, ipcContainer) if err != nil { return nil, err } @@ -142,7 +143,7 @@ func (daemon *Daemon) generateSecurityOpt(ipcMode runconfig.IpcMode, pidMode run // VolumeCreate creates a volume with the specified name, driver, and opts // This is called directly from the remote API -func (daemon *Daemon) VolumeCreate(name, driverName string, opts map[string]string) (*types.Volume, error) { +func (daemon *Daemon) VolumeCreate(ctx context.Context, name, driverName string, opts map[string]string) (*types.Volume, error) { if name == "" { name = stringid.GenerateNonCryptoID() } diff --git a/daemon/daemon.go b/daemon/daemon.go index 84b73aa269..65fbfbb2e9 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -20,6 +20,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/api" + "github.com/docker/docker/context" "github.com/docker/docker/daemon/events" "github.com/docker/docker/daemon/execdriver" "github.com/docker/docker/daemon/execdriver/execdrivers" @@ -127,14 +128,14 @@ type Daemon struct { // - A partial container ID prefix (e.g. short ID) of any length that is // unique enough to only return a single container object // If none of these searches succeed, an error is returned -func (daemon *Daemon) Get(prefixOrName string) (*Container, error) { +func (daemon *Daemon) Get(ctx context.Context, prefixOrName string) (*Container, error) { if containerByID := daemon.containers.Get(prefixOrName); containerByID != nil { // prefix is an exact match to a full container ID return containerByID, nil } // GetByName will match only an exact name provided; we ignore errors - if containerByName, _ := daemon.GetByName(prefixOrName); containerByName != nil { + if containerByName, _ := daemon.GetByName(ctx, prefixOrName); containerByName != nil { // prefix is an exact match to a full container Name return containerByName, nil } @@ -152,8 +153,8 @@ func (daemon *Daemon) Get(prefixOrName string) (*Container, error) { // Exists returns a true if a container of the specified ID or name exists, // false otherwise. -func (daemon *Daemon) Exists(id string) bool { - c, _ := daemon.Get(id) +func (daemon *Daemon) Exists(ctx context.Context, id string) bool { + c, _ := daemon.Get(ctx, id) return c != nil } @@ -178,8 +179,8 @@ func (daemon *Daemon) load(id string) (*Container, error) { } // Register makes a container object usable by the daemon as -func (daemon *Daemon) Register(container *Container) error { - if container.daemon != nil || daemon.Exists(container.ID) { +func (daemon *Daemon) Register(ctx context.Context, container *Container) error { + if container.daemon != nil || daemon.Exists(ctx, container.ID) { return fmt.Errorf("Container is already loaded") } if err := validateID(container.ID); err != nil { @@ -217,10 +218,7 @@ func (daemon *Daemon) Register(container *Container) error { } daemon.execDriver.Terminate(cmd) - if err := container.unmountIpcMounts(); err != nil { - logrus.Errorf("%s: Failed to umount ipc filesystems: %v", container.ID, err) - } - if err := container.Unmount(); err != nil { + if err := container.Unmount(ctx); err != nil { logrus.Debugf("unmount error %s", err) } if err := container.toDiskLocking(); err != nil { @@ -254,7 +252,7 @@ func (daemon *Daemon) ensureName(container *Container) error { return nil } -func (daemon *Daemon) restore() error { +func (daemon *Daemon) restore(ctx context.Context) error { type cr struct { container *Container registered bool @@ -324,7 +322,7 @@ func (daemon *Daemon) restore() error { } } - if err := daemon.Register(container); err != nil { + if err := daemon.Register(ctx, container); err != nil { logrus.Errorf("Failed to register container %s: %s", container.ID, err) // The container register failed should not be started. return @@ -335,7 +333,7 @@ func (daemon *Daemon) restore() error { if daemon.configStore.AutoRestart && container.shouldRestart() { logrus.Debugf("Starting container %s", container.ID) - if err := container.Start(); err != nil { + if err := container.Start(ctx); err != nil { logrus.Errorf("Failed to start container %s: %s", container.ID, err) } } @@ -365,7 +363,7 @@ func (daemon *Daemon) mergeAndVerifyConfig(config *runconfig.Config, img *image. return nil } -func (daemon *Daemon) generateIDAndName(name string) (string, string, error) { +func (daemon *Daemon) generateIDAndName(ctx context.Context, name string) (string, string, error) { var ( err error id = stringid.GenerateNonCryptoID() @@ -378,14 +376,14 @@ func (daemon *Daemon) generateIDAndName(name string) (string, string, error) { return id, name, nil } - if name, err = daemon.reserveName(id, name); err != nil { + if name, err = daemon.reserveName(ctx, id, name); err != nil { return "", "", err } return id, name, nil } -func (daemon *Daemon) reserveName(id, name string) (string, error) { +func (daemon *Daemon) reserveName(ctx context.Context, id, name string) (string, error) { if !validContainerNamePattern.MatchString(name) { return "", fmt.Errorf("Invalid container name (%s), only %s are allowed", name, validContainerNameChars) } @@ -399,7 +397,7 @@ func (daemon *Daemon) reserveName(id, name string) (string, error) { return "", err } - conflictingContainer, err := daemon.GetByName(name) + conflictingContainer, err := daemon.GetByName(ctx, name) if err != nil { if strings.Contains(err.Error(), "Could not find entity") { return "", err @@ -469,12 +467,12 @@ func (daemon *Daemon) getEntrypointAndArgs(configEntrypoint *stringutils.StrSlic return entrypoint, args } -func (daemon *Daemon) newContainer(name string, config *runconfig.Config, imgID string) (*Container, error) { +func (daemon *Daemon) newContainer(ctx context.Context, name string, config *runconfig.Config, imgID string) (*Container, error) { var ( id string err error ) - id, name, err = daemon.generateIDAndName(name) + id, name, err = daemon.generateIDAndName(ctx, name) if err != nil { return nil, err } @@ -511,7 +509,7 @@ func GetFullContainerName(name string) (string, error) { } // GetByName returns a container given a name. -func (daemon *Daemon) GetByName(name string) (*Container, error) { +func (daemon *Daemon) GetByName(ctx context.Context, name string) (*Container, error) { fullName, err := GetFullContainerName(name) if err != nil { return nil, err @@ -530,7 +528,7 @@ func (daemon *Daemon) GetByName(name string) (*Container, error) { // children returns all child containers of the container with the // given name. The containers are returned as a map from the container // name to a pointer to Container. -func (daemon *Daemon) children(name string) (map[string]*Container, error) { +func (daemon *Daemon) children(ctx context.Context, name string) (map[string]*Container, error) { name, err := GetFullContainerName(name) if err != nil { return nil, err @@ -538,7 +536,7 @@ func (daemon *Daemon) children(name string) (map[string]*Container, error) { children := make(map[string]*Container) err = daemon.containerGraphDB.Walk(name, func(p string, e *graphdb.Entity) error { - c, err := daemon.Get(e.ID()) + c, err := daemon.Get(ctx, e.ID()) if err != nil { return err } @@ -574,7 +572,7 @@ func (daemon *Daemon) registerLink(parent, child *Container, alias string) error // NewDaemon sets up everything for the daemon to be able to service // requests from the webserver. -func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemon, err error) { +func NewDaemon(ctx context.Context, config *Config, registryService *registry.Service) (daemon *Daemon, err error) { setDefaultMtu(config) // Ensure we have compatible configuration options @@ -642,7 +640,7 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo // Ensure the graph driver is shutdown at a later point defer func() { if err != nil { - if err := d.Shutdown(); err != nil { + if err := d.Shutdown(ctx); err != nil { logrus.Error(err) } } @@ -776,7 +774,7 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo go d.execCommandGC() - if err := d.restore(); err != nil { + if err := d.restore(ctx); err != nil { return nil, err } @@ -784,12 +782,12 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo } // Shutdown stops the daemon. -func (daemon *Daemon) Shutdown() error { +func (daemon *Daemon) Shutdown(ctx context.Context) error { daemon.shutdown = true if daemon.containers != nil { group := sync.WaitGroup{} logrus.Debug("starting clean shutdown of all containers...") - for _, container := range daemon.List() { + for _, container := range daemon.List(ctx) { c := container if c.IsRunning() { logrus.Debugf("stopping %s", c.ID) @@ -812,7 +810,7 @@ func (daemon *Daemon) Shutdown() error { logrus.Debugf("sending SIGTERM to container %s with error: %v", c.ID, err) return } - if err := c.unpause(); err != nil { + if err := c.unpause(ctx); err != nil { logrus.Debugf("Failed to unpause container %s with error: %v", c.ID, err) return } @@ -827,7 +825,7 @@ func (daemon *Daemon) Shutdown() error { } } else { // If container failed to exit in 10 seconds of SIGTERM, then using the force - if err := c.Stop(10); err != nil { + if err := c.Stop(ctx, 10); err != nil { logrus.Errorf("Stop container %s with error: %v", c.ID, err) } } @@ -865,7 +863,7 @@ func (daemon *Daemon) Shutdown() error { // Mount sets container.basefs // (is it not set coming in? why is it unset?) -func (daemon *Daemon) Mount(container *Container) error { +func (daemon *Daemon) Mount(ctx context.Context, container *Container) error { dir, err := daemon.driver.Get(container.ID, container.getMountLabel()) if err != nil { return fmt.Errorf("Error getting container %s from driver %s: %s", container.ID, daemon.driver, err) @@ -890,14 +888,14 @@ func (daemon *Daemon) unmount(container *Container) error { return nil } -func (daemon *Daemon) run(c *Container, pipes *execdriver.Pipes, startCallback execdriver.DriverCallback) (execdriver.ExitStatus, error) { +func (daemon *Daemon) run(ctx context.Context, c *Container, pipes *execdriver.Pipes, startCallback execdriver.DriverCallback) (execdriver.ExitStatus, error) { hooks := execdriver.Hooks{ Start: startCallback, } - hooks.PreStart = append(hooks.PreStart, func(processConfig *execdriver.ProcessConfig, pid int, chOOM <-chan struct{}) error { + hooks.PreStart = append(hooks.PreStart, func(ctx context.Context, processConfig *execdriver.ProcessConfig, pid int, chOOM <-chan struct{}) error { return c.setNetworkNamespaceKey(pid) }) - return daemon.execDriver.Run(c.command, pipes, hooks) + return daemon.execDriver.Run(ctx, c.command, pipes, hooks) } func (daemon *Daemon) kill(c *Container, sig int) error { @@ -964,12 +962,12 @@ func (daemon *Daemon) createRootfs(container *Container) error { // which need direct access to daemon.graph. // Once the tests switch to using engine and jobs, this method // can go away. -func (daemon *Daemon) Graph() *graph.Graph { +func (daemon *Daemon) Graph(ctx context.Context) *graph.Graph { return daemon.graph } // Repositories returns all repositories. -func (daemon *Daemon) Repositories() *graph.TagStore { +func (daemon *Daemon) Repositories(ctx context.Context) *graph.TagStore { return daemon.repositories } @@ -983,13 +981,13 @@ func (daemon *Daemon) systemInitPath() string { // GraphDriver returns the currently used driver for processing // container layers. -func (daemon *Daemon) GraphDriver() graphdriver.Driver { +func (daemon *Daemon) GraphDriver(ctx context.Context) graphdriver.Driver { return daemon.driver } // ExecutionDriver returns the currently used driver for creating and // starting execs in a container. -func (daemon *Daemon) ExecutionDriver() execdriver.Driver { +func (daemon *Daemon) ExecutionDriver(ctx context.Context) execdriver.Driver { return daemon.execDriver } @@ -1001,9 +999,9 @@ func (daemon *Daemon) containerGraph() *graphdb.Database { // of the image with imgID, that had the same config when it was // created. nil is returned if a child cannot be found. An error is // returned if the parent image cannot be found. -func (daemon *Daemon) ImageGetCached(imgID string, config *runconfig.Config) (*image.Image, error) { +func (daemon *Daemon) ImageGetCached(ctx context.Context, imgID string, config *runconfig.Config) (*image.Image, error) { // Retrieve all images - images := daemon.Graph().Map() + images := daemon.Graph(ctx).Map() // Store the tree in a map of map (map[parentId][childId]) imageMap := make(map[string]map[string]struct{}) @@ -1039,7 +1037,7 @@ func tempDir(rootDir string) (string, error) { return tmpDir, system.MkdirAll(tmpDir, 0700) } -func (daemon *Daemon) setHostConfig(container *Container, hostConfig *runconfig.HostConfig) error { +func (daemon *Daemon) setHostConfig(ctx context.Context, container *Container, hostConfig *runconfig.HostConfig) error { container.Lock() if err := parseSecurityOpt(container, hostConfig); err != nil { container.Unlock() @@ -1049,14 +1047,14 @@ func (daemon *Daemon) setHostConfig(container *Container, hostConfig *runconfig. // Do not lock while creating volumes since this could be calling out to external plugins // Don't want to block other actions, like `docker ps` because we're waiting on an external plugin - if err := daemon.registerMountPoints(container, hostConfig); err != nil { + if err := daemon.registerMountPoints(ctx, container, hostConfig); err != nil { return err } container.Lock() defer container.Unlock() // Register any links from the host config before starting the container - if err := daemon.registerLinks(container, hostConfig); err != nil { + if err := daemon.registerLinks(ctx, container, hostConfig); err != nil { return err } @@ -1094,7 +1092,7 @@ func getDefaultRouteMtu() (int, error) { // verifyContainerSettings performs validation of the hostconfig and config // structures. -func (daemon *Daemon) verifyContainerSettings(hostConfig *runconfig.HostConfig, config *runconfig.Config) ([]string, error) { +func (daemon *Daemon) verifyContainerSettings(ctx context.Context, hostConfig *runconfig.HostConfig, config *runconfig.Config) ([]string, error) { // First perform verification of settings common across all platforms. if config != nil { @@ -1131,7 +1129,7 @@ func (daemon *Daemon) verifyContainerSettings(hostConfig *runconfig.HostConfig, } // Now do platform-specific verification - return verifyPlatformContainerSettings(daemon, hostConfig, config) + return verifyPlatformContainerSettings(ctx, daemon, hostConfig, config) } func configureVolumes(config *Config) (*store.VolumeStore, error) { diff --git a/daemon/daemon_test.go b/daemon/daemon_test.go index f849fdbe94..9e0706f770 100644 --- a/daemon/daemon_test.go +++ b/daemon/daemon_test.go @@ -8,6 +8,7 @@ import ( "path/filepath" "testing" + "github.com/docker/docker/context" "github.com/docker/docker/pkg/graphdb" "github.com/docker/docker/pkg/stringid" "github.com/docker/docker/pkg/truncindex" @@ -92,32 +93,34 @@ func TestGet(t *testing.T) { containerGraphDB: graph, } - if container, _ := daemon.Get("3cdbd1aa394fd68559fd1441d6eff2ab7c1e6363582c82febfaa8045df3bd8de"); container != c2 { + ctx := context.Background() + + if container, _ := daemon.Get(ctx, "3cdbd1aa394fd68559fd1441d6eff2ab7c1e6363582c82febfaa8045df3bd8de"); container != c2 { t.Fatal("Should explicitly match full container IDs") } - if container, _ := daemon.Get("75fb0b8009"); container != c4 { + if container, _ := daemon.Get(ctx, "75fb0b8009"); container != c4 { t.Fatal("Should match a partial ID") } - if container, _ := daemon.Get("drunk_hawking"); container != c2 { + if container, _ := daemon.Get(ctx, "drunk_hawking"); container != c2 { t.Fatal("Should match a full name") } // c3.Name is a partial match for both c3.ID and c2.ID - if c, _ := daemon.Get("3cdbd1aa"); c != c3 { + if c, _ := daemon.Get(ctx, "3cdbd1aa"); c != c3 { t.Fatal("Should match a full name even though it collides with another container's ID") } - if container, _ := daemon.Get("d22d69a2b896"); container != c5 { + if container, _ := daemon.Get(ctx, "d22d69a2b896"); container != c5 { t.Fatal("Should match a container where the provided prefix is an exact match to the it's name, and is also a prefix for it's ID") } - if _, err := daemon.Get("3cdbd1"); err == nil { + if _, err := daemon.Get(ctx, "3cdbd1"); err == nil { t.Fatal("Should return an error when provided a prefix that partially matches multiple container ID's") } - if _, err := daemon.Get("nothing"); err == nil { + if _, err := daemon.Get(ctx, "nothing"); err == nil { t.Fatal("Should return an error when provided a prefix that is neither a name or a partial match to an ID") } @@ -486,13 +489,15 @@ func TestRemoveLocalVolumesFollowingSymlinks(t *testing.T) { t.Fatalf("Expected 1 volume mounted, was 0\n") } + ctx := context.Background() + m := c.MountPoints["/vol1"] - _, err = daemon.VolumeCreate(m.Name, m.Driver, nil) + _, err = daemon.VolumeCreate(ctx, m.Name, m.Driver, nil) if err != nil { t.Fatal(err) } - if err := daemon.VolumeRm(m.Name); err != nil { + if err := daemon.VolumeRm(ctx, m.Name); err != nil { t.Fatal(err) } diff --git a/daemon/daemon_unix.go b/daemon/daemon_unix.go index af46270170..030db716a0 100644 --- a/daemon/daemon_unix.go +++ b/daemon/daemon_unix.go @@ -13,6 +13,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/autogen/dockerversion" + "github.com/docker/docker/context" "github.com/docker/docker/daemon/graphdriver" "github.com/docker/docker/pkg/fileutils" "github.com/docker/docker/pkg/parsers" @@ -114,12 +115,12 @@ func (daemon *Daemon) adaptContainerSettings(hostConfig *runconfig.HostConfig, a // verifyPlatformContainerSettings performs platform-specific validation of the // hostconfig and config structures. -func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *runconfig.HostConfig, config *runconfig.Config) ([]string, error) { +func verifyPlatformContainerSettings(ctx context.Context, daemon *Daemon, hostConfig *runconfig.HostConfig, config *runconfig.Config) ([]string, error) { warnings := []string{} sysInfo := sysinfo.New(true) - if hostConfig.LxcConf.Len() > 0 && !strings.Contains(daemon.ExecutionDriver().Name(), "lxc") { - return warnings, fmt.Errorf("Cannot use --lxc-conf with execdriver: %s", daemon.ExecutionDriver().Name()) + if hostConfig.LxcConf.Len() > 0 && !strings.Contains(daemon.ExecutionDriver(ctx).Name(), "lxc") { + return warnings, fmt.Errorf("Cannot use --lxc-conf with execdriver: %s", daemon.ExecutionDriver(ctx).Name()) } // memory subsystem checks and adjustments @@ -484,12 +485,12 @@ func setupInitLayer(initLayer string) error { // NetworkAPIRouter implements a feature for server-experimental, // directly calling into libnetwork. -func (daemon *Daemon) NetworkAPIRouter() func(w http.ResponseWriter, req *http.Request) { +func (daemon *Daemon) NetworkAPIRouter(ctx context.Context) func(w http.ResponseWriter, req *http.Request) { return nwapi.NewHTTPHandler(daemon.netController) } // registerLinks writes the links to a file. -func (daemon *Daemon) registerLinks(container *Container, hostConfig *runconfig.HostConfig) error { +func (daemon *Daemon) registerLinks(ctx context.Context, container *Container, hostConfig *runconfig.HostConfig) error { if hostConfig == nil || hostConfig.Links == nil { return nil } @@ -499,14 +500,14 @@ func (daemon *Daemon) registerLinks(container *Container, hostConfig *runconfig. if err != nil { return err } - child, err := daemon.Get(name) + child, err := daemon.Get(ctx, name) if err != nil { //An error from daemon.Get() means this name could not be found return fmt.Errorf("Could not get container for %s", name) } for child.hostConfig.NetworkMode.IsContainer() { parts := strings.SplitN(string(child.hostConfig.NetworkMode), ":", 2) - child, err = daemon.Get(parts[1]) + child, err = daemon.Get(ctx, parts[1]) if err != nil { return fmt.Errorf("Could not get container for %s", parts[1]) } diff --git a/daemon/daemon_windows.go b/daemon/daemon_windows.go index 2818b116ce..6ad015c74b 100644 --- a/daemon/daemon_windows.go +++ b/daemon/daemon_windows.go @@ -6,6 +6,7 @@ import ( "syscall" "github.com/Sirupsen/logrus" + "github.com/docker/docker/context" "github.com/docker/docker/daemon/graphdriver" // register the windows graph driver _ "github.com/docker/docker/daemon/graphdriver/windows" @@ -47,7 +48,7 @@ func (daemon *Daemon) adaptContainerSettings(hostConfig *runconfig.HostConfig, a // verifyPlatformContainerSettings performs platform-specific validation of the // hostconfig and config structures. -func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *runconfig.HostConfig, config *runconfig.Config) ([]string, error) { +func verifyPlatformContainerSettings(ctx context.Context, daemon *Daemon, hostConfig *runconfig.HostConfig, config *runconfig.Config) ([]string, error) { return nil, nil } @@ -104,7 +105,7 @@ func initNetworkController(config *Config) (libnetwork.NetworkController, error) // registerLinks sets up links between containers and writes the // configuration out for persistence. -func (daemon *Daemon) registerLinks(container *Container, hostConfig *runconfig.HostConfig) error { +func (daemon *Daemon) registerLinks(ctx context.Context, container *Container, hostConfig *runconfig.HostConfig) error { // TODO Windows. Factored out for network modes. There may be more // refactoring required here. @@ -117,7 +118,7 @@ func (daemon *Daemon) registerLinks(container *Container, hostConfig *runconfig. if err != nil { return err } - child, err := daemon.Get(name) + child, err := daemon.Get(ctx, name) if err != nil { //An error from daemon.Get() means this name could not be found return fmt.Errorf("Could not get container for %s", name) diff --git a/daemon/delete.go b/daemon/delete.go index 52cc39beaf..771b03f9a8 100644 --- a/daemon/delete.go +++ b/daemon/delete.go @@ -5,6 +5,8 @@ import ( "os" "path" + "github.com/docker/docker/context" + "github.com/Sirupsen/logrus" derr "github.com/docker/docker/errors" "github.com/docker/docker/volume/store" @@ -19,8 +21,8 @@ type ContainerRmConfig struct { // is returned if the container is not found, or if the remove // fails. If the remove succeeds, the container name is released, and // network links are removed. -func (daemon *Daemon) ContainerRm(name string, config *ContainerRmConfig) error { - container, err := daemon.Get(name) +func (daemon *Daemon) ContainerRm(ctx context.Context, name string, config *ContainerRmConfig) error { + container, err := daemon.Get(ctx, name) if err != nil { return err } @@ -43,9 +45,9 @@ func (daemon *Daemon) ContainerRm(name string, config *ContainerRmConfig) error return err } - parentContainer, _ := daemon.Get(pe.ID()) + parentContainer, _ := daemon.Get(ctx, pe.ID()) if parentContainer != nil { - if err := parentContainer.updateNetwork(); err != nil { + if err := parentContainer.updateNetwork(ctx); err != nil { logrus.Debugf("Could not update network to remove link %s: %v", n, err) } } @@ -53,7 +55,7 @@ func (daemon *Daemon) ContainerRm(name string, config *ContainerRmConfig) error return nil } - if err := daemon.rm(container, config.ForceRemove); err != nil { + if err := daemon.rm(ctx, container, config.ForceRemove); err != nil { // return derr.ErrorCodeCantDestroy.WithArgs(name, utils.GetErrorMessage(err)) return err } @@ -66,12 +68,12 @@ func (daemon *Daemon) ContainerRm(name string, config *ContainerRmConfig) error } // Destroy unregisters a container from the daemon and cleanly removes its contents from the filesystem. -func (daemon *Daemon) rm(container *Container, forceRemove bool) (err error) { +func (daemon *Daemon) rm(ctx context.Context, container *Container, forceRemove bool) (err error) { if container.IsRunning() { if !forceRemove { return derr.ErrorCodeRmRunning } - if err := container.Kill(); err != nil { + if err := container.Kill(ctx); err != nil { return derr.ErrorCodeRmFailed.WithArgs(err) } } @@ -92,7 +94,7 @@ func (daemon *Daemon) rm(container *Container, forceRemove bool) (err error) { defer container.resetRemovalInProgress() - if err = container.Stop(3); err != nil { + if err = container.Stop(ctx, 3); err != nil { return err } @@ -113,7 +115,7 @@ func (daemon *Daemon) rm(container *Container, forceRemove bool) (err error) { daemon.idIndex.Delete(container.ID) daemon.containers.Delete(container.ID) os.RemoveAll(container.root) - container.logEvent("destroy") + container.logEvent(ctx, "destroy") } }() @@ -142,14 +144,14 @@ func (daemon *Daemon) rm(container *Container, forceRemove bool) (err error) { daemon.idIndex.Delete(container.ID) daemon.containers.Delete(container.ID) - container.logEvent("destroy") + container.logEvent(ctx, "destroy") return nil } // VolumeRm removes the volume with the given name. // If the volume is referenced by a container it is not removed // This is called directly from the remote API -func (daemon *Daemon) VolumeRm(name string) error { +func (daemon *Daemon) VolumeRm(ctx context.Context, name string) error { v, err := daemon.volumes.Get(name) if err != nil { return err diff --git a/daemon/events/events.go b/daemon/events/events.go index 0334dece47..eb19cd64fb 100644 --- a/daemon/events/events.go +++ b/daemon/events/events.go @@ -4,6 +4,8 @@ import ( "sync" "time" + "github.com/docker/docker/context" + "github.com/docker/docker/pkg/jsonmessage" "github.com/docker/docker/pkg/pubsub" ) @@ -44,9 +46,9 @@ func (e *Events) Evict(l chan interface{}) { // Log broadcasts event to listeners. Each listener has 100 millisecond for // receiving event or it will be skipped. -func (e *Events) Log(action, id, from string) { +func (e *Events) Log(ctx context.Context, action, id, from string) { now := time.Now().UTC() - jm := &jsonmessage.JSONMessage{Status: action, ID: id, From: from, Time: now.Unix(), TimeNano: now.UnixNano()} + jm := &jsonmessage.JSONMessage{RequestID: ctx.RequestID(), Status: action, ID: id, From: from, Time: now.Unix(), TimeNano: now.UnixNano()} e.mu.Lock() if len(e.events) == cap(e.events) { // discard oldest event diff --git a/daemon/events/events_test.go b/daemon/events/events_test.go index 7aa8d9facc..38e919c092 100644 --- a/daemon/events/events_test.go +++ b/daemon/events/events_test.go @@ -5,10 +5,12 @@ import ( "testing" "time" + "github.com/docker/docker/context" "github.com/docker/docker/pkg/jsonmessage" ) func TestEventsLog(t *testing.T) { + ctx := context.Background() e := New() _, l1 := e.Subscribe() _, l2 := e.Subscribe() @@ -18,7 +20,7 @@ func TestEventsLog(t *testing.T) { if count != 2 { t.Fatalf("Must be 2 subscribers, got %d", count) } - e.Log("test", "cont", "image") + e.Log(ctx, "test", "cont", "image") select { case msg := <-l1: jmsg, ok := msg.(*jsonmessage.JSONMessage) @@ -64,13 +66,14 @@ func TestEventsLog(t *testing.T) { } func TestEventsLogTimeout(t *testing.T) { + ctx := context.Background() e := New() _, l := e.Subscribe() defer e.Evict(l) c := make(chan struct{}) go func() { - e.Log("test", "cont", "image") + e.Log(ctx, "test", "cont", "image") close(c) }() @@ -82,13 +85,14 @@ func TestEventsLogTimeout(t *testing.T) { } func TestLogEvents(t *testing.T) { + ctx := context.Background() e := New() for i := 0; i < eventsLimit+16; i++ { action := fmt.Sprintf("action_%d", i) id := fmt.Sprintf("cont_%d", i) from := fmt.Sprintf("image_%d", i) - e.Log(action, id, from) + e.Log(ctx, action, id, from) } time.Sleep(50 * time.Millisecond) current, l := e.Subscribe() @@ -97,7 +101,7 @@ func TestLogEvents(t *testing.T) { action := fmt.Sprintf("action_%d", num) id := fmt.Sprintf("cont_%d", num) from := fmt.Sprintf("image_%d", num) - e.Log(action, id, from) + e.Log(ctx, action, id, from) } if len(e.events) != eventsLimit { t.Fatalf("Must be %d events, got %d", eventsLimit, len(e.events)) diff --git a/daemon/exec.go b/daemon/exec.go index 8ec8a1c583..8eb4a09dbb 100644 --- a/daemon/exec.go +++ b/daemon/exec.go @@ -8,6 +8,7 @@ import ( "time" "github.com/Sirupsen/logrus" + "github.com/docker/docker/context" "github.com/docker/docker/daemon/execdriver" derr "github.com/docker/docker/errors" "github.com/docker/docker/pkg/broadcastwriter" @@ -117,8 +118,8 @@ func (d *Daemon) unregisterExecCommand(ExecConfig *ExecConfig) { d.execCommands.Delete(ExecConfig.ID) } -func (d *Daemon) getActiveContainer(name string) (*Container, error) { - container, err := d.Get(name) +func (d *Daemon) getActiveContainer(ctx context.Context, name string) (*Container, error) { + container, err := d.Get(ctx, name) if err != nil { return nil, err } @@ -133,13 +134,13 @@ func (d *Daemon) getActiveContainer(name string) (*Container, error) { } // ContainerExecCreate sets up an exec in a running container. -func (d *Daemon) ContainerExecCreate(config *runconfig.ExecConfig) (string, error) { +func (d *Daemon) ContainerExecCreate(ctx context.Context, config *runconfig.ExecConfig) (string, error) { // Not all drivers support Exec (LXC for example) if err := checkExecSupport(d.execDriver.Name()); err != nil { return "", err } - container, err := d.getActiveContainer(config.Container) + container, err := d.getActiveContainer(ctx, config.Container) if err != nil { return "", err } @@ -174,14 +175,14 @@ func (d *Daemon) ContainerExecCreate(config *runconfig.ExecConfig) (string, erro d.registerExecCommand(ExecConfig) - container.logEvent("exec_create: " + ExecConfig.ProcessConfig.Entrypoint + " " + strings.Join(ExecConfig.ProcessConfig.Arguments, " ")) + container.logEvent(ctx, "exec_create: "+ExecConfig.ProcessConfig.Entrypoint+" "+strings.Join(ExecConfig.ProcessConfig.Arguments, " ")) return ExecConfig.ID, nil } // ContainerExecStart starts a previously set up exec instance. The // std streams are set up. -func (d *Daemon) ContainerExecStart(execName string, stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) error { +func (d *Daemon) ContainerExecStart(ctx context.Context, execName string, stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) error { var ( cStdin io.ReadCloser cStdout, cStderr io.Writer @@ -207,7 +208,7 @@ func (d *Daemon) ContainerExecStart(execName string, stdin io.ReadCloser, stdout logrus.Debugf("starting exec command %s in container %s", ExecConfig.ID, ExecConfig.Container.ID) container := ExecConfig.Container - container.logEvent("exec_start: " + ExecConfig.ProcessConfig.Entrypoint + " " + strings.Join(ExecConfig.ProcessConfig.Arguments, " ")) + container.logEvent(ctx, "exec_start: "+ExecConfig.ProcessConfig.Entrypoint+" "+strings.Join(ExecConfig.ProcessConfig.Arguments, " ")) if ExecConfig.OpenStdin { r, w := io.Pipe() @@ -243,7 +244,7 @@ func (d *Daemon) ContainerExecStart(execName string, stdin io.ReadCloser, stdout // the exitStatus) even after the cmd is done running. go func() { - if err := container.exec(ExecConfig); err != nil { + if err := container.exec(ctx, ExecConfig); err != nil { execErr <- derr.ErrorCodeExecCantRun.WithArgs(execName, container.ID, err) } }() @@ -267,11 +268,11 @@ func (d *Daemon) ContainerExecStart(execName string, stdin io.ReadCloser, stdout } // Exec calls the underlying exec driver to run -func (d *Daemon) Exec(c *Container, ExecConfig *ExecConfig, pipes *execdriver.Pipes, startCallback execdriver.DriverCallback) (int, error) { +func (d *Daemon) Exec(ctx context.Context, c *Container, ExecConfig *ExecConfig, pipes *execdriver.Pipes, startCallback execdriver.DriverCallback) (int, error) { hooks := execdriver.Hooks{ Start: startCallback, } - exitStatus, err := d.execDriver.Exec(c.command, ExecConfig.ProcessConfig, pipes, hooks) + exitStatus, err := d.execDriver.Exec(ctx, c.command, ExecConfig.ProcessConfig, pipes, hooks) // On err, make sure we don't leave ExitCode at zero if err != nil && exitStatus == 0 { diff --git a/daemon/execdriver/driver.go b/daemon/execdriver/driver.go index 9977711188..339cf59596 100644 --- a/daemon/execdriver/driver.go +++ b/daemon/execdriver/driver.go @@ -7,6 +7,7 @@ import ( "time" // TODO Windows: Factor out ulimit + "github.com/docker/docker/context" "github.com/docker/docker/pkg/ulimit" "github.com/opencontainers/runc/libcontainer" "github.com/opencontainers/runc/libcontainer/configs" @@ -29,7 +30,7 @@ var ( // through PreStart, Start and PostStop events. // Callbacks are provided a processConfig pointer and the pid of the child. // The channel will be used to notify the OOM events. -type DriverCallback func(processConfig *ProcessConfig, pid int, chOOM <-chan struct{}) error +type DriverCallback func(ctx context.Context, processConfig *ProcessConfig, pid int, chOOM <-chan struct{}) error // Hooks is a struct containing function pointers to callbacks // used by any execdriver implementation exploiting hooks capabilities @@ -69,11 +70,11 @@ type ExitStatus struct { type Driver interface { // Run executes the process, blocks until the process exits and returns // the exit code. It's the last stage on Docker side for running a container. - Run(c *Command, pipes *Pipes, hooks Hooks) (ExitStatus, error) + Run(ctx context.Context, c *Command, pipes *Pipes, hooks Hooks) (ExitStatus, error) // Exec executes the process in an existing container, blocks until the // process exits and returns the exit code. - Exec(c *Command, processConfig *ProcessConfig, pipes *Pipes, hooks Hooks) (int, error) + Exec(ctx context.Context, c *Command, processConfig *ProcessConfig, pipes *Pipes, hooks Hooks) (int, error) // Kill sends signals to process in container. Kill(c *Command, sig int) error diff --git a/daemon/execdriver/lxc/driver.go b/daemon/execdriver/lxc/driver.go index 30b36e775d..58248dc264 100644 --- a/daemon/execdriver/lxc/driver.go +++ b/daemon/execdriver/lxc/driver.go @@ -20,6 +20,7 @@ import ( "time" "github.com/Sirupsen/logrus" + "github.com/docker/docker/context" "github.com/docker/docker/daemon/execdriver" "github.com/docker/docker/pkg/stringutils" sysinfo "github.com/docker/docker/pkg/system" @@ -125,7 +126,7 @@ func killNetNsProc(proc *os.Process) { // Run implements the exec driver Driver interface, // it calls 'exec.Cmd' to launch lxc commands to run a container. -func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execdriver.Hooks) (execdriver.ExitStatus, error) { +func (d *Driver) Run(ctx context.Context, c *execdriver.Command, pipes *execdriver.Pipes, hooks execdriver.Hooks) (execdriver.ExitStatus, error) { var ( term execdriver.Terminal err error @@ -329,7 +330,7 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execd if hooks.Start != nil { logrus.Debugf("Invoking startCallback") - hooks.Start(&c.ProcessConfig, pid, oomKillNotification) + hooks.Start(ctx, &c.ProcessConfig, pid, oomKillNotification) } @@ -871,7 +872,7 @@ func (t *TtyConsole) Close() error { // Exec implements the exec driver Driver interface, // it is not implemented by lxc. -func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, hooks execdriver.Hooks) (int, error) { +func (d *Driver) Exec(ctx context.Context, c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, hooks execdriver.Hooks) (int, error) { return -1, ErrExec } diff --git a/daemon/execdriver/native/create.go b/daemon/execdriver/native/create.go index c480534585..da64c74012 100644 --- a/daemon/execdriver/native/create.go +++ b/daemon/execdriver/native/create.go @@ -9,6 +9,7 @@ import ( "strings" "syscall" + "github.com/docker/docker/context" "github.com/docker/docker/daemon/execdriver" "github.com/opencontainers/runc/libcontainer/apparmor" "github.com/opencontainers/runc/libcontainer/configs" @@ -18,7 +19,7 @@ import ( // createContainer populates and configures the container type with the // data provided by the execdriver.Command -func (d *Driver) createContainer(c *execdriver.Command, hooks execdriver.Hooks) (*configs.Config, error) { +func (d *Driver) createContainer(ctx context.Context, c *execdriver.Command, hooks execdriver.Hooks) (*configs.Config, error) { container := execdriver.InitContainer(c) if err := d.createIpc(container, c); err != nil { @@ -33,7 +34,7 @@ func (d *Driver) createContainer(c *execdriver.Command, hooks execdriver.Hooks) return nil, err } - if err := d.createNetwork(container, c, hooks); err != nil { + if err := d.createNetwork(ctx, container, c, hooks); err != nil { return nil, err } @@ -113,7 +114,7 @@ func generateIfaceName() (string, error) { return "", errors.New("Failed to find name for new interface") } -func (d *Driver) createNetwork(container *configs.Config, c *execdriver.Command, hooks execdriver.Hooks) error { +func (d *Driver) createNetwork(ctx context.Context, container *configs.Config, c *execdriver.Command, hooks execdriver.Hooks) error { if c.Network == nil { return nil } @@ -150,7 +151,7 @@ func (d *Driver) createNetwork(container *configs.Config, c *execdriver.Command, // non-blocking and return the correct result when read. chOOM := make(chan struct{}) close(chOOM) - if err := fnHook(&c.ProcessConfig, s.Pid, chOOM); err != nil { + if err := fnHook(ctx, &c.ProcessConfig, s.Pid, chOOM); err != nil { return err } } diff --git a/daemon/execdriver/native/driver.go b/daemon/execdriver/native/driver.go index 5a54d3130f..63843b8d79 100644 --- a/daemon/execdriver/native/driver.go +++ b/daemon/execdriver/native/driver.go @@ -14,6 +14,7 @@ import ( "time" "github.com/Sirupsen/logrus" + "github.com/docker/docker/context" "github.com/docker/docker/daemon/execdriver" "github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/pools" @@ -131,9 +132,9 @@ type execOutput struct { // Run implements the exec driver Driver interface, // it calls libcontainer APIs to run a container. -func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execdriver.Hooks) (execdriver.ExitStatus, error) { +func (d *Driver) Run(ctx context.Context, c *execdriver.Command, pipes *execdriver.Pipes, hooks execdriver.Hooks) (execdriver.ExitStatus, error) { // take the Command and populate the libcontainer.Config from it - container, err := d.createContainer(c, hooks) + container, err := d.createContainer(ctx, c, hooks) if err != nil { return execdriver.ExitStatus{ExitCode: -1}, err } @@ -174,7 +175,7 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execd p.Wait() return execdriver.ExitStatus{ExitCode: -1}, err } - hooks.Start(&c.ProcessConfig, pid, oom) + hooks.Start(ctx, &c.ProcessConfig, pid, oom) } waitF := p.Wait diff --git a/daemon/execdriver/native/exec.go b/daemon/execdriver/native/exec.go index b15e0cbd71..8327cc7650 100644 --- a/daemon/execdriver/native/exec.go +++ b/daemon/execdriver/native/exec.go @@ -8,6 +8,7 @@ import ( "os/exec" "syscall" + "github.com/docker/docker/context" "github.com/docker/docker/daemon/execdriver" "github.com/opencontainers/runc/libcontainer" // Blank import 'nsenter' so that init in that package will call c @@ -19,7 +20,7 @@ import ( // Exec implements the exec driver Driver interface, // it calls libcontainer APIs to execute a container. -func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, hooks execdriver.Hooks) (int, error) { +func (d *Driver) Exec(ctx context.Context, c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, hooks execdriver.Hooks) (int, error) { active := d.activeContainers[c.ID] if active == nil { return -1, fmt.Errorf("No active container exists with ID %s", c.ID) @@ -57,7 +58,7 @@ func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessCo // non-blocking and return the correct result when read. chOOM := make(chan struct{}) close(chOOM) - hooks.Start(&c.ProcessConfig, pid, chOOM) + hooks.Start(ctx, &c.ProcessConfig, pid, chOOM) } ps, err := p.Wait() diff --git a/daemon/execdriver/windows/exec.go b/daemon/execdriver/windows/exec.go index 5ea12a8cbb..bfa5a634ad 100644 --- a/daemon/execdriver/windows/exec.go +++ b/daemon/execdriver/windows/exec.go @@ -7,12 +7,13 @@ import ( "fmt" "github.com/Sirupsen/logrus" + "github.com/docker/docker/context" "github.com/docker/docker/daemon/execdriver" "github.com/microsoft/hcsshim" ) // Exec implements the exec driver Driver interface. -func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, hooks execdriver.Hooks) (int, error) { +func (d *Driver) Exec(ctx context.Context, c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, hooks execdriver.Hooks) (int, error) { var ( term execdriver.Terminal @@ -74,7 +75,7 @@ func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessCo // non-blocking and return the correct result when read. chOOM := make(chan struct{}) close(chOOM) - hooks.Start(&c.ProcessConfig, int(pid), chOOM) + hooks.Start(ctx, &c.ProcessConfig, int(pid), chOOM) } if exitCode, err = hcsshim.WaitForProcessInComputeSystem(c.ID, pid); err != nil { diff --git a/daemon/execdriver/windows/run.go b/daemon/execdriver/windows/run.go index dd47b0afca..49fa2b6a16 100644 --- a/daemon/execdriver/windows/run.go +++ b/daemon/execdriver/windows/run.go @@ -15,6 +15,7 @@ import ( "syscall" "github.com/Sirupsen/logrus" + "github.com/docker/docker/context" "github.com/docker/docker/daemon/execdriver" "github.com/microsoft/hcsshim" ) @@ -79,7 +80,7 @@ type containerInit struct { const defaultOwner = "docker" // Run implements the exec driver Driver interface -func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execdriver.Hooks) (execdriver.ExitStatus, error) { +func (d *Driver) Run(ctx context.Context, c *execdriver.Command, pipes *execdriver.Pipes, hooks execdriver.Hooks) (execdriver.ExitStatus, error) { var ( term execdriver.Terminal @@ -298,7 +299,7 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execd // non-blocking and return the correct result when read. chOOM := make(chan struct{}) close(chOOM) - hooks.Start(&c.ProcessConfig, int(pid), chOOM) + hooks.Start(ctx, &c.ProcessConfig, int(pid), chOOM) } var exitCode int32 diff --git a/daemon/export.go b/daemon/export.go index d470e5d584..60fdb7c16d 100644 --- a/daemon/export.go +++ b/daemon/export.go @@ -3,18 +3,19 @@ package daemon import ( "io" + "github.com/docker/docker/context" derr "github.com/docker/docker/errors" ) // ContainerExport writes the contents of the container to the given // writer. An error is returned if the container cannot be found. -func (daemon *Daemon) ContainerExport(name string, out io.Writer) error { - container, err := daemon.Get(name) +func (daemon *Daemon) ContainerExport(ctx context.Context, name string, out io.Writer) error { + container, err := daemon.Get(ctx, name) if err != nil { return err } - data, err := container.export() + data, err := container.export(ctx) if err != nil { return derr.ErrorCodeExportFailed.WithArgs(name, err) } diff --git a/daemon/image_delete.go b/daemon/image_delete.go index 5aff7d04cc..0f502dd76a 100644 --- a/daemon/image_delete.go +++ b/daemon/image_delete.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/docker/docker/api/types" + "github.com/docker/docker/context" derr "github.com/docker/docker/errors" "github.com/docker/docker/graph/tags" "github.com/docker/docker/image" @@ -50,10 +51,10 @@ import ( // FIXME: remove ImageDelete's dependency on Daemon, then move to the graph // package. This would require that we no longer need the daemon to determine // whether images are being used by a stopped or running container. -func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.ImageDelete, error) { +func (daemon *Daemon) ImageDelete(ctx context.Context, imageRef string, force, prune bool) ([]types.ImageDelete, error) { records := []types.ImageDelete{} - img, err := daemon.Repositories().LookupImage(imageRef) + img, err := daemon.Repositories(ctx).LookupImage(imageRef) if err != nil { return nil, err } @@ -64,8 +65,8 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I // first. We can only remove this reference if either force is // true, there are multiple repository references to this // image, or there are no containers using the given reference. - if !(force || daemon.imageHasMultipleRepositoryReferences(img.ID)) { - if container := daemon.getContainerUsingImage(img.ID); container != nil { + if !(force || daemon.imageHasMultipleRepositoryReferences(ctx, img.ID)) { + if container := daemon.getContainerUsingImage(ctx, img.ID); container != nil { // If we removed the repository reference then // this image would remain "dangling" and since // we really want to avoid that the client must @@ -74,14 +75,14 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I } } - parsedRef, err := daemon.removeImageRef(imageRef) + parsedRef, err := daemon.removeImageRef(ctx, imageRef) if err != nil { return nil, err } untaggedRecord := types.ImageDelete{Untagged: parsedRef} - daemon.EventsService.Log("untag", img.ID, "") + daemon.EventsService.Log(ctx, "untag", img.ID, "") records = append(records, untaggedRecord) removedRepositoryRef = true @@ -90,21 +91,21 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I // repository reference to the image then we will want to // remove that reference. // FIXME: Is this the behavior we want? - repoRefs := daemon.Repositories().ByID()[img.ID] + repoRefs := daemon.Repositories(ctx).ByID()[img.ID] if len(repoRefs) == 1 { - parsedRef, err := daemon.removeImageRef(repoRefs[0]) + parsedRef, err := daemon.removeImageRef(ctx, repoRefs[0]) if err != nil { return nil, err } untaggedRecord := types.ImageDelete{Untagged: parsedRef} - daemon.EventsService.Log("untag", img.ID, "") + daemon.EventsService.Log(ctx, "untag", img.ID, "") records = append(records, untaggedRecord) } } - return records, daemon.imageDeleteHelper(img, &records, force, prune, removedRepositoryRef) + return records, daemon.imageDeleteHelper(ctx, img, &records, force, prune, removedRepositoryRef) } // isImageIDPrefix returns whether the given possiblePrefix is a prefix of the @@ -115,14 +116,14 @@ func isImageIDPrefix(imageID, possiblePrefix string) bool { // imageHasMultipleRepositoryReferences returns whether there are multiple // repository references to the given imageID. -func (daemon *Daemon) imageHasMultipleRepositoryReferences(imageID string) bool { - return len(daemon.Repositories().ByID()[imageID]) > 1 +func (daemon *Daemon) imageHasMultipleRepositoryReferences(ctx context.Context, imageID string) bool { + return len(daemon.Repositories(ctx).ByID()[imageID]) > 1 } // getContainerUsingImage returns a container that was created using the given // imageID. Returns nil if there is no such container. -func (daemon *Daemon) getContainerUsingImage(imageID string) *Container { - for _, container := range daemon.List() { +func (daemon *Daemon) getContainerUsingImage(ctx context.Context, imageID string) *Container { + for _, container := range daemon.List(ctx) { if container.ImageID == imageID { return container } @@ -136,7 +137,7 @@ func (daemon *Daemon) getContainerUsingImage(imageID string) *Container { // repositoryRef must not be an image ID but a repository name followed by an // optional tag or digest reference. If tag or digest is omitted, the default // tag is used. Returns the resolved image reference and an error. -func (daemon *Daemon) removeImageRef(repositoryRef string) (string, error) { +func (daemon *Daemon) removeImageRef(ctx context.Context, repositoryRef string) (string, error) { repository, ref := parsers.ParseRepositoryTag(repositoryRef) if ref == "" { ref = tags.DefaultTag @@ -145,7 +146,7 @@ func (daemon *Daemon) removeImageRef(repositoryRef string) (string, error) { // Ignore the boolean value returned, as far as we're concerned, this // is an idempotent operation and it's okay if the reference didn't // exist in the first place. - _, err := daemon.Repositories().Delete(repository, ref) + _, err := daemon.Repositories(ctx).Delete(repository, ref) return utils.ImageReference(repository, ref), err } @@ -155,18 +156,18 @@ func (daemon *Daemon) removeImageRef(repositoryRef string) (string, error) { // on the first encountered error. Removed references are logged to this // daemon's event service. An "Untagged" types.ImageDelete is added to the // given list of records. -func (daemon *Daemon) removeAllReferencesToImageID(imgID string, records *[]types.ImageDelete) error { - imageRefs := daemon.Repositories().ByID()[imgID] +func (daemon *Daemon) removeAllReferencesToImageID(ctx context.Context, imgID string, records *[]types.ImageDelete) error { + imageRefs := daemon.Repositories(ctx).ByID()[imgID] for _, imageRef := range imageRefs { - parsedRef, err := daemon.removeImageRef(imageRef) + parsedRef, err := daemon.removeImageRef(ctx, imageRef) if err != nil { return err } untaggedRecord := types.ImageDelete{Untagged: parsedRef} - daemon.EventsService.Log("untag", imgID, "") + daemon.EventsService.Log(ctx, "untag", imgID, "") *records = append(*records, untaggedRecord) } @@ -203,11 +204,11 @@ func (idc *imageDeleteConflict) Error() string { // conflict is encountered, it will be returned immediately without deleting // the image. If quiet is true, any encountered conflicts will be ignored and // the function will return nil immediately without deleting the image. -func (daemon *Daemon) imageDeleteHelper(img *image.Image, records *[]types.ImageDelete, force, prune, quiet bool) error { +func (daemon *Daemon) imageDeleteHelper(ctx context.Context, img *image.Image, records *[]types.ImageDelete, force, prune, quiet bool) error { // First, determine if this image has any conflicts. Ignore soft conflicts // if force is true. - if conflict := daemon.checkImageDeleteConflict(img, force); conflict != nil { - if quiet && !daemon.imageIsDangling(img) { + if conflict := daemon.checkImageDeleteConflict(ctx, img, force); conflict != nil { + if quiet && !daemon.imageIsDangling(ctx, img) { // Ignore conflicts UNLESS the image is "dangling" in // which case we want the user to know. return nil @@ -219,15 +220,15 @@ func (daemon *Daemon) imageDeleteHelper(img *image.Image, records *[]types.Image } // Delete all repository tag/digest references to this image. - if err := daemon.removeAllReferencesToImageID(img.ID, records); err != nil { + if err := daemon.removeAllReferencesToImageID(ctx, img.ID, records); err != nil { return err } - if err := daemon.Graph().Delete(img.ID); err != nil { + if err := daemon.Graph(ctx).Delete(img.ID); err != nil { return err } - daemon.EventsService.Log("delete", img.ID, "") + daemon.EventsService.Log(ctx, "delete", img.ID, "") *records = append(*records, types.ImageDelete{Deleted: img.ID}) if !prune || img.Parent == "" { @@ -237,14 +238,14 @@ func (daemon *Daemon) imageDeleteHelper(img *image.Image, records *[]types.Image // We need to prune the parent image. This means delete it if there are // no tags/digests referencing it and there are no containers using it ( // either running or stopped). - parentImg, err := daemon.Graph().Get(img.Parent) + parentImg, err := daemon.Graph(ctx).Get(img.Parent) if err != nil { return derr.ErrorCodeImgNoParent.WithArgs(err) } // Do not force prunings, but do so quietly (stopping on any encountered // conflicts). - return daemon.imageDeleteHelper(parentImg, records, false, true, true) + return daemon.imageDeleteHelper(ctx, parentImg, records, false, true, true) } // checkImageDeleteConflict determines whether there are any conflicts @@ -253,9 +254,9 @@ func (daemon *Daemon) imageDeleteHelper(img *image.Image, records *[]types.Image // using the image. A soft conflict is any tags/digest referencing the given // image or any stopped container using the image. If ignoreSoftConflicts is // true, this function will not check for soft conflict conditions. -func (daemon *Daemon) checkImageDeleteConflict(img *image.Image, ignoreSoftConflicts bool) *imageDeleteConflict { +func (daemon *Daemon) checkImageDeleteConflict(ctx context.Context, img *image.Image, ignoreSoftConflicts bool) *imageDeleteConflict { // Check for hard conflicts first. - if conflict := daemon.checkImageDeleteHardConflict(img); conflict != nil { + if conflict := daemon.checkImageDeleteHardConflict(ctx, img); conflict != nil { return conflict } @@ -265,12 +266,12 @@ func (daemon *Daemon) checkImageDeleteConflict(img *image.Image, ignoreSoftConfl return nil } - return daemon.checkImageDeleteSoftConflict(img) + return daemon.checkImageDeleteSoftConflict(ctx, img) } -func (daemon *Daemon) checkImageDeleteHardConflict(img *image.Image) *imageDeleteConflict { +func (daemon *Daemon) checkImageDeleteHardConflict(ctx context.Context, img *image.Image) *imageDeleteConflict { // Check if the image ID is being used by a pull or build. - if daemon.Graph().IsHeld(img.ID) { + if daemon.Graph(ctx).IsHeld(img.ID) { return &imageDeleteConflict{ hard: true, imgID: img.ID, @@ -279,7 +280,7 @@ func (daemon *Daemon) checkImageDeleteHardConflict(img *image.Image) *imageDelet } // Check if the image has any descendent images. - if daemon.Graph().HasChildren(img) { + if daemon.Graph(ctx).HasChildren(img) { return &imageDeleteConflict{ hard: true, imgID: img.ID, @@ -288,7 +289,7 @@ func (daemon *Daemon) checkImageDeleteHardConflict(img *image.Image) *imageDelet } // Check if any running container is using the image. - for _, container := range daemon.List() { + for _, container := range daemon.List(ctx) { if !container.IsRunning() { // Skip this until we check for soft conflicts later. continue @@ -306,9 +307,9 @@ func (daemon *Daemon) checkImageDeleteHardConflict(img *image.Image) *imageDelet return nil } -func (daemon *Daemon) checkImageDeleteSoftConflict(img *image.Image) *imageDeleteConflict { +func (daemon *Daemon) checkImageDeleteSoftConflict(ctx context.Context, img *image.Image) *imageDeleteConflict { // Check if any repository tags/digest reference this image. - if daemon.Repositories().HasReferences(img) { + if daemon.Repositories(ctx).HasReferences(img) { return &imageDeleteConflict{ imgID: img.ID, message: "image is referenced in one or more repositories", @@ -316,7 +317,7 @@ func (daemon *Daemon) checkImageDeleteSoftConflict(img *image.Image) *imageDelet } // Check if any stopped containers reference this image. - for _, container := range daemon.List() { + for _, container := range daemon.List(ctx) { if container.IsRunning() { // Skip this as it was checked above in hard conflict conditions. continue @@ -336,6 +337,6 @@ func (daemon *Daemon) checkImageDeleteSoftConflict(img *image.Image) *imageDelet // imageIsDangling returns whether the given image is "dangling" which means // that there are no repository references to the given image and it has no // child images. -func (daemon *Daemon) imageIsDangling(img *image.Image) bool { - return !(daemon.Repositories().HasReferences(img) || daemon.Graph().HasChildren(img)) +func (daemon *Daemon) imageIsDangling(ctx context.Context, img *image.Image) bool { + return !(daemon.Repositories(ctx).HasReferences(img) || daemon.Graph(ctx).HasChildren(img)) } diff --git a/daemon/info.go b/daemon/info.go index 447e8c7789..582ad58e59 100644 --- a/daemon/info.go +++ b/daemon/info.go @@ -8,6 +8,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/api/types" "github.com/docker/docker/autogen/dockerversion" + "github.com/docker/docker/context" "github.com/docker/docker/pkg/fileutils" "github.com/docker/docker/pkg/parsers/kernel" "github.com/docker/docker/pkg/parsers/operatingsystem" @@ -18,8 +19,8 @@ import ( ) // SystemInfo returns information about the host server the daemon is running on. -func (daemon *Daemon) SystemInfo() (*types.Info, error) { - images := daemon.Graph().Map() +func (daemon *Daemon) SystemInfo(ctx context.Context) (*types.Info, error) { + images := daemon.Graph(ctx).Map() var imgcount int if images == nil { imgcount = 0 @@ -65,10 +66,10 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) { v := &types.Info{ ID: daemon.ID, - Containers: len(daemon.List()), + Containers: len(daemon.List(ctx)), Images: imgcount, - Driver: daemon.GraphDriver().String(), - DriverStatus: daemon.GraphDriver().Status(), + Driver: daemon.GraphDriver(ctx).String(), + DriverStatus: daemon.GraphDriver(ctx).Status(), IPv4Forwarding: !sysInfo.IPv4ForwardingDisabled, BridgeNfIptables: !sysInfo.BridgeNfCallIptablesDisabled, BridgeNfIP6tables: !sysInfo.BridgeNfCallIP6tablesDisabled, @@ -76,7 +77,7 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) { NFd: fileutils.GetTotalUsedFds(), NGoroutines: runtime.NumGoroutine(), SystemTime: time.Now().Format(time.RFC3339Nano), - ExecutionDriver: daemon.ExecutionDriver().Name(), + ExecutionDriver: daemon.ExecutionDriver(ctx).Name(), LoggingDriver: daemon.defaultLogConfig.Type, NEventsListener: daemon.EventsService.SubscribersCount(), KernelVersion: kernelVersion, diff --git a/daemon/inspect.go b/daemon/inspect.go index 6335de8f8f..4bca138ec7 100644 --- a/daemon/inspect.go +++ b/daemon/inspect.go @@ -5,13 +5,14 @@ import ( "time" "github.com/docker/docker/api/types" + "github.com/docker/docker/context" ) // ContainerInspect returns low-level information about a // container. Returns an error if the container cannot be found, or if // there is an error getting the data. -func (daemon *Daemon) ContainerInspect(name string) (*types.ContainerJSON, error) { - container, err := daemon.Get(name) +func (daemon *Daemon) ContainerInspect(ctx context.Context, name string) (*types.ContainerJSON, error) { + container, err := daemon.Get(ctx, name) if err != nil { return nil, err } @@ -19,7 +20,7 @@ func (daemon *Daemon) ContainerInspect(name string) (*types.ContainerJSON, error container.Lock() defer container.Unlock() - base, err := daemon.getInspectData(container) + base, err := daemon.getInspectData(ctx, container) if err != nil { return nil, err } @@ -30,8 +31,8 @@ func (daemon *Daemon) ContainerInspect(name string) (*types.ContainerJSON, error } // ContainerInspect120 serializes the master version of a container into a json type. -func (daemon *Daemon) ContainerInspect120(name string) (*types.ContainerJSON120, error) { - container, err := daemon.Get(name) +func (daemon *Daemon) ContainerInspect120(ctx context.Context, name string) (*types.ContainerJSON120, error) { + container, err := daemon.Get(ctx, name) if err != nil { return nil, err } @@ -39,7 +40,7 @@ func (daemon *Daemon) ContainerInspect120(name string) (*types.ContainerJSON120, container.Lock() defer container.Unlock() - base, err := daemon.getInspectData(container) + base, err := daemon.getInspectData(ctx, container) if err != nil { return nil, err } @@ -53,11 +54,11 @@ func (daemon *Daemon) ContainerInspect120(name string) (*types.ContainerJSON120, return &types.ContainerJSON120{base, mountPoints, config}, nil } -func (daemon *Daemon) getInspectData(container *Container) (*types.ContainerJSONBase, error) { +func (daemon *Daemon) getInspectData(ctx context.Context, container *Container) (*types.ContainerJSONBase, error) { // make a copy to play with hostConfig := *container.hostConfig - if children, err := daemon.children(container.Name); err == nil { + if children, err := daemon.children(ctx, container.Name); err == nil { for linkAlias, child := range children { hostConfig.Links = append(hostConfig.Links, fmt.Sprintf("%s:%s", child.Name, linkAlias)) } @@ -120,7 +121,7 @@ func (daemon *Daemon) getInspectData(container *Container) (*types.ContainerJSON // ContainerExecInspect returns low-level information about the exec // command. An error is returned if the exec cannot be found. -func (daemon *Daemon) ContainerExecInspect(id string) (*ExecConfig, error) { +func (daemon *Daemon) ContainerExecInspect(ctx context.Context, id string) (*ExecConfig, error) { eConfig, err := daemon.getExecConfig(id) if err != nil { return nil, err @@ -130,7 +131,7 @@ func (daemon *Daemon) ContainerExecInspect(id string) (*ExecConfig, error) { // VolumeInspect looks up a volume by name. An error is returned if // the volume cannot be found. -func (daemon *Daemon) VolumeInspect(name string) (*types.Volume, error) { +func (daemon *Daemon) VolumeInspect(ctx context.Context, name string) (*types.Volume, error) { v, err := daemon.volumes.Get(name) if err != nil { return nil, err diff --git a/daemon/inspect_unix.go b/daemon/inspect_unix.go index 088e830fed..b21c3d5e29 100644 --- a/daemon/inspect_unix.go +++ b/daemon/inspect_unix.go @@ -2,7 +2,10 @@ package daemon -import "github.com/docker/docker/api/types" +import ( + "github.com/docker/docker/api/types" + "github.com/docker/docker/context" +) // This sets platform-specific fields func setPlatformSpecificContainerFields(container *Container, contJSONBase *types.ContainerJSONBase) *types.ContainerJSONBase { @@ -15,8 +18,8 @@ func setPlatformSpecificContainerFields(container *Container, contJSONBase *type } // ContainerInspectPre120 gets containers for pre 1.20 APIs. -func (daemon *Daemon) ContainerInspectPre120(name string) (*types.ContainerJSONPre120, error) { - container, err := daemon.Get(name) +func (daemon *Daemon) ContainerInspectPre120(ctx context.Context, name string) (*types.ContainerJSONPre120, error) { + container, err := daemon.Get(ctx, name) if err != nil { return nil, err } @@ -24,7 +27,7 @@ func (daemon *Daemon) ContainerInspectPre120(name string) (*types.ContainerJSONP container.Lock() defer container.Unlock() - base, err := daemon.getInspectData(container) + base, err := daemon.getInspectData(ctx, container) if err != nil { return nil, err } diff --git a/daemon/inspect_windows.go b/daemon/inspect_windows.go index 34dceca609..9d48133049 100644 --- a/daemon/inspect_windows.go +++ b/daemon/inspect_windows.go @@ -1,6 +1,9 @@ package daemon -import "github.com/docker/docker/api/types" +import ( + "github.com/docker/docker/api/types" + "github.com/docker/docker/context" +) // This sets platform-specific fields func setPlatformSpecificContainerFields(container *Container, contJSONBase *types.ContainerJSONBase) *types.ContainerJSONBase { @@ -12,6 +15,6 @@ func addMountPoints(container *Container) []types.MountPoint { } // ContainerInspectPre120 get containers for pre 1.20 APIs. -func (daemon *Daemon) ContainerInspectPre120(name string) (*types.ContainerJSON, error) { - return daemon.ContainerInspect(name) +func (daemon *Daemon) ContainerInspectPre120(ctx context.Context, name string) (*types.ContainerJSON, error) { + return daemon.ContainerInspect(ctx, name) } diff --git a/daemon/kill.go b/daemon/kill.go index 7e99d370a0..d340e40e01 100644 --- a/daemon/kill.go +++ b/daemon/kill.go @@ -1,25 +1,29 @@ package daemon -import "syscall" +import ( + "syscall" + + "github.com/docker/docker/context" +) // ContainerKill send signal to the container // If no signal is given (sig 0), then Kill with SIGKILL and wait // for the container to exit. // If a signal is given, then just send it to the container and return. -func (daemon *Daemon) ContainerKill(name string, sig uint64) error { - container, err := daemon.Get(name) +func (daemon *Daemon) ContainerKill(ctx context.Context, name string, sig uint64) error { + container, err := daemon.Get(ctx, name) if err != nil { return err } // If no signal is passed, or SIGKILL, perform regular Kill (SIGKILL + wait()) if sig == 0 || syscall.Signal(sig) == syscall.SIGKILL { - if err := container.Kill(); err != nil { + if err := container.Kill(ctx); err != nil { return err } } else { // Otherwise, just send the requested signal - if err := container.killSig(int(sig)); err != nil { + if err := container.killSig(ctx, int(sig)); err != nil { return err } } diff --git a/daemon/list.go b/daemon/list.go index 75ec88de42..78d2ca9e72 100644 --- a/daemon/list.go +++ b/daemon/list.go @@ -8,6 +8,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/api/types" + "github.com/docker/docker/context" derr "github.com/docker/docker/errors" "github.com/docker/docker/image" "github.com/docker/docker/pkg/graphdb" @@ -20,7 +21,7 @@ type iterationAction int // containerReducer represents a reducer for a container. // Returns the object to serialize by the api. -type containerReducer func(*Container, *listContext) (*types.Container, error) +type containerReducer func(context.Context, *Container, *listContext) (*types.Container, error) const ( // includeContainer is the action to include a container in the reducer. @@ -35,7 +36,7 @@ const ( var errStopIteration = errors.New("container list iteration stopped") // List returns an array of all containers registered in the daemon. -func (daemon *Daemon) List() []*Container { +func (daemon *Daemon) List(ctx context.Context) []*Container { return daemon.containers.List() } @@ -79,21 +80,21 @@ type listContext struct { } // Containers returns the list of containers to show given the user's filtering. -func (daemon *Daemon) Containers(config *ContainersConfig) ([]*types.Container, error) { - return daemon.reduceContainers(config, daemon.transformContainer) +func (daemon *Daemon) Containers(ctx context.Context, config *ContainersConfig) ([]*types.Container, error) { + return daemon.reduceContainers(ctx, config, daemon.transformContainer) } // reduceContainer parses the user filtering and generates the list of containers to return based on a reducer. -func (daemon *Daemon) reduceContainers(config *ContainersConfig, reducer containerReducer) ([]*types.Container, error) { +func (daemon *Daemon) reduceContainers(ctx context.Context, config *ContainersConfig, reducer containerReducer) ([]*types.Container, error) { containers := []*types.Container{} - ctx, err := daemon.foldFilter(config) + fctx, err := daemon.foldFilter(ctx, config) if err != nil { return nil, err } - for _, container := range daemon.List() { - t, err := daemon.reducePsContainer(container, ctx, reducer) + for _, container := range daemon.List(ctx) { + t, err := daemon.reducePsContainer(ctx, container, fctx, reducer) if err != nil { if err != errStopIteration { return nil, err @@ -102,19 +103,19 @@ func (daemon *Daemon) reduceContainers(config *ContainersConfig, reducer contain } if t != nil { containers = append(containers, t) - ctx.idx++ + fctx.idx++ } } return containers, nil } // reducePsContainer is the basic representation for a container as expected by the ps command. -func (daemon *Daemon) reducePsContainer(container *Container, ctx *listContext, reducer containerReducer) (*types.Container, error) { +func (daemon *Daemon) reducePsContainer(ctx context.Context, container *Container, lctx *listContext, reducer containerReducer) (*types.Container, error) { container.Lock() defer container.Unlock() // filter containers to return - action := includeContainerInList(container, ctx) + action := includeContainerInList(container, lctx) switch action { case excludeContainer: return nil, nil @@ -123,11 +124,11 @@ func (daemon *Daemon) reducePsContainer(container *Container, ctx *listContext, } // transform internal container struct into api structs - return reducer(container, ctx) + return reducer(ctx, container, lctx) } // foldFilter generates the container filter based in the user's filtering options. -func (daemon *Daemon) foldFilter(config *ContainersConfig) (*listContext, error) { +func (daemon *Daemon) foldFilter(ctx context.Context, config *ContainersConfig) (*listContext, error) { psFilters, err := filters.FromParam(config.Filters) if err != nil { return nil, err @@ -159,11 +160,11 @@ func (daemon *Daemon) foldFilter(config *ContainersConfig) (*listContext, error) var ancestorFilter bool if ancestors, ok := psFilters["ancestor"]; ok { ancestorFilter = true - byParents := daemon.Graph().ByParent() + byParents := daemon.Graph(ctx).ByParent() // The idea is to walk the graph down the most "efficient" way. for _, ancestor := range ancestors { // First, get the imageId of the ancestor filter (yay) - image, err := daemon.Repositories().LookupImage(ancestor) + image, err := daemon.Repositories(ctx).LookupImage(ancestor) if err != nil { logrus.Warnf("Error while looking up for image %v", ancestor) continue @@ -185,14 +186,14 @@ func (daemon *Daemon) foldFilter(config *ContainersConfig) (*listContext, error) var beforeCont, sinceCont *Container if config.Before != "" { - beforeCont, err = daemon.Get(config.Before) + beforeCont, err = daemon.Get(ctx, config.Before) if err != nil { return nil, err } } if config.Since != "" { - sinceCont, err = daemon.Get(config.Since) + sinceCont, err = daemon.Get(ctx, config.Since) if err != nil { return nil, err } @@ -286,13 +287,13 @@ func includeContainerInList(container *Container, ctx *listContext) iterationAct } // transformContainer generates the container type expected by the docker ps command. -func (daemon *Daemon) transformContainer(container *Container, ctx *listContext) (*types.Container, error) { +func (daemon *Daemon) transformContainer(ctx context.Context, container *Container, lctx *listContext) (*types.Container, error) { newC := &types.Container{ ID: container.ID, - Names: ctx.names[container.ID], + Names: lctx.names[container.ID], } - img, err := daemon.Repositories().LookupImage(container.Config.Image) + img, err := daemon.Repositories(ctx).LookupImage(container.Config.Image) if err != nil { // If the image can no longer be found by its original reference, // it makes sense to show the ID instead of a stale reference. @@ -349,8 +350,8 @@ func (daemon *Daemon) transformContainer(container *Container, ctx *listContext) } } - if ctx.Size { - sizeRw, sizeRootFs := container.getSize() + if lctx.Size { + sizeRw, sizeRootFs := container.getSize(ctx) newC.SizeRw = sizeRw newC.SizeRootFs = sizeRootFs } @@ -361,7 +362,7 @@ func (daemon *Daemon) transformContainer(container *Container, ctx *listContext) // Volumes lists known volumes, using the filter to restrict the range // of volumes returned. -func (daemon *Daemon) Volumes(filter string) ([]*types.Volume, error) { +func (daemon *Daemon) Volumes(ctx context.Context, filter string) ([]*types.Volume, error) { var volumesOut []*types.Volume volFilters, err := filters.FromParam(filter) if err != nil { diff --git a/daemon/logs.go b/daemon/logs.go index d52a5dc527..094b971958 100644 --- a/daemon/logs.go +++ b/daemon/logs.go @@ -6,6 +6,7 @@ import ( "time" "github.com/Sirupsen/logrus" + "github.com/docker/docker/context" "github.com/docker/docker/daemon/logger" derr "github.com/docker/docker/errors" "github.com/docker/docker/pkg/stdcopy" @@ -30,7 +31,7 @@ type ContainerLogsConfig struct { // ContainerLogs hooks up a container's stdout and stderr streams // configured with the given struct. -func (daemon *Daemon) ContainerLogs(container *Container, config *ContainerLogsConfig) error { +func (daemon *Daemon) ContainerLogs(ctx context.Context, container *Container, config *ContainerLogsConfig) error { if !(config.UseStdout || config.UseStderr) { return derr.ErrorCodeNeedStream } diff --git a/daemon/monitor.go b/daemon/monitor.go index 4af0d2a2fd..49ef2a5bf7 100644 --- a/daemon/monitor.go +++ b/daemon/monitor.go @@ -7,6 +7,7 @@ import ( "time" "github.com/Sirupsen/logrus" + "github.com/docker/docker/context" "github.com/docker/docker/daemon/execdriver" "github.com/docker/docker/pkg/stringid" "github.com/docker/docker/runconfig" @@ -84,9 +85,9 @@ func (m *containerMonitor) ExitOnNext() { // Close closes the container's resources such as networking allocations and // unmounts the contatiner's root filesystem -func (m *containerMonitor) Close() error { +func (m *containerMonitor) Close(ctx context.Context) error { // Cleanup networking and mounts - m.container.cleanup() + m.container.cleanup(ctx) // FIXME: here is race condition between two RUN instructions in Dockerfile // because they share same runconfig and change image. Must be fixed @@ -101,7 +102,7 @@ func (m *containerMonitor) Close() error { } // Start starts the containers process and monitors it according to the restart policy -func (m *containerMonitor) Start() error { +func (m *containerMonitor) Start(ctx context.Context) error { var ( err error exitStatus execdriver.ExitStatus @@ -117,7 +118,7 @@ func (m *containerMonitor) Start() error { m.container.setStopped(&exitStatus) defer m.container.Unlock() } - m.Close() + m.Close(ctx) }() // reset stopped flag if m.container.HasBeenManuallyStopped { @@ -138,11 +139,11 @@ func (m *containerMonitor) Start() error { pipes := execdriver.NewPipes(m.container.stdin, m.container.stdout, m.container.stderr, m.container.Config.OpenStdin) - m.container.logEvent("start") + m.container.logEvent(ctx, "start") m.lastStartTime = time.Now() - if exitStatus, err = m.container.daemon.run(m.container, pipes, m.callback); err != nil { + if exitStatus, err = m.container.daemon.run(ctx, m.container, pipes, m.callback); err != nil { // if we receive an internal error from the initial start of a container then lets // return it instead of entering the restart loop if m.container.RestartCount == 0 { @@ -162,7 +163,7 @@ func (m *containerMonitor) Start() error { if m.shouldRestart(exitStatus.ExitCode) { m.container.setRestarting(&exitStatus) - m.container.logEvent("die") + m.container.logEvent(ctx, "die") m.resetContainer(true) // sleep with a small time increment between each restart to help avoid issues cased by quickly @@ -177,7 +178,7 @@ func (m *containerMonitor) Start() error { continue } - m.container.logEvent("die") + m.container.logEvent(ctx, "die") m.resetContainer(true) return err } @@ -245,11 +246,11 @@ func (m *containerMonitor) shouldRestart(exitCode int) bool { // callback ensures that the container's state is properly updated after we // received ack from the execution drivers -func (m *containerMonitor) callback(processConfig *execdriver.ProcessConfig, pid int, chOOM <-chan struct{}) error { +func (m *containerMonitor) callback(ctx context.Context, processConfig *execdriver.ProcessConfig, pid int, chOOM <-chan struct{}) error { go func() { _, ok := <-chOOM if ok { - m.container.logEvent("oom") + m.container.logEvent(ctx, "oom") } }() diff --git a/daemon/pause.go b/daemon/pause.go index 385e93f9f9..e9f8d70f18 100644 --- a/daemon/pause.go +++ b/daemon/pause.go @@ -1,17 +1,18 @@ package daemon import ( + "github.com/docker/docker/context" derr "github.com/docker/docker/errors" ) // ContainerPause pauses a container -func (daemon *Daemon) ContainerPause(name string) error { - container, err := daemon.Get(name) +func (daemon *Daemon) ContainerPause(ctx context.Context, name string) error { + container, err := daemon.Get(ctx, name) if err != nil { return err } - if err := container.pause(); err != nil { + if err := container.pause(ctx); err != nil { return derr.ErrorCodePauseError.WithArgs(name, err) } diff --git a/daemon/rename.go b/daemon/rename.go index de80e609f1..7595881605 100644 --- a/daemon/rename.go +++ b/daemon/rename.go @@ -1,18 +1,19 @@ package daemon import ( + "github.com/docker/docker/context" derr "github.com/docker/docker/errors" ) // ContainerRename changes the name of a container, using the oldName // to find the container. An error is returned if newName is already // reserved. -func (daemon *Daemon) ContainerRename(oldName, newName string) error { +func (daemon *Daemon) ContainerRename(ctx context.Context, oldName, newName string) error { if oldName == "" || newName == "" { return derr.ErrorCodeEmptyRename } - container, err := daemon.Get(oldName) + container, err := daemon.Get(ctx, oldName) if err != nil { return err } @@ -21,7 +22,7 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) error { container.Lock() defer container.Unlock() - if newName, err = daemon.reserveName(container.ID, newName); err != nil { + if newName, err = daemon.reserveName(ctx, container.ID, newName); err != nil { return derr.ErrorCodeRenameTaken.WithArgs(err) } @@ -29,7 +30,7 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) error { undo := func() { container.Name = oldName - daemon.reserveName(container.ID, oldName) + daemon.reserveName(ctx, container.ID, oldName) daemon.containerGraphDB.Delete(newName) } @@ -43,6 +44,6 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) error { return err } - container.logEvent("rename") + container.logEvent(ctx, "rename") return nil } diff --git a/daemon/resize.go b/daemon/resize.go index 199bc48b43..3291e0855d 100644 --- a/daemon/resize.go +++ b/daemon/resize.go @@ -1,20 +1,24 @@ package daemon +import ( + "github.com/docker/docker/context" +) + // ContainerResize changes the size of the TTY of the process running // in the container with the given name to the given height and width. -func (daemon *Daemon) ContainerResize(name string, height, width int) error { - container, err := daemon.Get(name) +func (daemon *Daemon) ContainerResize(ctx context.Context, name string, height, width int) error { + container, err := daemon.Get(ctx, name) if err != nil { return err } - return container.Resize(height, width) + return container.Resize(ctx, height, width) } // ContainerExecResize changes the size of the TTY of the process // running in the exec with the given name to the given height and // width. -func (daemon *Daemon) ContainerExecResize(name string, height, width int) error { +func (daemon *Daemon) ContainerExecResize(ctx context.Context, name string, height, width int) error { ExecConfig, err := daemon.getExecConfig(name) if err != nil { return err diff --git a/daemon/restart.go b/daemon/restart.go index 86ec88dbb1..99e4c605eb 100644 --- a/daemon/restart.go +++ b/daemon/restart.go @@ -1,6 +1,7 @@ package daemon import ( + "github.com/docker/docker/context" derr "github.com/docker/docker/errors" ) @@ -10,12 +11,12 @@ import ( // timeout, ContainerRestart will wait forever until a graceful // stop. Returns an error if the container cannot be found, or if // there is an underlying error at any stage of the restart. -func (daemon *Daemon) ContainerRestart(name string, seconds int) error { - container, err := daemon.Get(name) +func (daemon *Daemon) ContainerRestart(ctx context.Context, name string, seconds int) error { + container, err := daemon.Get(ctx, name) if err != nil { return err } - if err := container.Restart(seconds); err != nil { + if err := container.Restart(ctx, seconds); err != nil { return derr.ErrorCodeCantRestart.WithArgs(name, err) } return nil diff --git a/daemon/start.go b/daemon/start.go index 6eec10da28..8bd3c20a4a 100644 --- a/daemon/start.go +++ b/daemon/start.go @@ -3,14 +3,15 @@ package daemon import ( "runtime" + "github.com/docker/docker/context" derr "github.com/docker/docker/errors" "github.com/docker/docker/runconfig" "github.com/docker/docker/utils" ) // ContainerStart starts a container. -func (daemon *Daemon) ContainerStart(name string, hostConfig *runconfig.HostConfig) error { - container, err := daemon.Get(name) +func (daemon *Daemon) ContainerStart(ctx context.Context, name string, hostConfig *runconfig.HostConfig) error { + container, err := daemon.Get(ctx, name) if err != nil { return err } @@ -28,7 +29,7 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *runconfig.HostConf // This is kept for backward compatibility - hostconfig should be passed when // creating a container, not during start. if hostConfig != nil { - if err := daemon.setHostConfig(container, hostConfig); err != nil { + if err := daemon.setHostConfig(ctx, container, hostConfig); err != nil { return err } } @@ -40,11 +41,11 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *runconfig.HostConf // check if hostConfig is in line with the current system settings. // It may happen cgroups are umounted or the like. - if _, err = daemon.verifyContainerSettings(container.hostConfig, nil); err != nil { + if _, err = daemon.verifyContainerSettings(ctx, container.hostConfig, nil); err != nil { return err } - if err := container.Start(); err != nil { + if err := container.Start(ctx); err != nil { return derr.ErrorCodeCantStart.WithArgs(name, utils.GetErrorMessage(err)) } diff --git a/daemon/stats.go b/daemon/stats.go index bdf4c57078..2032d89f69 100644 --- a/daemon/stats.go +++ b/daemon/stats.go @@ -5,6 +5,7 @@ import ( "io" "github.com/docker/docker/api/types" + "github.com/docker/docker/context" "github.com/docker/docker/daemon/execdriver" "github.com/docker/docker/pkg/version" "github.com/docker/libnetwork/osl" @@ -22,9 +23,9 @@ type ContainerStatsConfig struct { // ContainerStats writes information about the container to the stream // given in the config object. -func (daemon *Daemon) ContainerStats(prefixOrName string, config *ContainerStatsConfig) error { +func (daemon *Daemon) ContainerStats(ctx context.Context, prefixOrName string, config *ContainerStatsConfig) error { - container, err := daemon.Get(prefixOrName) + container, err := daemon.Get(ctx, prefixOrName) if err != nil { return err } diff --git a/daemon/stop.go b/daemon/stop.go index 9e33315216..a6ddb91140 100644 --- a/daemon/stop.go +++ b/daemon/stop.go @@ -1,6 +1,7 @@ package daemon import ( + "github.com/docker/docker/context" derr "github.com/docker/docker/errors" ) @@ -10,15 +11,15 @@ import ( // will wait for a graceful termination. An error is returned if the // container is not found, is already stopped, or if there is a // problem stopping the container. -func (daemon *Daemon) ContainerStop(name string, seconds int) error { - container, err := daemon.Get(name) +func (daemon *Daemon) ContainerStop(ctx context.Context, name string, seconds int) error { + container, err := daemon.Get(ctx, name) if err != nil { return err } if !container.IsRunning() { return derr.ErrorCodeStopped } - if err := container.Stop(seconds); err != nil { + if err := container.Stop(ctx, seconds); err != nil { return derr.ErrorCodeCantStop.WithArgs(name, err) } return nil diff --git a/daemon/top_unix.go b/daemon/top_unix.go index 4112fbcbb1..84f249066c 100644 --- a/daemon/top_unix.go +++ b/daemon/top_unix.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/docker/docker/api/types" + "github.com/docker/docker/context" derr "github.com/docker/docker/errors" ) @@ -16,12 +17,12 @@ import ( // "-ef" if no args are given. An error is returned if the container // is not found, or is not running, or if there are any problems // running ps, or parsing the output. -func (daemon *Daemon) ContainerTop(name string, psArgs string) (*types.ContainerProcessList, error) { +func (daemon *Daemon) ContainerTop(ctx context.Context, name string, psArgs string) (*types.ContainerProcessList, error) { if psArgs == "" { psArgs = "-ef" } - container, err := daemon.Get(name) + container, err := daemon.Get(ctx, name) if err != nil { return nil, err } @@ -30,7 +31,7 @@ func (daemon *Daemon) ContainerTop(name string, psArgs string) (*types.Container return nil, derr.ErrorCodeNotRunning.WithArgs(name) } - pids, err := daemon.ExecutionDriver().GetPidsForContainer(container.ID) + pids, err := daemon.ExecutionDriver(ctx).GetPidsForContainer(container.ID) if err != nil { return nil, err } @@ -76,6 +77,6 @@ func (daemon *Daemon) ContainerTop(name string, psArgs string) (*types.Container } } } - container.logEvent("top") + container.logEvent(ctx, "top") return procList, nil } diff --git a/daemon/top_windows.go b/daemon/top_windows.go index f224b2e2d2..bf061acb02 100644 --- a/daemon/top_windows.go +++ b/daemon/top_windows.go @@ -2,10 +2,11 @@ package daemon import ( "github.com/docker/docker/api/types" + "github.com/docker/docker/context" derr "github.com/docker/docker/errors" ) // ContainerTop is not supported on Windows and returns an error. -func (daemon *Daemon) ContainerTop(name string, psArgs string) (*types.ContainerProcessList, error) { +func (daemon *Daemon) ContainerTop(ctx context.Context, name string, psArgs string) (*types.ContainerProcessList, error) { return nil, derr.ErrorCodeNoTop } diff --git a/daemon/unpause.go b/daemon/unpause.go index 6dd41c511c..49fdb105b8 100644 --- a/daemon/unpause.go +++ b/daemon/unpause.go @@ -1,17 +1,18 @@ package daemon import ( + "github.com/docker/docker/context" derr "github.com/docker/docker/errors" ) // ContainerUnpause unpauses a container -func (daemon *Daemon) ContainerUnpause(name string) error { - container, err := daemon.Get(name) +func (daemon *Daemon) ContainerUnpause(ctx context.Context, name string) error { + container, err := daemon.Get(ctx, name) if err != nil { return err } - if err := container.unpause(); err != nil { + if err := container.unpause(ctx); err != nil { return derr.ErrorCodeCantUnpause.WithArgs(name, err) } diff --git a/daemon/volumes_unix.go b/daemon/volumes_unix.go index 0982e982d5..24d8d6fe99 100644 --- a/daemon/volumes_unix.go +++ b/daemon/volumes_unix.go @@ -10,6 +10,7 @@ import ( "strings" "github.com/Sirupsen/logrus" + "github.com/docker/docker/context" "github.com/docker/docker/daemon/execdriver" derr "github.com/docker/docker/errors" "github.com/docker/docker/pkg/system" @@ -285,7 +286,7 @@ func parseVolumesFrom(spec string) (string, string, error) { // 1. Select the previously configured mount points for the containers, if any. // 2. Select the volumes mounted from another containers. Overrides previously configured mount point destination. // 3. Select the bind mounts set by the client. Overrides previously configured mount point destinations. -func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runconfig.HostConfig) error { +func (daemon *Daemon) registerMountPoints(ctx context.Context, container *Container, hostConfig *runconfig.HostConfig) error { binds := map[string]bool{} mountPoints := map[string]*mountPoint{} @@ -301,7 +302,7 @@ func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runc return err } - c, err := daemon.Get(containerID) + c, err := daemon.Get(ctx, containerID) if err != nil { return err } diff --git a/daemon/volumes_windows.go b/daemon/volumes_windows.go index df122ecbac..d239261bd4 100644 --- a/daemon/volumes_windows.go +++ b/daemon/volumes_windows.go @@ -3,6 +3,7 @@ package daemon import ( + "github.com/docker/docker/context" "github.com/docker/docker/daemon/execdriver" "github.com/docker/docker/runconfig" ) @@ -31,6 +32,6 @@ func (daemon *Daemon) verifyVolumesInfo(container *Container) error { // registerMountPoints initializes the container mount points with the // configured volumes and bind mounts. Windows does not support volumes or // mount points. -func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runconfig.HostConfig) error { +func (daemon *Daemon) registerMountPoints(ctx context.Context, container *Container, hostConfig *runconfig.HostConfig) error { return nil } diff --git a/daemon/wait.go b/daemon/wait.go index e429c46012..7fa6e14bd3 100644 --- a/daemon/wait.go +++ b/daemon/wait.go @@ -1,14 +1,18 @@ package daemon -import "time" +import ( + "time" + + "github.com/docker/docker/context" +) // ContainerWait stops processing until the given container is // stopped. If the container is not found, an error is returned. On a // successful stop, the exit code of the container is returned. On a // timeout, an error is returned. If you want to wait forever, supply // a negative duration for the timeout. -func (daemon *Daemon) ContainerWait(name string, timeout time.Duration) (int, error) { - container, err := daemon.Get(name) +func (daemon *Daemon) ContainerWait(ctx context.Context, name string, timeout time.Duration) (int, error) { + container, err := daemon.Get(ctx, name) if err != nil { return -1, err } diff --git a/docker/daemon.go b/docker/daemon.go index bd31447c64..382b2b28d0 100644 --- a/docker/daemon.go +++ b/docker/daemon.go @@ -17,6 +17,7 @@ import ( "github.com/docker/docker/autogen/dockerversion" "github.com/docker/docker/cli" "github.com/docker/docker/cliconfig" + "github.com/docker/docker/context" "github.com/docker/docker/daemon" "github.com/docker/docker/daemon/logger" "github.com/docker/docker/opts" @@ -150,6 +151,11 @@ func getGlobalFlag() (globalFlag *flag.Flag) { // CmdDaemon is the daemon command, called the raw arguments after `docker daemon`. func (cli *DaemonCli) CmdDaemon(args ...string) error { + // This may need to be made even more global - it all depends + // on whether we want the CLI to have a context object too. + // For now we'll leave it as a daemon-side object only. + ctx := context.Background() + // warn from uuid package when running the daemon uuid.Loggerf = logrus.Warnf @@ -224,7 +230,7 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error { serverConfig.TLSConfig = tlsConfig } - api := apiserver.New(serverConfig) + api := apiserver.New(ctx, serverConfig) // The serve API routine never exits unless an error occurs // We need to start it as a goroutine and wait on it so @@ -245,7 +251,7 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error { cli.TrustKeyPath = commonFlags.TrustKey registryService := registry.NewService(cli.registryOptions) - d, err := daemon.NewDaemon(cli.Config, registryService) + d, err := daemon.NewDaemon(ctx, cli.Config, registryService) if err != nil { if pfile != nil { if err := pfile.Remove(); err != nil { @@ -260,14 +266,14 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error { logrus.WithFields(logrus.Fields{ "version": dockerversion.VERSION, "commit": dockerversion.GITCOMMIT, - "execdriver": d.ExecutionDriver().Name(), - "graphdriver": d.GraphDriver().String(), + "execdriver": d.ExecutionDriver(ctx).Name(), + "graphdriver": d.GraphDriver(ctx).String(), }).Info("Docker daemon") signal.Trap(func() { api.Close() <-serveAPIWait - shutdownDaemon(d, 15) + shutdownDaemon(ctx, d, 15) if pfile != nil { if err := pfile.Remove(); err != nil { logrus.Error(err) @@ -277,12 +283,12 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error { // after the daemon is done setting up we can tell the api to start // accepting connections with specified daemon - api.AcceptConnections(d) + api.AcceptConnections(ctx, d) // Daemon is fully initialized and handling API traffic // Wait for serve API to complete errAPI := <-serveAPIWait - shutdownDaemon(d, 15) + shutdownDaemon(ctx, d, 15) if errAPI != nil { if pfile != nil { if err := pfile.Remove(); err != nil { @@ -297,10 +303,10 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error { // 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, timeout time.Duration) { +func shutdownDaemon(ctx context.Context, d *daemon.Daemon, timeout time.Duration) { ch := make(chan struct{}) go func() { - d.Shutdown() + d.Shutdown(ctx) close(ch) }() select { diff --git a/graph/import.go b/graph/import.go index 1a09dec470..e88358582b 100644 --- a/graph/import.go +++ b/graph/import.go @@ -5,6 +5,7 @@ import ( "net/http" "net/url" + "github.com/docker/docker/context" "github.com/docker/docker/pkg/httputils" "github.com/docker/docker/pkg/progressreader" "github.com/docker/docker/pkg/streamformatter" @@ -16,7 +17,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 (s *TagStore) Import(src string, repo string, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, containerConfig *runconfig.Config) error { +func (s *TagStore) Import(ctx context.Context, src string, repo string, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, containerConfig *runconfig.Config) error { var ( sf = streamformatter.NewJSONStreamFormatter() archive io.ReadCloser @@ -74,6 +75,6 @@ func (s *TagStore) Import(src string, repo string, tag string, msg string, inCon logID = utils.ImageReference(logID, tag) } - s.eventsService.Log("import", logID, "") + s.eventsService.Log(ctx, "import", logID, "") return nil } diff --git a/graph/pull.go b/graph/pull.go index 2403d77acf..1a52e9a365 100644 --- a/graph/pull.go +++ b/graph/pull.go @@ -6,6 +6,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/cliconfig" + "github.com/docker/docker/context" "github.com/docker/docker/pkg/streamformatter" "github.com/docker/docker/registry" "github.com/docker/docker/utils" @@ -62,7 +63,7 @@ func NewPuller(s *TagStore, endpoint registry.APIEndpoint, repoInfo *registry.Re // Pull initiates a pull operation. image is the repository name to pull, and // tag may be either empty, or indicate a specific tag to pull. -func (s *TagStore) Pull(image string, tag string, imagePullConfig *ImagePullConfig) error { +func (s *TagStore) Pull(ctx context.Context, image string, tag string, imagePullConfig *ImagePullConfig) error { var sf = streamformatter.NewJSONStreamFormatter() // Resolve the Repository name from fqn to RepositoryInfo @@ -131,7 +132,7 @@ func (s *TagStore) Pull(image string, tag string, imagePullConfig *ImagePullConf } - s.eventsService.Log("pull", logName, "") + s.eventsService.Log(ctx, "pull", logName, "") return nil } diff --git a/graph/push.go b/graph/push.go index ae5802dcb9..b5f79948ed 100644 --- a/graph/push.go +++ b/graph/push.go @@ -7,6 +7,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/distribution/digest" "github.com/docker/docker/cliconfig" + "github.com/docker/docker/context" "github.com/docker/docker/pkg/streamformatter" "github.com/docker/docker/registry" ) @@ -67,7 +68,7 @@ func (s *TagStore) NewPusher(endpoint registry.APIEndpoint, localRepo Repository } // Push initiates a push operation on the repository named localName. -func (s *TagStore) Push(localName string, imagePushConfig *ImagePushConfig) error { +func (s *TagStore) Push(ctx context.Context, localName string, imagePushConfig *ImagePushConfig) error { // FIXME: Allow to interrupt current push when new push of same image is done. var sf = streamformatter.NewJSONStreamFormatter() @@ -115,7 +116,7 @@ func (s *TagStore) Push(localName string, imagePushConfig *ImagePushConfig) erro } - s.eventsService.Log("push", repoInfo.LocalName, "") + s.eventsService.Log(ctx, "push", repoInfo.LocalName, "") return nil } diff --git a/integration-cli/docker_cli_events_test.go b/integration-cli/docker_cli_events_test.go index d196a89e9c..b94e9f23b6 100644 --- a/integration-cli/docker_cli_events_test.go +++ b/integration-cli/docker_cli_events_test.go @@ -410,7 +410,7 @@ func (s *DockerSuite) TestEventsFilterContainer(c *check.C) { } // Check the id - parsedID := strings.TrimSuffix(e[1], ":") + parsedID := strings.TrimSuffix(e[3], ":") if parsedID != id { return fmt.Errorf("expected event for container id %s: %s - parsed container id: %s", id, event, parsedID) } @@ -686,3 +686,78 @@ func (s *DockerRegistrySuite) TestEventsImageFilterPush(c *check.C) { c.Fatalf("Missing 'push' log event for image %s\n%s", repoName, out) } } + +func (s *DockerSuite) TestEventsReqID(c *check.C) { + // Tests for the "[reqid: xxx]" field in Events + testRequires(c, DaemonIsLinux) + + reqIDMatch := `[^ ]+ \[reqid: ([0-9a-z]{12})\] [0-9a-z]+: ` + reqIDRE := regexp.MustCompile(reqIDMatch) + + // Simple test just to make sure it works at all + dockerCmd(c, "create", "busybox", "true") + + out, _ := dockerCmd(c, "events", "--since=0", "--until=0s") + events := strings.Split(strings.TrimSpace(out), "\n") + + if len(events) == 0 { + c.Fatalf("Wrong # of events, should just be one, got:\n%v\n", events) + } + + createEvent := events[len(events)-1] + + matched, err := regexp.MatchString(reqIDMatch, createEvent) + if err != nil || !matched { + c.Fatalf("Error finding reqID in event: %v\n", createEvent) + } + + reqID1 := reqIDRE.FindStringSubmatch(createEvent)[1] + + // Now make sure another cmd doesn't get the same reqID + dockerCmd(c, "create", "busybox", "true") + + out, _ = dockerCmd(c, "events", "--since=0", "--until=0s") + events = strings.Split(strings.TrimSpace(out), "\n") + createEvent = events[len(events)-1] + + matched, err = regexp.MatchString(reqIDMatch, createEvent) + if err != nil || !matched { + c.Fatalf("Error finding reqID in event: %v\n", createEvent) + } + + reqID2 := reqIDRE.FindStringSubmatch(createEvent)[1] + + if reqID1 == reqID2 { + c.Fatalf("Should not have the same reqID(%s):\n%v\n", reqID1, createEvent) + } + + // Now make sure a build **does** use the same reqID for all + // 4 events that are generated + _, err = buildImage("reqidimg", ` + FROM busybox + RUN echo HI`, true) + if err != nil { + c.Fatalf("Couldn't create image: %q", err) + } + + out, _ = dockerCmd(c, "events", "--since=0", "--until=0s") + events = strings.Split(strings.TrimSpace(out), "\n") + + // Get last event's reqID - will use it to find other matching events + lastEvent := events[len(events)-1] + reqID := reqIDRE.FindStringSubmatch(lastEvent)[1] + + // Find all events with this same reqID + eventList := []string{lastEvent} + for i := len(events) - 2; i >= 0; i-- { + tmpID := reqIDRE.FindStringSubmatch(events[i])[1] + if tmpID != reqID { + break + } + eventList = append(eventList, events[i]) + } + + if len(eventList) != 5 { // create, start, die, commit, destroy + c.Fatalf("Wrong # of matching events - should be 5:\n%q\n", eventList) + } +} diff --git a/pkg/jsonmessage/jsonmessage.go b/pkg/jsonmessage/jsonmessage.go index 451c6a9fd2..4620483c66 100644 --- a/pkg/jsonmessage/jsonmessage.go +++ b/pkg/jsonmessage/jsonmessage.go @@ -92,6 +92,7 @@ func (p *JSONProgress) String() string { // the created time, where it from, status, ID of the // message. It's used for docker events. type JSONMessage struct { + RequestID string `json:"reqid,omitempty"` Stream string `json:"stream,omitempty"` Status string `json:"status,omitempty"` Progress *JSONProgress `json:"progressDetail,omitempty"` @@ -127,6 +128,9 @@ func (jm *JSONMessage) Display(out io.Writer, isTerminal bool) error { } else if jm.Time != 0 { fmt.Fprintf(out, "%s ", time.Unix(jm.Time, 0).Format(timeutils.RFC3339NanoFixed)) } + if jm.RequestID != "" { + fmt.Fprintf(out, "[reqid: %s] ", jm.RequestID) + } if jm.ID != "" { fmt.Fprintf(out, "%s: ", jm.ID) }