diff --git a/api/server/auth.go b/api/server/auth.go index 326a0e9e40..0373a9d2e1 100644 --- a/api/server/auth.go +++ b/api/server/auth.go @@ -6,10 +6,10 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/cliconfig" - "github.com/docker/docker/pkg/version" + "github.com/docker/docker/context" ) -func (s *Server) postAuth(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postAuth(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { var config *cliconfig.AuthConfig err := json.NewDecoder(r.Body).Decode(&config) r.Body.Close() diff --git a/api/server/container.go b/api/server/container.go index 08c3ed4860..3af7972674 100644 --- a/api/server/container.go +++ b/api/server/container.go @@ -12,14 +12,14 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/api/types" + "github.com/docker/docker/context" "github.com/docker/docker/daemon" "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/signal" - "github.com/docker/docker/pkg/version" "github.com/docker/docker/runconfig" ) -func (s *Server) getContainersJSON(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getContainersJSON(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -48,7 +48,7 @@ func (s *Server) getContainersJSON(version version.Version, w http.ResponseWrite return writeJSON(w, http.StatusOK, containers) } -func (s *Server) getContainersStats(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getContainersStats(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -89,7 +89,7 @@ func (s *Server) getContainersStats(version version.Version, w http.ResponseWrit return s.daemon.ContainerStats(container, config) } -func (s *Server) getContainersLogs(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getContainersLogs(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -146,7 +146,7 @@ func (s *Server) getContainersLogs(version version.Version, w http.ResponseWrite return nil } -func (s *Server) getContainersExport(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getContainersExport(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -154,7 +154,7 @@ func (s *Server) getContainersExport(version version.Version, w http.ResponseWri return s.daemon.ContainerExport(vars["name"], w) } -func (s *Server) postContainersStart(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainersStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -190,7 +190,7 @@ func (s *Server) postContainersStart(version version.Version, w http.ResponseWri return nil } -func (s *Server) postContainersStop(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainersStop(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -212,7 +212,7 @@ func (s *Server) postContainersStop(version version.Version, w http.ResponseWrit return nil } -func (s *Server) postContainersKill(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainersKill(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -250,6 +250,7 @@ func (s *Server) postContainersKill(version version.Version, w http.ResponseWrit // Return error that's not caused because the container is stopped. // Return error if the container is not running and the api is >= 1.20 // to keep backwards compatibility. + version := ctx.Version() if version.GreaterThanOrEqualTo("1.20") || !isStopped { return fmt.Errorf("Cannot kill container %s: %v", name, err) } @@ -259,7 +260,7 @@ func (s *Server) postContainersKill(version version.Version, w http.ResponseWrit return nil } -func (s *Server) postContainersRestart(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainersRestart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -278,7 +279,7 @@ func (s *Server) postContainersRestart(version version.Version, w http.ResponseW return nil } -func (s *Server) postContainersPause(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainersPause(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -295,7 +296,7 @@ func (s *Server) postContainersPause(version version.Version, w http.ResponseWri return nil } -func (s *Server) postContainersUnpause(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainersUnpause(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -312,7 +313,7 @@ func (s *Server) postContainersUnpause(version version.Version, w http.ResponseW return nil } -func (s *Server) postContainersWait(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainersWait(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -327,7 +328,7 @@ func (s *Server) postContainersWait(version version.Version, w http.ResponseWrit }) } -func (s *Server) getContainersChanges(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getContainersChanges(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -340,7 +341,7 @@ func (s *Server) getContainersChanges(version version.Version, w http.ResponseWr return writeJSON(w, http.StatusOK, changes) } -func (s *Server) getContainersTop(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getContainersTop(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -357,7 +358,7 @@ func (s *Server) getContainersTop(version version.Version, w http.ResponseWriter return writeJSON(w, http.StatusOK, procList) } -func (s *Server) postContainerRename(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainerRename(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -374,7 +375,7 @@ func (s *Server) postContainerRename(version version.Version, w http.ResponseWri return nil } -func (s *Server) postContainersCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainersCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -390,6 +391,7 @@ func (s *Server) postContainersCreate(version version.Version, w http.ResponseWr if err != nil { return err } + version := ctx.Version() adjustCPUShares := version.LessThan("1.19") container, warnings, err := s.daemon.ContainerCreate(name, config, hostConfig, adjustCPUShares) @@ -403,7 +405,7 @@ func (s *Server) postContainersCreate(version version.Version, w http.ResponseWr }) } -func (s *Server) deleteContainers(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) deleteContainers(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -431,7 +433,7 @@ func (s *Server) deleteContainers(version version.Version, w http.ResponseWriter return nil } -func (s *Server) postContainersResize(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainersResize(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -451,7 +453,7 @@ func (s *Server) postContainersResize(version version.Version, w http.ResponseWr return s.daemon.ContainerResize(vars["name"], height, width) } -func (s *Server) postContainersAttach(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainersAttach(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -493,7 +495,7 @@ func (s *Server) postContainersAttach(version version.Version, w http.ResponseWr return nil } -func (s *Server) wsContainersAttach(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) wsContainersAttach(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } diff --git a/api/server/copy.go b/api/server/copy.go index 2d26fb983a..b3d8ed320e 100644 --- a/api/server/copy.go +++ b/api/server/copy.go @@ -10,11 +10,11 @@ import ( "strings" "github.com/docker/docker/api/types" - "github.com/docker/docker/pkg/version" + "github.com/docker/docker/context" ) // postContainersCopy is deprecated in favor of getContainersArchive. -func (s *Server) postContainersCopy(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainersCopy(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -68,7 +68,7 @@ func setContainerPathStatHeader(stat *types.ContainerPathStat, header http.Heade return nil } -func (s *Server) headContainersArchive(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) headContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { v, err := archiveFormValues(r, vars) if err != nil { return err @@ -82,7 +82,7 @@ func (s *Server) headContainersArchive(version version.Version, w http.ResponseW return setContainerPathStatHeader(stat, w.Header()) } -func (s *Server) getContainersArchive(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { v, err := archiveFormValues(r, vars) if err != nil { return err @@ -104,7 +104,7 @@ func (s *Server) getContainersArchive(version version.Version, w http.ResponseWr return err } -func (s *Server) putContainersArchive(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) putContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { v, err := archiveFormValues(r, vars) if err != nil { return err diff --git a/api/server/daemon.go b/api/server/daemon.go index 97c9100374..df3cba9704 100644 --- a/api/server/daemon.go +++ b/api/server/daemon.go @@ -12,15 +12,15 @@ import ( "github.com/docker/docker/api" "github.com/docker/docker/api/types" "github.com/docker/docker/autogen/dockerversion" + "github.com/docker/docker/context" "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/jsonmessage" "github.com/docker/docker/pkg/parsers/filters" "github.com/docker/docker/pkg/parsers/kernel" - "github.com/docker/docker/pkg/version" "github.com/docker/docker/utils" ) -func (s *Server) getVersion(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getVersion(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { v := &types.Version{ Version: dockerversion.VERSION, APIVersion: api.Version, @@ -31,6 +31,8 @@ func (s *Server) getVersion(version version.Version, w http.ResponseWriter, r *h BuildTime: dockerversion.BUILDTIME, } + version := ctx.Version() + if version.GreaterThanOrEqualTo("1.19") { v.Experimental = utils.ExperimentalBuild() } @@ -42,7 +44,7 @@ func (s *Server) getVersion(version version.Version, w http.ResponseWriter, r *h return writeJSON(w, http.StatusOK, v) } -func (s *Server) getInfo(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getInfo(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { info, err := s.daemon.SystemInfo() if err != nil { return err @@ -51,7 +53,7 @@ func (s *Server) getInfo(version version.Version, w http.ResponseWriter, r *http return writeJSON(w, http.StatusOK, info) } -func (s *Server) getEvents(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getEvents(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } diff --git a/api/server/exec.go b/api/server/exec.go index dd38c0a030..46d46c58b7 100644 --- a/api/server/exec.go +++ b/api/server/exec.go @@ -9,12 +9,12 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/api/types" + "github.com/docker/docker/context" "github.com/docker/docker/pkg/stdcopy" - "github.com/docker/docker/pkg/version" "github.com/docker/docker/runconfig" ) -func (s *Server) getExecByID(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getExecByID(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter 'id'") } @@ -27,7 +27,7 @@ func (s *Server) getExecByID(version version.Version, w http.ResponseWriter, r * return writeJSON(w, http.StatusOK, eConfig) } -func (s *Server) postContainerExecCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainerExecCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -59,7 +59,7 @@ func (s *Server) postContainerExecCreate(version version.Version, w http.Respons } // TODO(vishh): Refactor the code to avoid having to specify stream config as part of both create and start. -func (s *Server) postContainerExecStart(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainerExecStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -106,7 +106,7 @@ func (s *Server) postContainerExecStart(version version.Version, w http.Response return nil } -func (s *Server) postContainerExecResize(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainerExecResize(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } diff --git a/api/server/image.go b/api/server/image.go index 3a751e8045..6ca18be69e 100644 --- a/api/server/image.go +++ b/api/server/image.go @@ -12,17 +12,17 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/builder" "github.com/docker/docker/cliconfig" + "github.com/docker/docker/context" "github.com/docker/docker/graph" "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/streamformatter" "github.com/docker/docker/pkg/ulimit" - "github.com/docker/docker/pkg/version" "github.com/docker/docker/runconfig" "github.com/docker/docker/utils" ) -func (s *Server) postCommit(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postCommit(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -34,6 +34,7 @@ func (s *Server) postCommit(version version.Version, w http.ResponseWriter, r *h cname := r.Form.Get("container") pause := boolValue(r, "pause") + version := ctx.Version() if r.FormValue("pause") == "" && version.GreaterThanOrEqualTo("1.13") { pause = true } @@ -64,7 +65,7 @@ func (s *Server) postCommit(version version.Version, w http.ResponseWriter, r *h } // Creates an image from Pull or from Import -func (s *Server) postImagesCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postImagesCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -140,7 +141,7 @@ func (s *Server) postImagesCreate(version version.Version, w http.ResponseWriter return nil } -func (s *Server) postImagesPush(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postImagesPush(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -192,7 +193,7 @@ func (s *Server) postImagesPush(version version.Version, w http.ResponseWriter, return nil } -func (s *Server) getImagesGet(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getImagesGet(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -220,11 +221,11 @@ func (s *Server) getImagesGet(version version.Version, w http.ResponseWriter, r return nil } -func (s *Server) postImagesLoad(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +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) } -func (s *Server) deleteImages(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) deleteImages(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -249,7 +250,7 @@ func (s *Server) deleteImages(version version.Version, w http.ResponseWriter, r return writeJSON(w, http.StatusOK, list) } -func (s *Server) getImagesByName(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getImagesByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -262,7 +263,7 @@ func (s *Server) getImagesByName(version version.Version, w http.ResponseWriter, return writeJSON(w, http.StatusOK, imageInspect) } -func (s *Server) postBuild(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postBuild(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { var ( authConfigs = map[string]cliconfig.AuthConfig{} authConfigsEncoded = r.Header.Get("X-Registry-Config") @@ -280,6 +281,7 @@ func (s *Server) postBuild(version version.Version, w http.ResponseWriter, r *ht w.Header().Set("Content-Type", "application/json") + version := ctx.Version() if boolValue(r, "forcerm") && version.GreaterThanOrEqualTo("1.12") { buildConfig.Remove = true } else if r.FormValue("rm") == "" && version.GreaterThanOrEqualTo("1.12") { @@ -346,7 +348,7 @@ func (s *Server) postBuild(version version.Version, w http.ResponseWriter, r *ht return nil } -func (s *Server) getImagesJSON(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getImagesJSON(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -360,7 +362,7 @@ func (s *Server) getImagesJSON(version version.Version, w http.ResponseWriter, r return writeJSON(w, http.StatusOK, images) } -func (s *Server) getImagesHistory(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getImagesHistory(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -374,7 +376,7 @@ func (s *Server) getImagesHistory(version version.Version, w http.ResponseWriter return writeJSON(w, http.StatusOK, history) } -func (s *Server) postImagesTag(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postImagesTag(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -394,7 +396,7 @@ func (s *Server) postImagesTag(version version.Version, w http.ResponseWriter, r return nil } -func (s *Server) getImagesSearch(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getImagesSearch(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } diff --git a/api/server/inspect.go b/api/server/inspect.go index 41f958ebb1..782ae4865c 100644 --- a/api/server/inspect.go +++ b/api/server/inspect.go @@ -4,11 +4,11 @@ import ( "fmt" "net/http" - "github.com/docker/docker/pkg/version" + "github.com/docker/docker/context" ) // getContainersByName inspects containers configuration and serializes it as json. -func (s *Server) getContainersByName(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getContainersByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -16,6 +16,8 @@ func (s *Server) getContainersByName(version version.Version, w http.ResponseWri var json interface{} var err error + version := ctx.Version() + switch { case version.LessThan("1.20"): json, err = s.daemon.ContainerInspectPre120(vars["name"]) diff --git a/api/server/server.go b/api/server/server.go index 1ab504da57..f7d85138a7 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -16,8 +16,10 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/api" "github.com/docker/docker/autogen/dockerversion" + "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/pkg/version" ) @@ -122,7 +124,7 @@ func (s *HTTPServer) Close() error { // HTTPAPIFunc is an adapter to allow the use of ordinary functions as Docker API endpoints. // Any function that has the appropriate signature can be register as a API endpoint (e.g. getVersion). -type HTTPAPIFunc func(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error +type HTTPAPIFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error func hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) { conn, _, err := w.(http.Hijacker).Hijack() @@ -219,7 +221,7 @@ func writeJSON(w http.ResponseWriter, code int, v interface{}) error { return json.NewEncoder(w).Encode(v) } -func (s *Server) optionsHandler(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) optionsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { w.WriteHeader(http.StatusOK) return nil } @@ -230,7 +232,7 @@ func writeCorsHeaders(w http.ResponseWriter, r *http.Request, corsHeaders string w.Header().Add("Access-Control-Allow-Methods", "HEAD, GET, POST, DELETE, PUT, OPTIONS") } -func (s *Server) ping(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) ping(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { _, err := w.Write([]byte{'O', 'K'}) return err } @@ -250,6 +252,24 @@ func (s *Server) initTCPSocket(addr string) (l net.Listener, err error) { func makeHTTPHandler(logging bool, localMethod string, localRoute string, handlerFunc HTTPAPIFunc, corsHeaders string, dockerVersion version.Version) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { + // Define the context that we'll pass around to share info + // like the docker-request-id. + // + // The 'context' will be used for global data that should + // apply to all requests. Data that is specific to the + // immediate function being called should still be passed + // as 'args' on the function call. + + reqID := stringid.TruncateID(stringid.GenerateNonCryptoID()) + apiVersion := version.Version(mux.Vars(r)["version"]) + if apiVersion == "" { + apiVersion = api.Version + } + + ctx := context.Background() + ctx = context.WithValue(ctx, context.RequestID, reqID) + ctx = context.WithValue(ctx, context.APIVersion, apiVersion) + // log the request logrus.Debugf("Calling %s %s", localMethod, localRoute) @@ -270,26 +290,22 @@ func makeHTTPHandler(logging bool, localMethod string, localRoute string, handle logrus.Debugf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], dockerVersion) } } - version := version.Version(mux.Vars(r)["version"]) - if version == "" { - version = api.Version - } if corsHeaders != "" { writeCorsHeaders(w, r, corsHeaders) } - if version.GreaterThan(api.Version) { - http.Error(w, fmt.Errorf("client is newer than server (client API version: %s, server API version: %s)", version, api.Version).Error(), http.StatusBadRequest) + if apiVersion.GreaterThan(api.Version) { + http.Error(w, fmt.Errorf("client is newer than server (client API version: %s, server API version: %s)", apiVersion, api.Version).Error(), http.StatusBadRequest) return } - if version.LessThan(api.MinVersion) { + if apiVersion.LessThan(api.MinVersion) { http.Error(w, fmt.Errorf("client is too old, minimum supported API version is %s, please upgrade your client to a newer version", api.MinVersion).Error(), http.StatusBadRequest) return } w.Header().Set("Server", "Docker/"+dockerversion.VERSION+" ("+runtime.GOOS+")") - if err := handlerFunc(version, w, r, mux.Vars(r)); err != nil { + if err := handlerFunc(ctx, w, r, mux.Vars(r)); err != nil { logrus.Errorf("Handler for %s %s returned error: %s", localMethod, localRoute, err) httpError(w, err) } diff --git a/api/server/volume.go b/api/server/volume.go index d070a33fb0..cec3b820c4 100644 --- a/api/server/volume.go +++ b/api/server/volume.go @@ -5,10 +5,10 @@ import ( "net/http" "github.com/docker/docker/api/types" - "github.com/docker/docker/pkg/version" + "github.com/docker/docker/context" ) -func (s *Server) getVolumesList(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getVolumesList(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -20,7 +20,7 @@ func (s *Server) getVolumesList(version version.Version, w http.ResponseWriter, return writeJSON(w, http.StatusOK, &types.VolumesListResponse{Volumes: volumes}) } -func (s *Server) getVolumeByName(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getVolumeByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -32,7 +32,7 @@ func (s *Server) getVolumeByName(version version.Version, w http.ResponseWriter, return writeJSON(w, http.StatusOK, v) } -func (s *Server) postVolumesCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postVolumesCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -53,7 +53,7 @@ func (s *Server) postVolumesCreate(version version.Version, w http.ResponseWrite return writeJSON(w, http.StatusCreated, volume) } -func (s *Server) deleteVolumes(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) deleteVolumes(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } diff --git a/context/context.go b/context/context.go new file mode 100644 index 0000000000..3532507c3d --- /dev/null +++ b/context/context.go @@ -0,0 +1,64 @@ +package context + +import ( + "golang.org/x/net/context" + + "github.com/docker/docker/pkg/version" +) + +const ( + // RequestID is the unique ID for each http request + RequestID = "request-id" + + // APIVersion is the client's requested API version + APIVersion = "api-version" +) + +// Context is just our own wrapper for the golang 'Context' - mainly +// so we can add our over version of the funcs. +type Context struct { + context.Context +} + +// Background creates a new Context based on golang's default one. +func Background() Context { + return Context{context.Background()} +} + +// WithValue will return a Context that has this new key/value pair +// associated with it. Just uses the golang version but then wraps it. +func WithValue(ctx Context, key, value interface{}) Context { + return Context{context.WithValue(ctx, key, value)} +} + +// RequestID is a utility func to make it easier to get the +// request ID associated with this Context/request. +func (ctx Context) RequestID() string { + val := ctx.Value(RequestID) + if val == nil { + return "" + } + + id, ok := val.(string) + if !ok { + // Ideally we shouldn't panic but we also should never get here + panic("Context RequestID isn't a string") + } + return id +} + +// Version is a utility func to make it easier to get the +// API version string associated with this Context/request. +func (ctx Context) Version() version.Version { + val := ctx.Value(APIVersion) + if val == nil { + return version.Version("") + } + + ver, ok := val.(version.Version) + if !ok { + // Ideally we shouldn't panic but we also should never get here + panic("Context APIVersion isn't a version.Version") + } + return ver +} diff --git a/context/context_test.go b/context/context_test.go new file mode 100644 index 0000000000..e1ec47435b --- /dev/null +++ b/context/context_test.go @@ -0,0 +1,35 @@ +package context + +import ( + "testing" + + "github.com/docker/docker/pkg/version" +) + +func TestContext(t *testing.T) { + ctx := Background() + + // First make sure getting non-existent values doesn't break + if id := ctx.RequestID(); id != "" { + t.Fatalf("RequestID() should have been '', was: %q", id) + } + + if ver := ctx.Version(); ver != "" { + t.Fatalf("Version() should have been '', was: %q", ver) + } + + // Test basic set/get + ctx = WithValue(ctx, RequestID, "123") + if ctx.RequestID() != "123" { + t.Fatalf("RequestID() should have been '123'") + } + + // Now make sure after a 2nd set we can still get both + ctx = WithValue(ctx, APIVersion, version.Version("x.y")) + if id := ctx.RequestID(); id != "123" { + t.Fatalf("RequestID() should have been '123', was %q", id) + } + if ver := ctx.Version(); ver != "x.y" { + t.Fatalf("Version() should have been 'x.y', was %q", ver) + } +}