Sfoglia il codice sorgente

Add a "context" to the api/server/* code

This defines a 'context' object that is passed to each API handler.
Right now the context just has a unique 'requestID' for each API call.
The next steps would be:
- use this 'requestID' in our logging.
- determine the best way to format the logging to include this info.

In particular for log events that generate multiple entries in the log
we can use the requestID to help correlate the log entries.

Adding the requestID to the logging will be a challenge since it could mean
changing every single logrus.XXX() call to pass in the 'context' object.

But first step is to agree on a format, which we can discus in a subsequent
PR, but my initial thoughts are to add it right after the timestamp:

current format:
INFO[0039] POST /v1.21/build?buildargs=%7B%22foo%22%3A%22xxx%22%7D&cgroupparent=&cpuperiod=0&cpuquota=0&cpusetcpus=&cpusetmems=&cpushares=0&dockerfile=Dockerfile&memory=0&memswap=0&rm=1&t=&ulimits=null

proposed format:
INFO[0039-83dea1222191] POST /v1.21/build?buildargs=%7B%22foo%22%3A%22xxx%22%7D&cgroupparent=&cpuperiod=0&cpuquota=0&cpusetcpus=&cpusetmems=&cpushares=0&dockerfile=Dockerfile&memory=0&memswap=0&rm=1&t=&ulimits=null

Signed-off-by: Doug Davis <dug@us.ibm.com>
Doug Davis 10 anni fa
parent
commit
8b454dd79e

+ 3 - 2
api/server/auth.go

@@ -4,12 +4,13 @@ import (
 	"encoding/json"
 	"encoding/json"
 	"net/http"
 	"net/http"
 
 
+	"golang.org/x/net/context"
+
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/cliconfig"
 	"github.com/docker/docker/cliconfig"
-	"github.com/docker/docker/pkg/version"
 )
 )
 
 
-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
 	var config *cliconfig.AuthConfig
 	err := json.NewDecoder(r.Body).Decode(&config)
 	err := json.NewDecoder(r.Body).Decode(&config)
 	r.Body.Close()
 	r.Body.Close()

+ 22 - 19
api/server/container.go

@@ -8,6 +8,7 @@ import (
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
+	"golang.org/x/net/context"
 	"golang.org/x/net/websocket"
 	"golang.org/x/net/websocket"
 
 
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
@@ -19,7 +20,7 @@ import (
 	"github.com/docker/docker/runconfig"
 	"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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -48,7 +49,7 @@ func (s *Server) getContainersJSON(version version.Version, w http.ResponseWrite
 	return writeJSON(w, http.StatusOK, containers)
 	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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -89,7 +90,7 @@ func (s *Server) getContainersStats(version version.Version, w http.ResponseWrit
 	return s.daemon.ContainerStats(container, config)
 	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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -146,7 +147,7 @@ func (s *Server) getContainersLogs(version version.Version, w http.ResponseWrite
 	return nil
 	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 {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 		return fmt.Errorf("Missing parameter")
 	}
 	}
@@ -154,7 +155,7 @@ func (s *Server) getContainersExport(version version.Version, w http.ResponseWri
 	return s.daemon.ContainerExport(vars["name"], w)
 	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 {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 		return fmt.Errorf("Missing parameter")
 	}
 	}
@@ -190,7 +191,7 @@ func (s *Server) postContainersStart(version version.Version, w http.ResponseWri
 	return nil
 	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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -212,7 +213,7 @@ func (s *Server) postContainersStop(version version.Version, w http.ResponseWrit
 	return nil
 	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 {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 		return fmt.Errorf("Missing parameter")
 	}
 	}
@@ -250,6 +251,7 @@ func (s *Server) postContainersKill(version version.Version, w http.ResponseWrit
 		// Return error that's not caused because the container is stopped.
 		// 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
 		// Return error if the container is not running and the api is >= 1.20
 		// to keep backwards compatibility.
 		// to keep backwards compatibility.
+		version, _ := ctx.Value("api-version").(version.Version)
 		if version.GreaterThanOrEqualTo("1.20") || !isStopped {
 		if version.GreaterThanOrEqualTo("1.20") || !isStopped {
 			return fmt.Errorf("Cannot kill container %s: %v", name, err)
 			return fmt.Errorf("Cannot kill container %s: %v", name, err)
 		}
 		}
@@ -259,7 +261,7 @@ func (s *Server) postContainersKill(version version.Version, w http.ResponseWrit
 	return nil
 	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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -278,7 +280,7 @@ func (s *Server) postContainersRestart(version version.Version, w http.ResponseW
 	return nil
 	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 {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 		return fmt.Errorf("Missing parameter")
 	}
 	}
@@ -295,7 +297,7 @@ func (s *Server) postContainersPause(version version.Version, w http.ResponseWri
 	return nil
 	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 {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 		return fmt.Errorf("Missing parameter")
 	}
 	}
@@ -312,7 +314,7 @@ func (s *Server) postContainersUnpause(version version.Version, w http.ResponseW
 	return nil
 	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 {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 		return fmt.Errorf("Missing parameter")
 	}
 	}
@@ -327,7 +329,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 {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 		return fmt.Errorf("Missing parameter")
 	}
 	}
@@ -340,7 +342,7 @@ func (s *Server) getContainersChanges(version version.Version, w http.ResponseWr
 	return writeJSON(w, http.StatusOK, changes)
 	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 {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 		return fmt.Errorf("Missing parameter")
 	}
 	}
@@ -357,7 +359,7 @@ func (s *Server) getContainersTop(version version.Version, w http.ResponseWriter
 	return writeJSON(w, http.StatusOK, procList)
 	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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -374,7 +376,7 @@ func (s *Server) postContainerRename(version version.Version, w http.ResponseWri
 	return nil
 	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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -390,6 +392,7 @@ func (s *Server) postContainersCreate(version version.Version, w http.ResponseWr
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
+	version, _ := ctx.Value("api-version").(version.Version)
 	adjustCPUShares := version.LessThan("1.19")
 	adjustCPUShares := version.LessThan("1.19")
 
 
 	container, warnings, err := s.daemon.ContainerCreate(name, config, hostConfig, adjustCPUShares)
 	container, warnings, err := s.daemon.ContainerCreate(name, config, hostConfig, adjustCPUShares)
@@ -403,7 +406,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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -431,7 +434,7 @@ func (s *Server) deleteContainers(version version.Version, w http.ResponseWriter
 	return nil
 	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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -451,7 +454,7 @@ func (s *Server) postContainersResize(version version.Version, w http.ResponseWr
 	return s.daemon.ContainerResize(vars["name"], height, width)
 	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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -493,7 +496,7 @@ func (s *Server) postContainersAttach(version version.Version, w http.ResponseWr
 	return nil
 	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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}

+ 6 - 5
api/server/copy.go

@@ -9,12 +9,13 @@ import (
 	"os"
 	"os"
 	"strings"
 	"strings"
 
 
+	"golang.org/x/net/context"
+
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types"
-	"github.com/docker/docker/pkg/version"
 )
 )
 
 
 // postContainersCopy is deprecated in favor of getContainersArchive.
 // 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 {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 		return fmt.Errorf("Missing parameter")
 	}
 	}
@@ -68,7 +69,7 @@ func setContainerPathStatHeader(stat *types.ContainerPathStat, header http.Heade
 	return nil
 	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)
 	v, err := archiveFormValues(r, vars)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
@@ -82,7 +83,7 @@ func (s *Server) headContainersArchive(version version.Version, w http.ResponseW
 	return setContainerPathStatHeader(stat, w.Header())
 	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)
 	v, err := archiveFormValues(r, vars)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
@@ -104,7 +105,7 @@ func (s *Server) getContainersArchive(version version.Version, w http.ResponseWr
 	return err
 	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)
 	v, err := archiveFormValues(r, vars)
 	if err != nil {
 	if err != nil {
 		return err
 		return err

+ 7 - 3
api/server/daemon.go

@@ -8,6 +8,8 @@ import (
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
+	"golang.org/x/net/context"
+
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/api"
 	"github.com/docker/docker/api"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types"
@@ -20,7 +22,7 @@ import (
 	"github.com/docker/docker/utils"
 	"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{
 	v := &types.Version{
 		Version:    dockerversion.VERSION,
 		Version:    dockerversion.VERSION,
 		APIVersion: api.Version,
 		APIVersion: api.Version,
@@ -31,6 +33,8 @@ func (s *Server) getVersion(version version.Version, w http.ResponseWriter, r *h
 		BuildTime:  dockerversion.BUILDTIME,
 		BuildTime:  dockerversion.BUILDTIME,
 	}
 	}
 
 
+	version, _ := ctx.Value("api-version").(version.Version)
+
 	if version.GreaterThanOrEqualTo("1.19") {
 	if version.GreaterThanOrEqualTo("1.19") {
 		v.Experimental = utils.ExperimentalBuild()
 		v.Experimental = utils.ExperimentalBuild()
 	}
 	}
@@ -42,7 +46,7 @@ func (s *Server) getVersion(version version.Version, w http.ResponseWriter, r *h
 	return writeJSON(w, http.StatusOK, v)
 	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()
 	info, err := s.daemon.SystemInfo()
 	if err != nil {
 	if err != nil {
 		return err
 		return err
@@ -51,7 +55,7 @@ func (s *Server) getInfo(version version.Version, w http.ResponseWriter, r *http
 	return writeJSON(w, http.StatusOK, info)
 	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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}

+ 6 - 5
api/server/exec.go

@@ -7,14 +7,15 @@ import (
 	"net/http"
 	"net/http"
 	"strconv"
 	"strconv"
 
 
+	"golang.org/x/net/context"
+
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/pkg/stdcopy"
 	"github.com/docker/docker/pkg/stdcopy"
-	"github.com/docker/docker/pkg/version"
 	"github.com/docker/docker/runconfig"
 	"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 {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter 'id'")
 		return fmt.Errorf("Missing parameter 'id'")
 	}
 	}
@@ -27,7 +28,7 @@ func (s *Server) getExecByID(version version.Version, w http.ResponseWriter, r *
 	return writeJSON(w, http.StatusOK, eConfig)
 	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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -59,7 +60,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.
 // 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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -106,7 +107,7 @@ func (s *Server) postContainerExecStart(version version.Version, w http.Response
 	return nil
 	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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}

+ 16 - 12
api/server/image.go

@@ -8,6 +8,8 @@ import (
 	"net/http"
 	"net/http"
 	"strings"
 	"strings"
 
 
+	"golang.org/x/net/context"
+
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/builder"
 	"github.com/docker/docker/builder"
@@ -22,7 +24,7 @@ import (
 	"github.com/docker/docker/utils"
 	"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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -34,6 +36,7 @@ func (s *Server) postCommit(version version.Version, w http.ResponseWriter, r *h
 	cname := r.Form.Get("container")
 	cname := r.Form.Get("container")
 
 
 	pause := boolValue(r, "pause")
 	pause := boolValue(r, "pause")
+	version, _ := ctx.Value("api-version").(version.Version)
 	if r.FormValue("pause") == "" && version.GreaterThanOrEqualTo("1.13") {
 	if r.FormValue("pause") == "" && version.GreaterThanOrEqualTo("1.13") {
 		pause = true
 		pause = true
 	}
 	}
@@ -64,7 +67,7 @@ func (s *Server) postCommit(version version.Version, w http.ResponseWriter, r *h
 }
 }
 
 
 // Creates an image from Pull or from Import
 // 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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -140,7 +143,7 @@ func (s *Server) postImagesCreate(version version.Version, w http.ResponseWriter
 	return nil
 	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 {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 		return fmt.Errorf("Missing parameter")
 	}
 	}
@@ -192,7 +195,7 @@ func (s *Server) postImagesPush(version version.Version, w http.ResponseWriter,
 	return nil
 	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 {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 		return fmt.Errorf("Missing parameter")
 	}
 	}
@@ -220,11 +223,11 @@ func (s *Server) getImagesGet(version version.Version, w http.ResponseWriter, r
 	return nil
 	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)
 	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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -249,7 +252,7 @@ func (s *Server) deleteImages(version version.Version, w http.ResponseWriter, r
 	return writeJSON(w, http.StatusOK, list)
 	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 {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 		return fmt.Errorf("Missing parameter")
 	}
 	}
@@ -262,7 +265,7 @@ func (s *Server) getImagesByName(version version.Version, w http.ResponseWriter,
 	return writeJSON(w, http.StatusOK, imageInspect)
 	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 (
 	var (
 		authConfigs        = map[string]cliconfig.AuthConfig{}
 		authConfigs        = map[string]cliconfig.AuthConfig{}
 		authConfigsEncoded = r.Header.Get("X-Registry-Config")
 		authConfigsEncoded = r.Header.Get("X-Registry-Config")
@@ -280,6 +283,7 @@ func (s *Server) postBuild(version version.Version, w http.ResponseWriter, r *ht
 
 
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
 
 
+	version, _ := ctx.Value("api-version").(version.Version)
 	if boolValue(r, "forcerm") && version.GreaterThanOrEqualTo("1.12") {
 	if boolValue(r, "forcerm") && version.GreaterThanOrEqualTo("1.12") {
 		buildConfig.Remove = true
 		buildConfig.Remove = true
 	} else if r.FormValue("rm") == "" && version.GreaterThanOrEqualTo("1.12") {
 	} else if r.FormValue("rm") == "" && version.GreaterThanOrEqualTo("1.12") {
@@ -346,7 +350,7 @@ func (s *Server) postBuild(version version.Version, w http.ResponseWriter, r *ht
 	return nil
 	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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -360,7 +364,7 @@ func (s *Server) getImagesJSON(version version.Version, w http.ResponseWriter, r
 	return writeJSON(w, http.StatusOK, images)
 	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 {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 		return fmt.Errorf("Missing parameter")
 	}
 	}
@@ -374,7 +378,7 @@ func (s *Server) getImagesHistory(version version.Version, w http.ResponseWriter
 	return writeJSON(w, http.StatusOK, history)
 	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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -394,7 +398,7 @@ func (s *Server) postImagesTag(version version.Version, w http.ResponseWriter, r
 	return nil
 	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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}

+ 5 - 1
api/server/inspect.go

@@ -4,11 +4,13 @@ import (
 	"fmt"
 	"fmt"
 	"net/http"
 	"net/http"
 
 
+	"golang.org/x/net/context"
+
 	"github.com/docker/docker/pkg/version"
 	"github.com/docker/docker/pkg/version"
 )
 )
 
 
 // getContainersByName inspects containers configuration and serializes it as json.
 // 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 {
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 		return fmt.Errorf("Missing parameter")
 	}
 	}
@@ -16,6 +18,8 @@ func (s *Server) getContainersByName(version version.Version, w http.ResponseWri
 	var json interface{}
 	var json interface{}
 	var err error
 	var err error
 
 
+	version, _ := ctx.Value("api-version").(version.Version)
+
 	switch {
 	switch {
 	case version.LessThan("1.20"):
 	case version.LessThan("1.20"):
 		json, err = s.daemon.ContainerInspectPre120(vars["name"])
 		json, err = s.daemon.ContainerInspectPre120(vars["name"])

+ 27 - 11
api/server/server.go

@@ -12,12 +12,14 @@ import (
 	"strings"
 	"strings"
 
 
 	"github.com/gorilla/mux"
 	"github.com/gorilla/mux"
+	"golang.org/x/net/context"
 
 
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/api"
 	"github.com/docker/docker/api"
 	"github.com/docker/docker/autogen/dockerversion"
 	"github.com/docker/docker/autogen/dockerversion"
 	"github.com/docker/docker/daemon"
 	"github.com/docker/docker/daemon"
 	"github.com/docker/docker/pkg/sockets"
 	"github.com/docker/docker/pkg/sockets"
+	"github.com/docker/docker/pkg/stringid"
 	"github.com/docker/docker/pkg/version"
 	"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.
 // 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).
 // 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) {
 func hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) {
 	conn, _, err := w.(http.Hijacker).Hijack()
 	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)
 	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)
 	w.WriteHeader(http.StatusOK)
 	return nil
 	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")
 	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'})
 	_, err := w.Write([]byte{'O', 'K'})
 	return err
 	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 {
 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) {
 	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())
+		api_version := version.Version(mux.Vars(r)["version"])
+		if api_version == "" {
+			api_version = api.Version
+		}
+
+		ctx := context.Background()
+		ctx = context.WithValue(ctx, "docker-request-id", reqID)
+		ctx = context.WithValue(ctx, "api-version", api_version)
+
 		// log the request
 		// log the request
 		logrus.Debugf("Calling %s %s", localMethod, localRoute)
 		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)
 				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 != "" {
 		if corsHeaders != "" {
 			writeCorsHeaders(w, r, 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 api_version.GreaterThan(api.Version) {
+			http.Error(w, fmt.Errorf("client is newer than server (client API version: %s, server API version: %s)", api_version, api.Version).Error(), http.StatusBadRequest)
 			return
 			return
 		}
 		}
-		if version.LessThan(api.MinVersion) {
+		if api_version.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)
 			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
 			return
 		}
 		}
 
 
 		w.Header().Set("Server", "Docker/"+dockerversion.VERSION+" ("+runtime.GOOS+")")
 		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)
 			logrus.Errorf("Handler for %s %s returned error: %s", localMethod, localRoute, err)
 			httpError(w, err)
 			httpError(w, err)
 		}
 		}

+ 6 - 5
api/server/volume.go

@@ -4,11 +4,12 @@ import (
 	"encoding/json"
 	"encoding/json"
 	"net/http"
 	"net/http"
 
 
+	"golang.org/x/net/context"
+
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types"
-	"github.com/docker/docker/pkg/version"
 )
 )
 
 
-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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -20,7 +21,7 @@ func (s *Server) getVolumesList(version version.Version, w http.ResponseWriter,
 	return writeJSON(w, http.StatusOK, &types.VolumesListResponse{Volumes: volumes})
 	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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -32,7 +33,7 @@ func (s *Server) getVolumeByName(version version.Version, w http.ResponseWriter,
 	return writeJSON(w, http.StatusOK, v)
 	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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}
@@ -53,7 +54,7 @@ func (s *Server) postVolumesCreate(version version.Version, w http.ResponseWrite
 	return writeJSON(w, http.StatusCreated, volume)
 	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 {
 	if err := parseForm(r); err != nil {
 		return err
 		return err
 	}
 	}