Browse Source

Merge pull request #28489 from vieux/1.13.0-rc2-cherrypicks

1.13.0-rc2 cherry-picks : part 2
Brian Goff 8 years ago
parent
commit
f7ae8204cb
100 changed files with 997 additions and 484 deletions
  1. 17 14
      api/server/httputils/errors.go
  2. 3 3
      api/server/router/checkpoint/checkpoint.go
  3. 67 0
      api/server/router/experimental.go
  4. 2 2
      api/server/router/swarm/backend.go
  5. 3 14
      api/server/router/swarm/cluster.go
  6. 5 6
      api/server/router/swarm/cluster_routes.go
  7. 1 1
      api/server/server.go
  8. 36 19
      api/swagger.yaml
  9. 3 1
      api/types/client.go
  10. 12 0
      api/types/service_update_response.go
  11. 1 1
      api/types/swarm/service.go
  12. 1 0
      api/types/versions/v1p24/types.go
  13. 1 1
      api/types/volume.go
  14. 1 1
      api/types/volume/volumes_create.go
  15. 1 1
      builder/dockerfile/evaluator_windows.go
  16. 2 5
      cli/command/checkpoint/cmd.go
  17. 8 0
      cli/command/cli.go
  18. 1 4
      cli/command/container/cmd.go
  19. 16 18
      cli/command/container/list.go
  20. 51 0
      cli/command/container/ps_test.go
  21. 2 2
      cli/command/formatter/container_test.go
  22. 6 0
      cli/command/formatter/service.go
  23. 1 4
      cli/command/image/cmd.go
  24. 4 2
      cli/command/image/load.go
  25. 2 2
      cli/command/image/tag.go
  26. 1 4
      cli/command/network/cmd.go
  27. 1 4
      cli/command/node/cmd.go
  28. 1 4
      cli/command/plugin/cmd.go
  29. 1 5
      cli/command/secret/cmd.go
  30. 1 4
      cli/command/service/cmd.go
  31. 4 0
      cli/command/service/create.go
  32. 5 1
      cli/command/service/scale.go
  33. 5 1
      cli/command/service/update.go
  34. 2 5
      cli/command/stack/cmd.go
  35. 8 3
      cli/command/stack/deploy.go
  36. 1 1
      cli/command/stack/list.go
  37. 1 4
      cli/command/swarm/cmd.go
  38. 1 4
      cli/command/system/cmd.go
  39. 1 4
      cli/command/volume/cmd.go
  40. 1 1
      client/interface.go
  41. 9 3
      client/plugin_install.go
  42. 9 2
      client/service_update.go
  43. 3 3
      client/service_update_test.go
  44. 31 6
      cmd/docker/docker.go
  45. 16 8
      cmd/dockerd/daemon.go
  46. 0 15
      cmd/dockerd/routes_experimental.go
  47. 1 4
      container/health.go
  48. 4 1
      contrib/check-config.sh
  49. 4 2
      contrib/completion/zsh/_docker
  50. 66 37
      daemon/cluster/cluster.go
  51. 2 6
      daemon/commit.go
  52. 0 8
      daemon/create_windows.go
  53. 5 6
      daemon/daemon.go
  54. 8 3
      daemon/daemon_unix.go
  55. 3 1
      daemon/daemon_windows.go
  56. 30 1
      daemon/debugtrap.go
  57. 2 1
      daemon/graphdriver/plugin.go
  58. 2 4
      daemon/graphdriver/windows/windows.go
  59. 22 8
      daemon/health.go
  60. 1 1
      daemon/health_test.go
  61. 1 0
      daemon/image_pull.go
  62. 1 0
      daemon/info_unix.go
  63. 1 0
      daemon/info_windows.go
  64. 2 0
      docs/extend/config.md
  65. 2 2
      docs/extend/index.md
  66. 3 0
      docs/reference/api/docker_remote_api.md
  67. 6 6
      docs/reference/api/docker_remote_api_v1.18.md
  68. 6 6
      docs/reference/api/docker_remote_api_v1.19.md
  69. 7 7
      docs/reference/api/docker_remote_api_v1.20.md
  70. 9 9
      docs/reference/api/docker_remote_api_v1.21.md
  71. 12 9
      docs/reference/api/docker_remote_api_v1.22.md
  72. 13 10
      docs/reference/api/docker_remote_api_v1.23.md
  73. 23 20
      docs/reference/api/docker_remote_api_v1.24.md
  74. 50 36
      docs/reference/api/docker_remote_api_v1.25.md
  75. 19 0
      docs/reference/commandline/images.md
  76. 50 27
      docs/reference/commandline/info.md
  77. 7 4
      docs/reference/commandline/stats.md
  78. 2 2
      docs/reference/commandline/tag.md
  79. 3 3
      hack/dockerfile/binaries-commits
  80. 2 1
      hack/generate-swagger-api.sh
  81. 1 1
      hack/validate/vet
  82. 4 1
      image/tarexport/load.go
  83. 4 2
      image/tarexport/save.go
  84. 1 1
      integration-cli/daemon.go
  85. 23 27
      integration-cli/docker_cli_build_test.go
  86. 1 1
      integration-cli/docker_cli_help_test.go
  87. 16 0
      integration-cli/docker_cli_swarm_test.go
  88. 1 1
      libcontainerd/remote_unix.go
  89. 52 27
      man/docker-info.1.md
  90. 1 1
      man/docker-run.1.md
  91. 2 0
      man/docker-stats.1.md
  92. 2 2
      man/docker-tag.1.md
  93. 1 0
      opts/port.go
  94. 8 3
      pkg/archive/archive.go
  95. 1 1
      pkg/devicemapper/devmapper_wrapper_no_deferred_remove.go
  96. 1 1
      pkg/discovery/backends.go
  97. 4 4
      pkg/ioutils/multireader.go
  98. 21 0
      pkg/ioutils/multireader_test.go
  99. 29 0
      pkg/system/filesys.go
  100. 106 3
      pkg/system/filesys_windows.go

+ 17 - 14
api/server/httputils/errors.go

@@ -28,7 +28,7 @@ type inputValidationError interface {
 	IsValidationError() bool
 }
 
-// GetHTTPErrorStatusCode retrieve status code from error message
+// GetHTTPErrorStatusCode retrieves status code from error message
 func GetHTTPErrorStatusCode(err error) int {
 	if err == nil {
 		logrus.WithFields(logrus.Fields{"error": err}).Error("unexpected HTTP error handling")
@@ -49,20 +49,23 @@ func GetHTTPErrorStatusCode(err error) int {
 		// If we need to differentiate between different possible error types,
 		// we should create appropriate error types that implement the httpStatusError interface.
 		errStr := strings.ToLower(errMsg)
-		for keyword, status := range map[string]int{
-			"not found":             http.StatusNotFound,
-			"no such":               http.StatusNotFound,
-			"bad parameter":         http.StatusBadRequest,
-			"no command":            http.StatusBadRequest,
-			"conflict":              http.StatusConflict,
-			"impossible":            http.StatusNotAcceptable,
-			"wrong login/password":  http.StatusUnauthorized,
-			"unauthorized":          http.StatusUnauthorized,
-			"hasn't been activated": http.StatusForbidden,
-			"this node":             http.StatusNotAcceptable,
+		for _, status := range []struct {
+			keyword string
+			code    int
+		}{
+			{"not found", http.StatusNotFound},
+			{"no such", http.StatusNotFound},
+			{"bad parameter", http.StatusBadRequest},
+			{"no command", http.StatusBadRequest},
+			{"conflict", http.StatusConflict},
+			{"impossible", http.StatusNotAcceptable},
+			{"wrong login/password", http.StatusUnauthorized},
+			{"unauthorized", http.StatusUnauthorized},
+			{"hasn't been activated", http.StatusForbidden},
+			{"this node", http.StatusServiceUnavailable},
 		} {
-			if strings.Contains(errStr, keyword) {
-				statusCode = status
+			if strings.Contains(errStr, status.keyword) {
+				statusCode = status.code
 				break
 			}
 		}

+ 3 - 3
api/server/router/checkpoint/checkpoint.go

@@ -29,8 +29,8 @@ func (r *checkpointRouter) Routes() []router.Route {
 
 func (r *checkpointRouter) initRoutes() {
 	r.routes = []router.Route{
-		router.NewGetRoute("/containers/{name:.*}/checkpoints", r.getContainerCheckpoints),
-		router.NewPostRoute("/containers/{name:.*}/checkpoints", r.postContainerCheckpoint),
-		router.NewDeleteRoute("/containers/{name}/checkpoints/{checkpoint}", r.deleteContainerCheckpoint),
+		router.Experimental(router.NewGetRoute("/containers/{name:.*}/checkpoints", r.getContainerCheckpoints)),
+		router.Experimental(router.NewPostRoute("/containers/{name:.*}/checkpoints", r.postContainerCheckpoint)),
+		router.Experimental(router.NewDeleteRoute("/containers/{name}/checkpoints/{checkpoint}", r.deleteContainerCheckpoint)),
 	}
 }

+ 67 - 0
api/server/router/experimental.go

@@ -0,0 +1,67 @@
+package router
+
+import (
+	"errors"
+	"net/http"
+
+	"golang.org/x/net/context"
+
+	apierrors "github.com/docker/docker/api/errors"
+	"github.com/docker/docker/api/server/httputils"
+)
+
+var (
+	errExperimentalFeature = errors.New("This experimental feature is disabled by default. Start the Docker daemon with --experimental in order to enable it.")
+)
+
+// ExperimentalRoute defines an experimental API route that can be enabled or disabled.
+type ExperimentalRoute interface {
+	Route
+
+	Enable()
+	Disable()
+}
+
+// experimentalRoute defines an experimental API route that can be enabled or disabled.
+// It implements ExperimentalRoute
+type experimentalRoute struct {
+	local   Route
+	handler httputils.APIFunc
+}
+
+// Enable enables this experimental route
+func (r *experimentalRoute) Enable() {
+	r.handler = r.local.Handler()
+}
+
+// Disable disables the experimental route
+func (r *experimentalRoute) Disable() {
+	r.handler = experimentalHandler
+}
+
+func experimentalHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	return apierrors.NewErrorWithStatusCode(errExperimentalFeature, http.StatusNotImplemented)
+}
+
+// Handler returns returns the APIFunc to let the server wrap it in middlewares.
+func (r *experimentalRoute) Handler() httputils.APIFunc {
+	return r.handler
+}
+
+// Method returns the http method that the route responds to.
+func (r *experimentalRoute) Method() string {
+	return r.local.Method()
+}
+
+// Path returns the subpath where the route responds to.
+func (r *experimentalRoute) Path() string {
+	return r.local.Path()
+}
+
+// Experimental will mark a route as experimental.
+func Experimental(r Route) Route {
+	return &experimentalRoute{
+		local:   r,
+		handler: experimentalHandler,
+	}
+}

+ 2 - 2
api/server/router/swarm/backend.go

@@ -18,8 +18,8 @@ type Backend interface {
 	UnlockSwarm(req types.UnlockRequest) error
 	GetServices(basictypes.ServiceListOptions) ([]types.Service, error)
 	GetService(string) (types.Service, error)
-	CreateService(types.ServiceSpec, string) (string, error)
-	UpdateService(string, uint64, types.ServiceSpec, string, string) error
+	CreateService(types.ServiceSpec, string) (*basictypes.ServiceCreateResponse, error)
+	UpdateService(string, uint64, types.ServiceSpec, string, string) (*basictypes.ServiceUpdateResponse, error)
 	RemoveService(string) error
 	ServiceLogs(context.Context, string, *backend.ContainerLogsConfig, chan struct{}) error
 	GetNodes(basictypes.NodeListOptions) ([]types.Node, error)

+ 3 - 14
api/server/router/swarm/cluster.go

@@ -1,9 +1,6 @@
 package swarm
 
-import (
-	"github.com/docker/docker/api/server/router"
-	"github.com/docker/docker/daemon"
-)
+import "github.com/docker/docker/api/server/router"
 
 // swarmRouter is a router to talk with the build controller
 type swarmRouter struct {
@@ -12,14 +9,11 @@ type swarmRouter struct {
 }
 
 // NewRouter initializes a new build router
-func NewRouter(d *daemon.Daemon, b Backend) router.Router {
+func NewRouter(b Backend) router.Router {
 	r := &swarmRouter{
 		backend: b,
 	}
 	r.initRoutes()
-	if d.HasExperimental() {
-		r.addExperimentalRoutes()
-	}
 	return r
 }
 
@@ -28,12 +22,6 @@ func (sr *swarmRouter) Routes() []router.Route {
 	return sr.routes
 }
 
-func (sr *swarmRouter) addExperimentalRoutes() {
-	sr.routes = append(sr.routes,
-		router.Cancellable(router.NewGetRoute("/services/{id}/logs", sr.getServiceLogs)),
-	)
-}
-
 func (sr *swarmRouter) initRoutes() {
 	sr.routes = []router.Route{
 		router.NewPostRoute("/swarm/init", sr.initCluster),
@@ -48,6 +36,7 @@ func (sr *swarmRouter) initRoutes() {
 		router.NewPostRoute("/services/create", sr.createService),
 		router.NewPostRoute("/services/{id}/update", sr.updateService),
 		router.NewDeleteRoute("/services/{id}", sr.removeService),
+		router.Experimental(router.Cancellable(router.NewGetRoute("/services/{id}/logs", sr.getServiceLogs))),
 		router.NewGetRoute("/nodes", sr.getNodes),
 		router.NewGetRoute("/nodes/{id}", sr.getNode),
 		router.NewDeleteRoute("/nodes/{id}", sr.removeNode),

+ 5 - 6
api/server/router/swarm/cluster_routes.go

@@ -166,15 +166,13 @@ func (sr *swarmRouter) createService(ctx context.Context, w http.ResponseWriter,
 	// Get returns "" if the header does not exist
 	encodedAuth := r.Header.Get("X-Registry-Auth")
 
-	id, err := sr.backend.CreateService(service, encodedAuth)
+	resp, err := sr.backend.CreateService(service, encodedAuth)
 	if err != nil {
 		logrus.Errorf("Error creating service %s: %v", service.Name, err)
 		return err
 	}
 
-	return httputils.WriteJSON(w, http.StatusCreated, &basictypes.ServiceCreateResponse{
-		ID: id,
-	})
+	return httputils.WriteJSON(w, http.StatusCreated, resp)
 }
 
 func (sr *swarmRouter) updateService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
@@ -194,11 +192,12 @@ func (sr *swarmRouter) updateService(ctx context.Context, w http.ResponseWriter,
 
 	registryAuthFrom := r.URL.Query().Get("registryAuthFrom")
 
-	if err := sr.backend.UpdateService(vars["id"], version, service, encodedAuth, registryAuthFrom); err != nil {
+	resp, err := sr.backend.UpdateService(vars["id"], version, service, encodedAuth, registryAuthFrom)
+	if err != nil {
 		logrus.Errorf("Error updating service %s: %v", vars["id"], err)
 		return err
 	}
-	return nil
+	return httputils.WriteJSON(w, http.StatusOK, resp)
 }
 
 func (sr *swarmRouter) removeService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {

+ 1 - 1
api/server/server.go

@@ -102,7 +102,7 @@ func (s *Server) serveAPI() error {
 }
 
 // HTTPServer contains an instance of http server and the listener.
-// srv *http.Server, contains configuration to create a http server and a mux router with all api end points.
+// srv *http.Server, contains configuration to create an http server and a mux router with all api end points.
 // l   net.Listener, is a TCP or Socket listener that dispatches incoming request to the router.
 type HTTPServer struct {
 	srv *http.Server

+ 36 - 19
api/swagger.yaml

@@ -2218,6 +2218,16 @@ definitions:
       Deleted:
         description: "The image ID of an image that was deleted"
         type: "string"
+  ServiceUpdateResponse:
+    type: "object"
+    properties:
+      Warnings:
+        description: "Optional warning messages"
+        type: "array"
+        items:
+          type: "string"
+    example:
+      Warning: "unable to pin image doesnotexist:latest to digest: image library/doesnotexist:latest not found"
   ContainerSummary:
     type: "array"
     items:
@@ -6731,14 +6741,14 @@ paths:
           description: "bad parameter"
           schema:
             $ref: "#/definitions/ErrorResponse"
-        406:
-          description: "node is already part of a swarm"
-          schema:
-            $ref: "#/definitions/ErrorResponse"
         500:
           description: "server error"
           schema:
             $ref: "#/definitions/ErrorResponse"
+        503:
+          description: "node is already part of a swarm"
+          schema:
+            $ref: "#/definitions/ErrorResponse"
       parameters:
         - name: "body"
           in: "body"
@@ -6773,14 +6783,14 @@ paths:
       responses:
         200:
           description: "no error"
-        406:
-          description: "node is not part of a swarm"
-          schema:
-            $ref: "#/definitions/ErrorResponse"
         500:
           description: "server error"
           schema:
             $ref: "#/definitions/ErrorResponse"
+        503:
+          description: "node is not part of a swarm"
+          schema:
+            $ref: "#/definitions/ErrorResponse"
       parameters:
         - name: "force"
           description: "Force leave swarm, even if this is the last manager or that it will break the cluster."
@@ -6800,14 +6810,14 @@ paths:
           description: "bad parameter"
           schema:
             $ref: "#/definitions/ErrorResponse"
-        406:
-          description: "node is not part of a swarm"
-          schema:
-            $ref: "#/definitions/ErrorResponse"
         500:
           description: "server error"
           schema:
             $ref: "#/definitions/ErrorResponse"
+        503:
+          description: "node is not part of a swarm"
+          schema:
+            $ref: "#/definitions/ErrorResponse"
       parameters:
         - name: "body"
           in: "body"
@@ -6875,12 +6885,12 @@ paths:
               ID:
                 description: "The ID of the created service."
                 type: "string"
+              Warning:
+                description: "Optional warning message"
+                type: "string"
             example:
               ID: "ak7w3gjqoa3kuz8xcpnyy0pvl"
-        406:
-          description: "server error or node is not part of a swarm"
-          schema:
-            $ref: "#/definitions/ErrorResponse"
+              Warning: "unable to pin image doesnotexist:latest to digest: image library/doesnotexist:latest not found"
         409:
           description: "name conflicts with an existing service"
           schema:
@@ -6889,6 +6899,10 @@ paths:
           description: "server error"
           schema:
             $ref: "#/definitions/ErrorResponse"
+        503:
+          description: "server error or node is not part of a swarm"
+          schema:
+            $ref: "#/definitions/ErrorResponse"
       parameters:
         - name: "body"
           in: "body"
@@ -6998,10 +7012,14 @@ paths:
   /services/{id}/update:
     post:
       summary: "Update a service"
-      operationId: "PostServicesUpdate"
+      operationId: "ServiceUpdate"
+      consumes: ["application/json"]
+      produces: ["application/json"]
       responses:
         200:
           description: "no error"
+          schema:
+            $ref: "#/definitions/ImageDeleteResponse"
         404:
           description: "no such service"
           schema:
@@ -7065,8 +7083,7 @@ paths:
           description: "A base64-encoded auth configuration for pulling from private registries. [See the authentication section for details.](#section/Authentication)"
           type: "string"
 
-      tags:
-        - "Services"
+      tags: [Service]
   /tasks:
     get:
       summary: "List tasks"

+ 3 - 1
api/types/client.go

@@ -285,10 +285,12 @@ type ServiceCreateOptions struct {
 }
 
 // ServiceCreateResponse contains the information returned to a client
-// on the  creation of a new service.
+// on the creation of a new service.
 type ServiceCreateResponse struct {
 	// ID is the ID of the created service.
 	ID string
+	// Warnings is a set of non-fatal warning messages to pass on to the user.
+	Warnings []string `json:",omitempty"`
 }
 
 // Values for RegistryAuthFrom in ServiceUpdateOptions

+ 12 - 0
api/types/service_update_response.go

@@ -0,0 +1,12 @@
+package types
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// ServiceUpdateResponse service update response
+// swagger:model ServiceUpdateResponse
+type ServiceUpdateResponse struct {
+
+	// Optional warning messages
+	Warnings []string `json:"Warnings"`
+}

+ 1 - 1
api/types/swarm/service.go

@@ -74,7 +74,7 @@ const (
 type UpdateConfig struct {
 	// Maximum number of tasks to be updated in one iteration.
 	// 0 means unlimited parallelism.
-	Parallelism uint64 `json:",omitempty"`
+	Parallelism uint64
 
 	// Amount of time between updates.
 	Delay time.Duration `json:",omitempty"`

+ 1 - 0
api/types/versions/v1p24/types.go

@@ -3,6 +3,7 @@ package v1p24
 
 import "github.com/docker/docker/api/types"
 
+// Info is a backcompatibility struct for the API 1.24
 type Info struct {
 	*types.InfoBase
 	ExecutionDriver string

+ 1 - 1
api/types/volume.go

@@ -11,7 +11,7 @@ type Volume struct {
 	// Required: true
 	Driver string `json:"Driver"`
 
-	// A mapping of abitrary key/value data set on this volume.
+	// User-defined key/value metadata.
 	// Required: true
 	Labels map[string]string `json:"Labels"`
 

+ 1 - 1
api/types/volume/volumes_create.go

@@ -19,7 +19,7 @@ type VolumesCreateBody struct {
 	// Required: true
 	DriverOpts map[string]string `json:"DriverOpts"`
 
-	// A mapping of arbitrary key/value data to set on the volume.
+	// User-defined key/value metadata.
 	// Required: true
 	Labels map[string]string `json:"Labels"`
 

+ 1 - 1
builder/dockerfile/evaluator_windows.go

@@ -6,7 +6,7 @@ import "fmt"
 // a command not supported on the platform.
 func platformSupports(command string) error {
 	switch command {
-	case "user", "stopsignal":
+	case "stopsignal":
 		return fmt.Errorf("The daemon on this platform does not support the command '%s'", command)
 	}
 	return nil

+ 2 - 5
cli/command/checkpoint/cmd.go

@@ -12,11 +12,8 @@ func NewCheckpointCommand(dockerCli *command.DockerCli) *cobra.Command {
 		Use:   "checkpoint",
 		Short: "Manage checkpoints",
 		Args:  cli.NoArgs,
-		Run: func(cmd *cobra.Command, args []string) {
-			cmd.SetOutput(dockerCli.Err())
-			cmd.HelpFunc()(cmd, args)
-		},
-		Tags: map[string]string{"experimental": "", "version": "1.25"},
+		RunE:  dockerCli.ShowHelp,
+		Tags:  map[string]string{"experimental": "", "version": "1.25"},
 	}
 	cmd.AddCommand(
 		newCreateCommand(dockerCli),

+ 8 - 0
cli/command/cli.go

@@ -20,6 +20,7 @@ import (
 	dopts "github.com/docker/docker/opts"
 	"github.com/docker/go-connections/sockets"
 	"github.com/docker/go-connections/tlsconfig"
+	"github.com/spf13/cobra"
 	"golang.org/x/net/context"
 )
 
@@ -73,6 +74,13 @@ func (cli *DockerCli) In() *InStream {
 	return cli.in
 }
 
+// ShowHelp shows the command help.
+func (cli *DockerCli) ShowHelp(cmd *cobra.Command, args []string) error {
+	cmd.SetOutput(cli.err)
+	cmd.HelpFunc()(cmd, args)
+	return nil
+}
+
 // ConfigFile returns the ConfigFile
 func (cli *DockerCli) ConfigFile() *configfile.ConfigFile {
 	return cli.configFile

+ 1 - 4
cli/command/container/cmd.go

@@ -13,10 +13,7 @@ func NewContainerCommand(dockerCli *command.DockerCli) *cobra.Command {
 		Use:   "container",
 		Short: "Manage containers",
 		Args:  cli.NoArgs,
-		Run: func(cmd *cobra.Command, args []string) {
-			cmd.SetOutput(dockerCli.Err())
-			cmd.HelpFunc()(cmd, args)
-		},
+		RunE:  dockerCli.ShowHelp,
 	}
 	cmd.AddCommand(
 		NewAttachCommand(dockerCli),

+ 16 - 18
cli/command/container/list.go

@@ -59,20 +59,18 @@ func newListCommand(dockerCli *command.DockerCli) *cobra.Command {
 	return &cmd
 }
 
-type preProcessor struct {
-	types.Container
-	opts *types.ContainerListOptions
-
-	// Fields that need to exist so the template doesn't error out
-	// These are needed since they are available on the final object but are not
-	// fields in types.Container
-	// TODO(cpuguy83): this seems rather broken
-	Networks, CreatedAt, RunningFor bool
-}
-
-// Size sets the size option when called by a template execution.
-func (p *preProcessor) Size() bool {
-	p.opts.Size = true
+// listOptionsProcessor is used to set any container list options which may only
+// be embedded in the format template.
+// This is passed directly into tmpl.Execute in order to allow the preprocessor
+// to set any list options that were not provided by flags (e.g. `.Size`).
+// It is using a `map[string]bool` so that unknown fields passed into the
+// template format do not cause errors. These errors will get picked up when
+// running through the actual template processor.
+type listOptionsProcessor map[string]bool
+
+// Size sets the size of the map when called by a template execution.
+func (o listOptionsProcessor) Size() bool {
+	o["size"] = true
 	return true
 }
 
@@ -88,20 +86,20 @@ func buildContainerListOptions(opts *psOptions) (*types.ContainerListOptions, er
 		options.Limit = 1
 	}
 
-	// Currently only used with Size, so we can determine if the user
-	// put {{.Size}} in their format.
-	pre := &preProcessor{opts: options}
 	tmpl, err := templates.Parse(opts.format)
 
 	if err != nil {
 		return nil, err
 	}
 
+	optionsProcessor := listOptionsProcessor{}
 	// This shouldn't error out but swallowing the error makes it harder
 	// to track down if preProcessor issues come up. Ref #24696
-	if err := tmpl.Execute(ioutil.Discard, pre); err != nil {
+	if err := tmpl.Execute(ioutil.Discard, optionsProcessor); err != nil {
 		return nil, err
 	}
+	// At the moment all we need is to capture .Size for preprocessor
+	options.Size = opts.size || optionsProcessor["size"]
 
 	return options, nil
 }

+ 51 - 0
cli/command/container/ps_test.go

@@ -46,6 +46,57 @@ func TestBuildContainerListOptions(t *testing.T) {
 			expectedLimit:   1,
 			expectedFilters: make(map[string]string),
 		},
+		{
+			psOpts: &psOptions{
+				all:    true,
+				size:   false,
+				last:   5,
+				filter: filters,
+				// With .Size, size should be true
+				format: "{{.Size}}",
+			},
+			expectedAll:   true,
+			expectedSize:  true,
+			expectedLimit: 5,
+			expectedFilters: map[string]string{
+				"foo": "bar",
+				"baz": "foo",
+			},
+		},
+		{
+			psOpts: &psOptions{
+				all:    true,
+				size:   false,
+				last:   5,
+				filter: filters,
+				// With .Size, size should be true
+				format: "{{.Size}} {{.CreatedAt}} {{.Networks}}",
+			},
+			expectedAll:   true,
+			expectedSize:  true,
+			expectedLimit: 5,
+			expectedFilters: map[string]string{
+				"foo": "bar",
+				"baz": "foo",
+			},
+		},
+		{
+			psOpts: &psOptions{
+				all:    true,
+				size:   false,
+				last:   5,
+				filter: filters,
+				// Without .Size, size should be false
+				format: "{{.CreatedAt}} {{.Networks}}",
+			},
+			expectedAll:   true,
+			expectedSize:  false,
+			expectedLimit: 5,
+			expectedFilters: map[string]string{
+				"foo": "bar",
+				"baz": "foo",
+			},
+		},
 	}
 
 	for _, c := range contexts {

+ 2 - 2
cli/command/formatter/container_test.go

@@ -372,7 +372,7 @@ func TestContainerContextWriteJSONField(t *testing.T) {
 }
 
 func TestContainerBackCompat(t *testing.T) {
-	containers := []types.Container{types.Container{ID: "brewhaha"}}
+	containers := []types.Container{{ID: "brewhaha"}}
 	cases := []string{
 		"ID",
 		"Names",
@@ -390,7 +390,7 @@ func TestContainerBackCompat(t *testing.T) {
 	for _, c := range cases {
 		ctx := Context{Format: Format(fmt.Sprintf("{{ .%s }}", c)), Output: buf}
 		if err := ContainerWrite(ctx, containers); err != nil {
-			t.Log("could not render template for field '%s': %v", c, err)
+			t.Logf("could not render template for field '%s': %v", c, err)
 			t.Fail()
 		}
 		buf.Reset()

+ 6 - 0
cli/command/formatter/service.go

@@ -263,6 +263,9 @@ func (ctx *serviceInspectContext) HasResources() bool {
 }
 
 func (ctx *serviceInspectContext) HasResourceReservations() bool {
+	if ctx.Service.Spec.TaskTemplate.Resources == nil || ctx.Service.Spec.TaskTemplate.Resources.Reservations == nil {
+		return false
+	}
 	return ctx.Service.Spec.TaskTemplate.Resources.Reservations.NanoCPUs > 0 || ctx.Service.Spec.TaskTemplate.Resources.Reservations.MemoryBytes > 0
 }
 
@@ -281,6 +284,9 @@ func (ctx *serviceInspectContext) ResourceReservationMemory() string {
 }
 
 func (ctx *serviceInspectContext) HasResourceLimits() bool {
+	if ctx.Service.Spec.TaskTemplate.Resources == nil || ctx.Service.Spec.TaskTemplate.Resources.Limits == nil {
+		return false
+	}
 	return ctx.Service.Spec.TaskTemplate.Resources.Limits.NanoCPUs > 0 || ctx.Service.Spec.TaskTemplate.Resources.Limits.MemoryBytes > 0
 }
 

+ 1 - 4
cli/command/image/cmd.go

@@ -13,10 +13,7 @@ func NewImageCommand(dockerCli *command.DockerCli) *cobra.Command {
 		Use:   "image",
 		Short: "Manage images",
 		Args:  cli.NoArgs,
-		Run: func(cmd *cobra.Command, args []string) {
-			cmd.SetOutput(dockerCli.Err())
-			cmd.HelpFunc()(cmd, args)
-		},
+		RunE:  dockerCli.ShowHelp,
 	}
 	cmd.AddCommand(
 		NewBuildCommand(dockerCli),

+ 4 - 2
cli/command/image/load.go

@@ -3,13 +3,13 @@ package image
 import (
 	"fmt"
 	"io"
-	"os"
 
 	"golang.org/x/net/context"
 
 	"github.com/docker/docker/cli"
 	"github.com/docker/docker/cli/command"
 	"github.com/docker/docker/pkg/jsonmessage"
+	"github.com/docker/docker/pkg/system"
 	"github.com/spf13/cobra"
 )
 
@@ -43,7 +43,9 @@ func runLoad(dockerCli *command.DockerCli, opts loadOptions) error {
 
 	var input io.Reader = dockerCli.In()
 	if opts.input != "" {
-		file, err := os.Open(opts.input)
+		// We use system.OpenSequential to use sequential file access on Windows, avoiding
+		// depleting the standby list un-necessarily. On Linux, this equates to a regular os.Open.
+		file, err := system.OpenSequential(opts.input)
 		if err != nil {
 			return err
 		}

+ 2 - 2
cli/command/image/tag.go

@@ -18,8 +18,8 @@ func NewTagCommand(dockerCli *command.DockerCli) *cobra.Command {
 	var opts tagOptions
 
 	cmd := &cobra.Command{
-		Use:   "tag IMAGE[:TAG] IMAGE[:TAG]",
-		Short: "Tag an image into a repository",
+		Use:   "tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]",
+		Short: "Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE",
 		Args:  cli.ExactArgs(2),
 		RunE: func(cmd *cobra.Command, args []string) error {
 			opts.image = args[0]

+ 1 - 4
cli/command/network/cmd.go

@@ -13,10 +13,7 @@ func NewNetworkCommand(dockerCli *command.DockerCli) *cobra.Command {
 		Use:   "network",
 		Short: "Manage networks",
 		Args:  cli.NoArgs,
-		Run: func(cmd *cobra.Command, args []string) {
-			cmd.SetOutput(dockerCli.Err())
-			cmd.HelpFunc()(cmd, args)
-		},
+		RunE:  dockerCli.ShowHelp,
 	}
 	cmd.AddCommand(
 		newConnectCommand(dockerCli),

+ 1 - 4
cli/command/node/cmd.go

@@ -14,10 +14,7 @@ func NewNodeCommand(dockerCli *command.DockerCli) *cobra.Command {
 		Use:   "node",
 		Short: "Manage Swarm nodes",
 		Args:  cli.NoArgs,
-		Run: func(cmd *cobra.Command, args []string) {
-			cmd.SetOutput(dockerCli.Err())
-			cmd.HelpFunc()(cmd, args)
-		},
+		RunE:  dockerCli.ShowHelp,
 	}
 	cmd.AddCommand(
 		newDemoteCommand(dockerCli),

+ 1 - 4
cli/command/plugin/cmd.go

@@ -12,10 +12,7 @@ func NewPluginCommand(dockerCli *command.DockerCli) *cobra.Command {
 		Use:   "plugin",
 		Short: "Manage plugins",
 		Args:  cli.NoArgs,
-		Run: func(cmd *cobra.Command, args []string) {
-			cmd.SetOutput(dockerCli.Err())
-			cmd.HelpFunc()(cmd, args)
-		},
+		RunE:  dockerCli.ShowHelp,
 	}
 
 	cmd.AddCommand(

+ 1 - 5
cli/command/secret/cmd.go

@@ -1,8 +1,6 @@
 package secret
 
 import (
-	"fmt"
-
 	"github.com/spf13/cobra"
 
 	"github.com/docker/docker/cli"
@@ -15,9 +13,7 @@ func NewSecretCommand(dockerCli *command.DockerCli) *cobra.Command {
 		Use:   "secret",
 		Short: "Manage Docker secrets",
 		Args:  cli.NoArgs,
-		Run: func(cmd *cobra.Command, args []string) {
-			fmt.Fprintf(dockerCli.Err(), "\n"+cmd.UsageString())
-		},
+		RunE:  dockerCli.ShowHelp,
 	}
 	cmd.AddCommand(
 		newSecretListCommand(dockerCli),

+ 1 - 4
cli/command/service/cmd.go

@@ -13,10 +13,7 @@ func NewServiceCommand(dockerCli *command.DockerCli) *cobra.Command {
 		Use:   "service",
 		Short: "Manage services",
 		Args:  cli.NoArgs,
-		Run: func(cmd *cobra.Command, args []string) {
-			cmd.SetOutput(dockerCli.Err())
-			cmd.HelpFunc()(cmd, args)
-		},
+		RunE:  dockerCli.ShowHelp,
 	}
 	cmd.AddCommand(
 		newCreateCommand(dockerCli),

+ 4 - 0
cli/command/service/create.go

@@ -90,6 +90,10 @@ func runCreate(dockerCli *command.DockerCli, opts *serviceOptions) error {
 		return err
 	}
 
+	for _, warning := range response.Warnings {
+		fmt.Fprintln(dockerCli.Err(), warning)
+	}
+
 	fmt.Fprintf(dockerCli.Out(), "%s\n", response.ID)
 	return nil
 }

+ 5 - 1
cli/command/service/scale.go

@@ -82,11 +82,15 @@ func runServiceScale(dockerCli *command.DockerCli, serviceID string, scale uint6
 
 	serviceMode.Replicated.Replicas = &scale
 
-	err = client.ServiceUpdate(ctx, service.ID, service.Version, service.Spec, types.ServiceUpdateOptions{})
+	response, err := client.ServiceUpdate(ctx, service.ID, service.Version, service.Spec, types.ServiceUpdateOptions{})
 	if err != nil {
 		return err
 	}
 
+	for _, warning := range response.Warnings {
+		fmt.Fprintln(dockerCli.Err(), warning)
+	}
+
 	fmt.Fprintf(dockerCli.Out(), "%s scaled to %d\n", serviceID, scale)
 	return nil
 }

+ 5 - 1
cli/command/service/update.go

@@ -133,11 +133,15 @@ func runUpdate(dockerCli *command.DockerCli, flags *pflag.FlagSet, serviceID str
 		updateOpts.RegistryAuthFrom = types.RegistryAuthFromSpec
 	}
 
-	err = apiClient.ServiceUpdate(ctx, service.ID, service.Version, *spec, updateOpts)
+	response, err := apiClient.ServiceUpdate(ctx, service.ID, service.Version, *spec, updateOpts)
 	if err != nil {
 		return err
 	}
 
+	for _, warning := range response.Warnings {
+		fmt.Fprintln(dockerCli.Err(), warning)
+	}
+
 	fmt.Fprintf(dockerCli.Out(), "%s\n", serviceID)
 	return nil
 }

+ 2 - 5
cli/command/stack/cmd.go

@@ -12,11 +12,8 @@ func NewStackCommand(dockerCli *command.DockerCli) *cobra.Command {
 		Use:   "stack",
 		Short: "Manage Docker stacks",
 		Args:  cli.NoArgs,
-		Run: func(cmd *cobra.Command, args []string) {
-			cmd.SetOutput(dockerCli.Err())
-			cmd.HelpFunc()(cmd, args)
-		},
-		Tags: map[string]string{"experimental": "", "version": "1.25"},
+		RunE:  dockerCli.ShowHelp,
+		Tags:  map[string]string{"experimental": "", "version": "1.25"},
 	}
 	cmd.AddCommand(
 		newDeployCommand(dockerCli),

+ 8 - 3
cli/command/stack/deploy.go

@@ -408,15 +408,20 @@ func deployServices(
 			if sendAuth {
 				updateOpts.EncodedRegistryAuth = encodedAuth
 			}
-			if err := apiClient.ServiceUpdate(
+			response, err := apiClient.ServiceUpdate(
 				ctx,
 				service.ID,
 				service.Version,
 				serviceSpec,
 				updateOpts,
-			); err != nil {
+			)
+			if err != nil {
 				return err
 			}
+
+			for _, warning := range response.Warnings {
+				fmt.Fprintln(dockerCli.Err(), warning)
+			}
 		} else {
 			fmt.Fprintf(out, "Creating service %s\n", name)
 
@@ -526,7 +531,7 @@ func convertService(
 func convertExtraHosts(extraHosts map[string]string) []string {
 	hosts := []string{}
 	for host, ip := range extraHosts {
-		hosts = append(hosts, fmt.Sprintf("%s %s", host, ip))
+		hosts = append(hosts, fmt.Sprintf("%s %s", ip, host))
 	}
 	return hosts
 }

+ 1 - 1
cli/command/stack/list.go

@@ -72,7 +72,7 @@ func printTable(out io.Writer, stacks []*stack) {
 
 type stack struct {
 	// Name is the name of the stack
-	Name     string
+	Name string
 	// Services is the number of the services
 	Services int
 }

+ 1 - 4
cli/command/swarm/cmd.go

@@ -13,10 +13,7 @@ func NewSwarmCommand(dockerCli *command.DockerCli) *cobra.Command {
 		Use:   "swarm",
 		Short: "Manage Swarm",
 		Args:  cli.NoArgs,
-		Run: func(cmd *cobra.Command, args []string) {
-			cmd.SetOutput(dockerCli.Err())
-			cmd.HelpFunc()(cmd, args)
-		},
+		RunE:  dockerCli.ShowHelp,
 	}
 	cmd.AddCommand(
 		newInitCommand(dockerCli),

+ 1 - 4
cli/command/system/cmd.go

@@ -13,10 +13,7 @@ func NewSystemCommand(dockerCli *command.DockerCli) *cobra.Command {
 		Use:   "system",
 		Short: "Manage Docker",
 		Args:  cli.NoArgs,
-		Run: func(cmd *cobra.Command, args []string) {
-			cmd.SetOutput(dockerCli.Err())
-			cmd.HelpFunc()(cmd, args)
-		},
+		RunE:  dockerCli.ShowHelp,
 	}
 	cmd.AddCommand(
 		NewEventsCommand(dockerCli),

+ 1 - 4
cli/command/volume/cmd.go

@@ -14,10 +14,7 @@ func NewVolumeCommand(dockerCli *command.DockerCli) *cobra.Command {
 		Short: "Manage volumes",
 		Long:  volumeDescription,
 		Args:  cli.NoArgs,
-		Run: func(cmd *cobra.Command, args []string) {
-			cmd.SetOutput(dockerCli.Err())
-			cmd.HelpFunc()(cmd, args)
-		},
+		RunE:  dockerCli.ShowHelp,
 	}
 	cmd.AddCommand(
 		newCreateCommand(dockerCli),

+ 1 - 1
client/interface.go

@@ -124,7 +124,7 @@ type ServiceAPIClient interface {
 	ServiceInspectWithRaw(ctx context.Context, serviceID string) (swarm.Service, []byte, error)
 	ServiceList(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error)
 	ServiceRemove(ctx context.Context, serviceID string) error
-	ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) error
+	ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (types.ServiceUpdateResponse, error)
 	ServiceLogs(ctx context.Context, serviceID string, options types.ContainerLogsOptions) (io.ReadCloser, error)
 	TaskInspectWithRaw(ctx context.Context, taskID string) (swarm.Task, []byte, error)
 	TaskList(ctx context.Context, options types.TaskListOptions) ([]swarm.Task, error)

+ 9 - 3
client/plugin_install.go

@@ -10,7 +10,7 @@ import (
 )
 
 // PluginInstall installs a plugin
-func (cli *Client) PluginInstall(ctx context.Context, name string, options types.PluginInstallOptions) error {
+func (cli *Client) PluginInstall(ctx context.Context, name string, options types.PluginInstallOptions) (err error) {
 	// FIXME(vdemeester) name is a ref, we might want to parse/validate it here.
 	query := url.Values{}
 	query.Set("name", name)
@@ -27,6 +27,14 @@ func (cli *Client) PluginInstall(ctx context.Context, name string, options types
 		ensureReaderClosed(resp)
 		return err
 	}
+
+	defer func() {
+		if err != nil {
+			delResp, _ := cli.delete(ctx, "/plugins/"+name, nil, nil)
+			ensureReaderClosed(delResp)
+		}
+	}()
+
 	var privileges types.PluginPrivileges
 	if err := json.NewDecoder(resp.body).Decode(&privileges); err != nil {
 		ensureReaderClosed(resp)
@@ -40,8 +48,6 @@ func (cli *Client) PluginInstall(ctx context.Context, name string, options types
 			return err
 		}
 		if !accept {
-			resp, _ := cli.delete(ctx, "/plugins/"+name, nil, nil)
-			ensureReaderClosed(resp)
 			return pluginPermissionDenied{name}
 		}
 	}

+ 9 - 2
client/service_update.go

@@ -1,6 +1,7 @@
 package client
 
 import (
+	"encoding/json"
 	"net/url"
 	"strconv"
 
@@ -10,7 +11,7 @@ import (
 )
 
 // ServiceUpdate updates a Service.
-func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) error {
+func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (types.ServiceUpdateResponse, error) {
 	var (
 		headers map[string][]string
 		query   = url.Values{}
@@ -28,7 +29,13 @@ func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version
 
 	query.Set("version", strconv.FormatUint(version.Index, 10))
 
+	var response types.ServiceUpdateResponse
 	resp, err := cli.post(ctx, "/services/"+serviceID+"/update", query, service, headers)
+	if err != nil {
+		return response, err
+	}
+
+	err = json.NewDecoder(resp.body).Decode(&response)
 	ensureReaderClosed(resp)
-	return err
+	return response, err
 }

+ 3 - 3
client/service_update_test.go

@@ -19,7 +19,7 @@ func TestServiceUpdateError(t *testing.T) {
 		client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
 	}
 
-	err := client.ServiceUpdate(context.Background(), "service_id", swarm.Version{}, swarm.ServiceSpec{}, types.ServiceUpdateOptions{})
+	_, err := client.ServiceUpdate(context.Background(), "service_id", swarm.Version{}, swarm.ServiceSpec{}, types.ServiceUpdateOptions{})
 	if err == nil || err.Error() != "Error response from daemon: Server error" {
 		t.Fatalf("expected a Server Error, got %v", err)
 	}
@@ -64,12 +64,12 @@ func TestServiceUpdate(t *testing.T) {
 				}
 				return &http.Response{
 					StatusCode: http.StatusOK,
-					Body:       ioutil.NopCloser(bytes.NewReader([]byte("body"))),
+					Body:       ioutil.NopCloser(bytes.NewReader([]byte("{}"))),
 				}, nil
 			}),
 		}
 
-		err := client.ServiceUpdate(context.Background(), "service_id", updateCase.swarmVersion, swarm.ServiceSpec{}, types.ServiceUpdateOptions{})
+		_, err := client.ServiceUpdate(context.Background(), "service_id", updateCase.swarmVersion, swarm.ServiceSpec{}, types.ServiceUpdateOptions{})
 		if err != nil {
 			t.Fatal(err)
 		}

+ 31 - 6
cmd/docker/docker.go

@@ -1,6 +1,7 @@
 package main
 
 import (
+	"errors"
 	"fmt"
 	"os"
 
@@ -34,27 +35,37 @@ func newDockerCommand(dockerCli *command.DockerCli) *cobra.Command {
 				showVersion()
 				return nil
 			}
-			cmd.SetOutput(dockerCli.Err())
-			cmd.HelpFunc()(cmd, args)
-			return nil
+			return dockerCli.ShowHelp(cmd, args)
 		},
 		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+			// daemon command is special, we redirect directly to another binary
+			if cmd.Name() == "daemon" {
+				return nil
+			}
 			// flags must be the top-level command flags, not cmd.Flags()
 			opts.Common.SetDefaultOptions(flags)
 			dockerPreRun(opts)
-			return dockerCli.Initialize(opts)
+			if err := dockerCli.Initialize(opts); err != nil {
+				return err
+			}
+			return isSupported(cmd, dockerCli.Client().ClientVersion(), dockerCli.HasExperimental())
 		},
 	}
 	cli.SetupRootCommand(cmd)
 
 	cmd.SetHelpFunc(func(ccmd *cobra.Command, args []string) {
-		if dockerCli.Client() == nil {
+		if dockerCli.Client() == nil { // when using --help, PersistenPreRun is not called, so initialization is needed.
 			// flags must be the top-level command flags, not cmd.Flags()
 			opts.Common.SetDefaultOptions(flags)
 			dockerPreRun(opts)
 			dockerCli.Initialize(opts)
 		}
 
+		if err := isSupported(ccmd, dockerCli.Client().ClientVersion(), dockerCli.HasExperimental()); err != nil {
+			ccmd.Println(err)
+			return
+		}
+
 		hideUnsupportedFeatures(ccmd, dockerCli.Client().ClientVersion(), dockerCli.HasExperimental())
 
 		if err := ccmd.Help(); err != nil {
@@ -79,7 +90,7 @@ func noArgs(cmd *cobra.Command, args []string) error {
 		return nil
 	}
 	return fmt.Errorf(
-		"docker: '%s' is not a docker command.\nSee 'docker --help'.", args[0])
+		"docker: '%s' is not a docker command.\nSee 'docker --help'", args[0])
 }
 
 func main() {
@@ -153,3 +164,17 @@ func hideUnsupportedFeatures(cmd *cobra.Command, clientVersion string, hasExperi
 		}
 	}
 }
+
+func isSupported(cmd *cobra.Command, clientVersion string, hasExperimental bool) error {
+	if !hasExperimental {
+		if _, ok := cmd.Tags["experimental"]; ok {
+			return errors.New("only supported with experimental daemon")
+		}
+	}
+
+	if cmdVersion, ok := cmd.Tags["version"]; ok && versions.LessThan(clientVersion, cmdVersion) {
+		return fmt.Errorf("only supported with daemon version >= %s", cmdVersion)
+	}
+
+	return nil
+}

+ 16 - 8
cmd/dockerd/daemon.go

@@ -17,6 +17,7 @@ import (
 	"github.com/docker/docker/api/server/middleware"
 	"github.com/docker/docker/api/server/router"
 	"github.com/docker/docker/api/server/router/build"
+	checkpointrouter "github.com/docker/docker/api/server/router/checkpoint"
 	"github.com/docker/docker/api/server/router/container"
 	"github.com/docker/docker/api/server/router/image"
 	"github.com/docker/docker/api/server/router/network"
@@ -461,25 +462,32 @@ func loadDaemonCliConfig(opts daemonOptions) (*daemon.Config, error) {
 func initRouter(s *apiserver.Server, d *daemon.Daemon, c *cluster.Cluster) {
 	decoder := runconfig.ContainerDecoder{}
 
-	routers := []router.Router{}
-
-	// we need to add the checkpoint router before the container router or the DELETE gets masked
-	routers = addExperimentalRouters(routers, d, decoder)
-
-	routers = append(routers, []router.Router{
+	routers := []router.Router{
+		// we need to add the checkpoint router before the container router or the DELETE gets masked
+		checkpointrouter.NewRouter(d, decoder),
 		container.NewRouter(d, decoder),
 		image.NewRouter(d, decoder),
 		systemrouter.NewRouter(d, c),
 		volume.NewRouter(d),
 		build.NewRouter(dockerfile.NewBuildManager(d)),
-		swarmrouter.NewRouter(d, c),
+		swarmrouter.NewRouter(c),
 		pluginrouter.NewRouter(plugin.GetManager()),
-	}...)
+	}
 
 	if d.NetworkControllerEnabled() {
 		routers = append(routers, network.NewRouter(d, c))
 	}
 
+	if d.HasExperimental() {
+		for _, r := range routers {
+			for _, route := range r.Routes() {
+				if experimental, ok := route.(router.ExperimentalRoute); ok {
+					experimental.Enable()
+				}
+			}
+		}
+	}
+
 	s.InitRouter(utils.IsDebugEnabled(), routers...)
 }
 

+ 0 - 15
cmd/dockerd/routes_experimental.go

@@ -1,15 +0,0 @@
-package main
-
-import (
-	"github.com/docker/docker/api/server/httputils"
-	"github.com/docker/docker/api/server/router"
-	checkpointrouter "github.com/docker/docker/api/server/router/checkpoint"
-	"github.com/docker/docker/daemon"
-)
-
-func addExperimentalRouters(routers []router.Router, d *daemon.Daemon, decoder httputils.ContainerDecoder) []router.Router {
-	if !d.HasExperimental() {
-		return []router.Router{}
-	}
-	return append(routers, checkpointrouter.NewRouter(d, decoder))
-}

+ 1 - 4
container/health.go

@@ -42,10 +42,7 @@ func (s *Health) OpenMonitorChannel() chan struct{} {
 func (s *Health) CloseMonitorChannel() {
 	if s.stop != nil {
 		logrus.Debug("CloseMonitorChannel: waiting for probe to stop")
-		// This channel does not buffer. Once the write succeeds, the monitor
-		// has read the stop request and will not make any further updates
-		// to c.State.Health.
-		s.stop <- struct{}{}
+		close(s.stop)
 		s.stop = nil
 		logrus.Debug("CloseMonitorChannel done")
 	}

+ 4 - 1
contrib/check-config.sh

@@ -188,7 +188,6 @@ fi
 
 flags=(
 	NAMESPACES {NET,PID,IPC,UTS}_NS
-	DEVPTS_MULTIPLE_INSTANCES
 	CGROUPS CGROUP_CPUACCT CGROUP_DEVICE CGROUP_FREEZER CGROUP_SCHED CPUSETS MEMCG
 	KEYS
 	VETH BRIDGE BRIDGE_NETFILTER
@@ -200,6 +199,10 @@ flags=(
 	POSIX_MQUEUE
 )
 check_flags "${flags[@]}"
+if [ "$kernelMajor" -lt 4 ] || [ "$kernelMajor" -eq 4 -a "$kernelMinor" -lt 8 ]; then
+        check_flags DEVPTS_MULTIPLE_INSTANCES
+fi
+
 echo
 
 echo 'Optional Features:'

+ 4 - 2
contrib/completion/zsh/_docker

@@ -1961,7 +1961,7 @@ __docker_swarm_subcommand() {
 __docker_system_commands() {
     local -a _docker_system_subcommands
     _docker_system_subcommands=(
-        "df:Show docker disk usage"
+        "df:Show docker filesystem usage"
         "events:Get real time events from the server"
         "info:Display system-wide information"
         "prune:Remove unused data"
@@ -1978,7 +1978,9 @@ __docker_system_subcommand() {
 
     case "$words[1]" in
         (df)
-            # @TODO
+            _arguments $(__docker_arguments) \
+                $opts_help \
+                "($help -v --verbose)"{-v,--verbose}"[Show detailed information on space usage]" && ret=0
             ;;
         (events)
             _arguments $(__docker_arguments) \

+ 66 - 37
daemon/cluster/cluster.go

@@ -16,6 +16,7 @@ import (
 	"time"
 
 	"github.com/Sirupsen/logrus"
+	distreference "github.com/docker/distribution/reference"
 	apierrors "github.com/docker/docker/api/errors"
 	apitypes "github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/backend"
@@ -69,7 +70,7 @@ var ErrSwarmJoinTimeoutReached = fmt.Errorf("Timeout was reached before node was
 // ErrSwarmLocked is returned if the swarm is encrypted and needs a key to unlock it.
 var ErrSwarmLocked = fmt.Errorf("Swarm is encrypted and needs to be unlocked before it can be used. Please use \"docker swarm unlock\" to unlock it.")
 
-// ErrSwarmCertificatesExipred is returned if docker was not started for the whole validity period and they had no chance to renew automatically.
+// ErrSwarmCertificatesExpired is returned if docker was not started for the whole validity period and they had no chance to renew automatically.
 var ErrSwarmCertificatesExpired = errors.New("Swarm certificates have expired. To replace them, leave the swarm and join again.")
 
 // NetworkSubnetsProvider exposes functions for retrieving the subnets
@@ -587,6 +588,15 @@ func (c *Cluster) GetUnlockKey() (string, error) {
 
 // UnlockSwarm provides a key to decrypt data that is encrypted at rest.
 func (c *Cluster) UnlockSwarm(req types.UnlockRequest) error {
+	c.RLock()
+	if !c.isActiveManager() {
+		if err := c.errNoManager(); err != ErrSwarmLocked {
+			c.RUnlock()
+			return err
+		}
+	}
+	c.RUnlock()
+
 	key, err := encryption.ParseHumanReadableKey(req.UnlockKey)
 	if err != nil {
 		return err
@@ -1008,16 +1018,25 @@ func (c *Cluster) GetServices(options apitypes.ServiceListOptions) ([]types.Serv
 
 // imageWithDigestString takes an image such as name or name:tag
 // and returns the image pinned to a digest, such as name@sha256:34234...
+// Due to the difference between the docker/docker/reference, and the
+// docker/distribution/reference packages, we're parsing the image twice.
+// As the two packages converge, this function should be simplified.
+// TODO(nishanttotla): After the packages converge, the function must
+// convert distreference.Named -> distreference.Canonical, and the logic simplified.
 func (c *Cluster) imageWithDigestString(ctx context.Context, image string, authConfig *apitypes.AuthConfig) (string, error) {
-	ref, err := reference.ParseNamed(image)
+	ref, err := distreference.ParseNamed(image)
 	if err != nil {
 		return "", err
 	}
 	// only query registry if not a canonical reference (i.e. with digest)
-	if _, ok := ref.(reference.Canonical); !ok {
-		ref = reference.WithDefaultTag(ref)
-
-		namedTaggedRef, ok := ref.(reference.NamedTagged)
+	if _, ok := ref.(distreference.Canonical); !ok {
+		// create a docker/docker/reference Named object because GetRepository needs it
+		dockerRef, err := reference.ParseNamed(image)
+		if err != nil {
+			return "", err
+		}
+		dockerRef = reference.WithDefaultTag(dockerRef)
+		namedTaggedRef, ok := dockerRef.(reference.NamedTagged)
 		if !ok {
 			return "", fmt.Errorf("unable to cast image to NamedTagged reference object")
 		}
@@ -1031,28 +1050,23 @@ func (c *Cluster) imageWithDigestString(ctx context.Context, image string, authC
 			return "", err
 		}
 
-		// TODO(nishanttotla): Currently, the service would lose the tag while calling WithDigest
-		// To prevent this, we create the image string manually, which is a bad idea in general
-		// This will be fixed when https://github.com/docker/distribution/pull/2044 is vendored
-		// namedDigestedRef, err := reference.WithDigest(ref, dscrptr.Digest)
-		// if err != nil {
-		// 	return "", err
-		// }
-		// return namedDigestedRef.String(), nil
-		return image + "@" + dscrptr.Digest.String(), nil
-	} else {
-		// reference already contains a digest, so just return it
-		return ref.String(), nil
+		namedDigestedRef, err := distreference.WithDigest(distreference.EnsureTagged(ref), dscrptr.Digest)
+		if err != nil {
+			return "", err
+		}
+		return namedDigestedRef.String(), nil
 	}
+	// reference already contains a digest, so just return it
+	return ref.String(), nil
 }
 
 // CreateService creates a new service in a managed swarm cluster.
-func (c *Cluster) CreateService(s types.ServiceSpec, encodedAuth string) (string, error) {
+func (c *Cluster) CreateService(s types.ServiceSpec, encodedAuth string) (*apitypes.ServiceCreateResponse, error) {
 	c.RLock()
 	defer c.RUnlock()
 
 	if !c.isActiveManager() {
-		return "", c.errNoManager()
+		return nil, c.errNoManager()
 	}
 
 	ctx, cancel := c.getRequestContext()
@@ -1060,17 +1074,17 @@ func (c *Cluster) CreateService(s types.ServiceSpec, encodedAuth string) (string
 
 	err := c.populateNetworkID(ctx, c.client, &s)
 	if err != nil {
-		return "", err
+		return nil, err
 	}
 
 	serviceSpec, err := convert.ServiceSpecToGRPC(s)
 	if err != nil {
-		return "", err
+		return nil, err
 	}
 
 	ctnr := serviceSpec.Task.GetContainer()
 	if ctnr == nil {
-		return "", fmt.Errorf("service does not use container tasks")
+		return nil, fmt.Errorf("service does not use container tasks")
 	}
 
 	if encodedAuth != "" {
@@ -1084,11 +1098,15 @@ func (c *Cluster) CreateService(s types.ServiceSpec, encodedAuth string) (string
 			logrus.Warnf("invalid authconfig: %v", err)
 		}
 	}
+
+	resp := &apitypes.ServiceCreateResponse{}
+
 	// pin image by digest
 	if os.Getenv("DOCKER_SERVICE_PREFER_OFFLINE_IMAGE") != "1" {
 		digestImage, err := c.imageWithDigestString(ctx, ctnr.Image, authConfig)
 		if err != nil {
 			logrus.Warnf("unable to pin image %s to digest: %s", ctnr.Image, err.Error())
+			resp.Warnings = append(resp.Warnings, fmt.Sprintf("unable to pin image %s to digest: %s", ctnr.Image, err.Error()))
 		} else {
 			logrus.Debugf("pinning image %s by digest: %s", ctnr.Image, digestImage)
 			ctnr.Image = digestImage
@@ -1097,10 +1115,11 @@ func (c *Cluster) CreateService(s types.ServiceSpec, encodedAuth string) (string
 
 	r, err := c.client.CreateService(ctx, &swarmapi.CreateServiceRequest{Spec: &serviceSpec})
 	if err != nil {
-		return "", err
+		return nil, err
 	}
 
-	return r.Service.ID, nil
+	resp.ID = r.Service.ID
+	return resp, nil
 }
 
 // GetService returns a service based on an ID or name.
@@ -1123,12 +1142,12 @@ func (c *Cluster) GetService(input string) (types.Service, error) {
 }
 
 // UpdateService updates existing service to match new properties.
-func (c *Cluster) UpdateService(serviceIDOrName string, version uint64, spec types.ServiceSpec, encodedAuth string, registryAuthFrom string) error {
+func (c *Cluster) UpdateService(serviceIDOrName string, version uint64, spec types.ServiceSpec, encodedAuth string, registryAuthFrom string) (*apitypes.ServiceUpdateResponse, error) {
 	c.RLock()
 	defer c.RUnlock()
 
 	if !c.isActiveManager() {
-		return c.errNoManager()
+		return nil, c.errNoManager()
 	}
 
 	ctx, cancel := c.getRequestContext()
@@ -1136,22 +1155,22 @@ func (c *Cluster) UpdateService(serviceIDOrName string, version uint64, spec typ
 
 	err := c.populateNetworkID(ctx, c.client, &spec)
 	if err != nil {
-		return err
+		return nil, err
 	}
 
 	serviceSpec, err := convert.ServiceSpecToGRPC(spec)
 	if err != nil {
-		return err
+		return nil, err
 	}
 
 	currentService, err := getService(ctx, c.client, serviceIDOrName)
 	if err != nil {
-		return err
+		return nil, err
 	}
 
 	newCtnr := serviceSpec.Task.GetContainer()
 	if newCtnr == nil {
-		return fmt.Errorf("service does not use container tasks")
+		return nil, fmt.Errorf("service does not use container tasks")
 	}
 
 	if encodedAuth != "" {
@@ -1165,14 +1184,14 @@ func (c *Cluster) UpdateService(serviceIDOrName string, version uint64, spec typ
 			ctnr = currentService.Spec.Task.GetContainer()
 		case apitypes.RegistryAuthFromPreviousSpec:
 			if currentService.PreviousSpec == nil {
-				return fmt.Errorf("service does not have a previous spec")
+				return nil, fmt.Errorf("service does not have a previous spec")
 			}
 			ctnr = currentService.PreviousSpec.Task.GetContainer()
 		default:
-			return fmt.Errorf("unsupported registryAuthFromValue")
+			return nil, fmt.Errorf("unsupported registryAuthFromValue")
 		}
 		if ctnr == nil {
-			return fmt.Errorf("service does not use container tasks")
+			return nil, fmt.Errorf("service does not use container tasks")
 		}
 		newCtnr.PullOptions = ctnr.PullOptions
 		// update encodedAuth so it can be used to pin image by digest
@@ -1188,11 +1207,15 @@ func (c *Cluster) UpdateService(serviceIDOrName string, version uint64, spec typ
 			logrus.Warnf("invalid authconfig: %v", err)
 		}
 	}
+
+	resp := &apitypes.ServiceUpdateResponse{}
+
 	// pin image by digest
 	if os.Getenv("DOCKER_SERVICE_PREFER_OFFLINE_IMAGE") != "1" {
 		digestImage, err := c.imageWithDigestString(ctx, newCtnr.Image, authConfig)
 		if err != nil {
 			logrus.Warnf("unable to pin image %s to digest: %s", newCtnr.Image, err.Error())
+			resp.Warnings = append(resp.Warnings, fmt.Sprintf("unable to pin image %s to digest: %s", newCtnr.Image, err.Error()))
 		} else if newCtnr.Image != digestImage {
 			logrus.Debugf("pinning image %s by digest: %s", newCtnr.Image, digestImage)
 			newCtnr.Image = digestImage
@@ -1209,7 +1232,8 @@ func (c *Cluster) UpdateService(serviceIDOrName string, version uint64, spec typ
 			},
 		},
 	)
-	return err
+
+	return resp, err
 }
 
 // RemoveService removes a service from a managed swarm cluster.
@@ -1369,7 +1393,7 @@ func (c *Cluster) GetNode(input string) (types.Node, error) {
 }
 
 // UpdateNode updates existing nodes properties.
-func (c *Cluster) UpdateNode(nodeID string, version uint64, spec types.NodeSpec) error {
+func (c *Cluster) UpdateNode(input string, version uint64, spec types.NodeSpec) error {
 	c.RLock()
 	defer c.RUnlock()
 
@@ -1385,10 +1409,15 @@ func (c *Cluster) UpdateNode(nodeID string, version uint64, spec types.NodeSpec)
 	ctx, cancel := c.getRequestContext()
 	defer cancel()
 
+	currentNode, err := getNode(ctx, c.client, input)
+	if err != nil {
+		return err
+	}
+
 	_, err = c.client.UpdateNode(
 		ctx,
 		&swarmapi.UpdateNodeRequest{
-			NodeID: nodeID,
+			NodeID: currentNode.ID,
 			Spec:   &nodeSpec,
 			NodeVersion: &swarmapi.Version{
 				Index: version,

+ 2 - 6
daemon/commit.go

@@ -17,7 +17,6 @@ import (
 	"github.com/docker/docker/layer"
 	"github.com/docker/docker/pkg/ioutils"
 	"github.com/docker/docker/reference"
-	"github.com/docker/go-connections/nat"
 )
 
 // merge merges two Config, the image container configuration (defaults values),
@@ -32,9 +31,6 @@ func merge(userConf, imageConf *containertypes.Config) error {
 	if len(userConf.ExposedPorts) == 0 {
 		userConf.ExposedPorts = imageConf.ExposedPorts
 	} else if imageConf.ExposedPorts != nil {
-		if userConf.ExposedPorts == nil {
-			userConf.ExposedPorts = make(nat.PortSet)
-		}
 		for port := range imageConf.ExposedPorts {
 			if _, exists := userConf.ExposedPorts[port]; !exists {
 				userConf.ExposedPorts[port] = struct{}{}
@@ -244,8 +240,8 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str
 	}
 
 	attributes := map[string]string{
-		"comment": c.Comment,
-		"imageID": id.String(),
+		"comment":  c.Comment,
+		"imageID":  id.String(),
 		"imageRef": imageRef,
 	}
 	daemon.LogContainerEventWithAttributes(container, "commit", attributes)

+ 0 - 8
daemon/create_windows.go

@@ -16,14 +16,6 @@ func (daemon *Daemon) createContainerPlatformSpecificSettings(container *contain
 		hostConfig.Isolation = daemon.defaultIsolation
 	}
 
-	if err := daemon.Mount(container); err != nil {
-		return nil
-	}
-	defer daemon.Unmount(container)
-	if err := container.SetupWorkingDirectory(0, 0); err != nil {
-		return err
-	}
-
 	for spec := range config.Volumes {
 
 		mp, err := volume.ParseMountRaw(spec, hostConfig.VolumeDriver)

+ 5 - 6
daemon/daemon.go

@@ -550,7 +550,12 @@ func NewDaemon(config *Config, registryService registry.Service, containerdRemot
 		driverName = config.GraphDriver
 	}
 
+	d.RegistryService = registryService
 	d.PluginStore = pluginstore.NewStore(config.Root)
+	// Plugin system initialization should happen before restore. Do not change order.
+	if err := d.pluginInit(config, containerdRemote); err != nil {
+		return nil, err
+	}
 
 	d.layerStore, err = layer.NewStoreFromOptions(layer.StoreOptions{
 		StorePath:                 config.Root,
@@ -649,7 +654,6 @@ func NewDaemon(config *Config, registryService registry.Service, containerdRemot
 		Type:   config.LogConfig.Type,
 		Config: config.LogConfig.Config,
 	}
-	d.RegistryService = registryService
 	d.EventsService = eventsService
 	d.volumes = volStore
 	d.root = config.Root
@@ -668,11 +672,6 @@ func NewDaemon(config *Config, registryService registry.Service, containerdRemot
 		return nil, err
 	}
 
-	// Plugin system initialization should happen before restore. Do not change order.
-	if err := d.pluginInit(config, containerdRemote); err != nil {
-		return nil, err
-	}
-
 	if err := d.restore(); err != nil {
 		return nil, err
 	}

+ 8 - 3
daemon/daemon_unix.go

@@ -112,9 +112,7 @@ func getCPUResources(config containertypes.Resources) *specs.CPU {
 	}
 
 	if config.NanoCPUs > 0 {
-		// Use the default setting of 100ms, as is specified in:
 		// https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt
-		//    	cpu.cfs_period_us=100ms
 		period := uint64(100 * time.Millisecond / time.Microsecond)
 		quota := uint64(config.NanoCPUs) * period / 1e9
 		cpu.Period = &period
@@ -361,8 +359,15 @@ func verifyContainerResources(resources *containertypes.Resources, sysInfo *sysi
 	if resources.NanoCPUs > 0 && (!sysInfo.CPUCfsPeriod || !sysInfo.CPUCfsQuota) {
 		return warnings, fmt.Errorf("NanoCPUs can not be set, as your kernel does not support CPU cfs period/quota or the cgroup is not mounted")
 	}
+	// The highest precision we could get on Linux is 0.001, by setting
+	//   cpu.cfs_period_us=1000ms
+	//   cpu.cfs_quota=1ms
+	// See the following link for details:
+	// https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt
+	// Here we don't set the lower limit and it is up to the underlying platform (e.g., Linux) to return an error.
+	// The error message is 0.01 so that this is consistent with Windows
 	if resources.NanoCPUs < 0 || resources.NanoCPUs > int64(sysinfo.NumCPU())*1e9 {
-		return warnings, fmt.Errorf("Range of Nano CPUs is from 1 to %d", int64(sysinfo.NumCPU())*1e9)
+		return warnings, fmt.Errorf("Range of CPUs is from 0.01 to %d.00, as there are only %d CPUs available", sysinfo.NumCPU(), sysinfo.NumCPU())
 	}
 
 	if resources.CPUShares > 0 && !sysInfo.CPUShares {

+ 3 - 1
daemon/daemon_windows.go

@@ -129,8 +129,10 @@ func verifyContainerResources(resources *containertypes.Resources, isHyperv bool
 	if resources.NanoCPUs > 0 && resources.CPUShares > 0 {
 		return warnings, fmt.Errorf("conflicting options: Nano CPUs and CPU Shares cannot both be set")
 	}
+	// The precision we could get is 0.01, because on Windows we have to convert to CPUPercent.
+	// We don't set the lower limit here and it is up to the underlying platform (e.g., Windows) to return an error.
 	if resources.NanoCPUs < 0 || resources.NanoCPUs > int64(sysinfo.NumCPU())*1e9 {
-		return warnings, fmt.Errorf("range of Nano CPUs is from 1 to %d", int64(sysinfo.NumCPU())*1e9)
+		return warnings, fmt.Errorf("range of CPUs is from 0.01 to %d.00, as there are only %d CPUs available", sysinfo.NumCPU(), sysinfo.NumCPU())
 	}
 
 	if len(resources.BlkioDeviceReadBps) > 0 {

+ 30 - 1
daemon/debugtrap.go

@@ -27,7 +27,36 @@ func (d *Daemon) dumpDaemon(dir string) (string, error) {
 		return "", errors.Wrap(err, "failed to open file to write the daemon datastructure dump")
 	}
 	defer f.Close()
-	spew.Fdump(f, d) // Does not return an error
+
+	dump := struct {
+		containers      interface{}
+		names           interface{}
+		links           interface{}
+		execs           interface{}
+		volumes         interface{}
+		images          interface{}
+		layers          interface{}
+		imageReferences interface{}
+		downloads       interface{}
+		uploads         interface{}
+		registry        interface{}
+		plugins         interface{}
+	}{
+		containers:      d.containers,
+		execs:           d.execCommands,
+		volumes:         d.volumes,
+		images:          d.imageStore,
+		layers:          d.layerStore,
+		imageReferences: d.referenceStore,
+		downloads:       d.downloadManager,
+		uploads:         d.uploadManager,
+		registry:        d.RegistryService,
+		plugins:         d.PluginStore,
+		names:           d.nameIndex,
+		links:           d.linkIndex,
+	}
+
+	spew.Fdump(f, dump) // Does not return an error
 	f.Sync()
 	return path, nil
 }

+ 2 - 1
daemon/graphdriver/plugin.go

@@ -3,6 +3,7 @@ package graphdriver
 import (
 	"fmt"
 	"io"
+	"path/filepath"
 
 	"github.com/docker/docker/pkg/plugingetter"
 )
@@ -26,5 +27,5 @@ func lookupPlugin(name, home string, opts []string, pg plugingetter.PluginGetter
 
 func newPluginDriver(name, home string, opts []string, c pluginClient) (Driver, error) {
 	proxy := &graphDriverProxy{name, c}
-	return proxy, proxy.Init(home, opts)
+	return proxy, proxy.Init(filepath.Join(home, name), opts)
 }

+ 2 - 4
daemon/graphdriver/windows/windows.go

@@ -165,18 +165,16 @@ func (d *Driver) Exists(id string) bool {
 func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error {
 	if opts != nil {
 		return d.create(id, parent, opts.MountLabel, false, opts.StorageOpt)
-	} else {
-		return d.create(id, parent, "", false, nil)
 	}
+	return d.create(id, parent, "", false, nil)
 }
 
 // Create creates a new read-only layer with the given id.
 func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
 	if opts != nil {
 		return d.create(id, parent, opts.MountLabel, true, opts.StorageOpt)
-	} else {
-		return d.create(id, parent, "", true, nil)
 	}
+	return d.create(id, parent, "", true, nil)
 }
 
 func (d *Driver) create(id, parent, mountLabel string, readOnly bool, storageOpt map[string]string) error {

+ 22 - 8
daemon/health.go

@@ -12,6 +12,7 @@ import (
 
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/api/types"
+	containertypes "github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/api/types/strslice"
 	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon/exec"
@@ -63,11 +64,7 @@ func (p *cmdProbe) run(ctx context.Context, d *Daemon, container *container.Cont
 
 	cmdSlice := strslice.StrSlice(container.Config.Healthcheck.Test)[1:]
 	if p.shell {
-		if runtime.GOOS != "windows" {
-			cmdSlice = append([]string{"/bin/sh", "-c"}, cmdSlice...)
-		} else {
-			cmdSlice = append([]string{"cmd", "/S", "/C"}, cmdSlice...)
-		}
+		cmdSlice = append(getShell(container.Config), cmdSlice...)
 	}
 	entrypoint, args := d.getEntrypointAndArgs(strslice.StrSlice{}, cmdSlice)
 	execConfig := exec.NewConfig()
@@ -107,10 +104,17 @@ func (p *cmdProbe) run(ctx context.Context, d *Daemon, container *container.Cont
 }
 
 // Update the container's Status.Health struct based on the latest probe's result.
-func handleProbeResult(d *Daemon, c *container.Container, result *types.HealthcheckResult) {
+func handleProbeResult(d *Daemon, c *container.Container, result *types.HealthcheckResult, done chan struct{}) {
 	c.Lock()
 	defer c.Unlock()
 
+	// probe may have been cancelled while waiting on lock. Ignore result then
+	select {
+	case <-done:
+		return
+	default:
+	}
+
 	retries := c.Config.Healthcheck.Retries
 	if retries <= 0 {
 		retries = defaultProbeRetries
@@ -183,7 +187,7 @@ func monitor(d *Daemon, c *container.Container, stop chan struct{}, probe probe)
 				cancelProbe()
 				return
 			case result := <-results:
-				handleProbeResult(d, c, result)
+				handleProbeResult(d, c, result, stop)
 				// Stop timeout
 				cancelProbe()
 			case <-ctx.Done():
@@ -193,7 +197,7 @@ func monitor(d *Daemon, c *container.Container, stop chan struct{}, probe probe)
 					Output:   fmt.Sprintf("Health check exceeded timeout (%v)", probeTimeout),
 					Start:    startTime,
 					End:      time.Now(),
-				})
+				}, stop)
 				cancelProbe()
 				// Wait for probe to exit (it might take a while to respond to the TERM
 				// signal and we don't want dying probes to pile up).
@@ -325,3 +329,13 @@ func min(x, y int) int {
 	}
 	return y
 }
+
+func getShell(config *containertypes.Config) []string {
+	if len(config.Shell) != 0 {
+		return config.Shell
+	}
+	if runtime.GOOS != "windows" {
+		return []string{"/bin/sh", "-c"}
+	}
+	return []string{"cmd", "/S", "/C"}
+}

+ 1 - 1
daemon/health_test.go

@@ -80,7 +80,7 @@ func TestHealthStates(t *testing.T) {
 			Start:    startTime,
 			End:      startTime,
 			ExitCode: exitCode,
-		})
+		}, nil)
 	}
 
 	// starting -> failed -> success -> failed

+ 1 - 0
daemon/image_pull.go

@@ -106,6 +106,7 @@ func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference.
 	return err
 }
 
+// GetRepository returns a repository from the registry.
 func (daemon *Daemon) GetRepository(ctx context.Context, ref reference.NamedTagged, authConfig *types.AuthConfig) (dist.Repository, bool, error) {
 	// get repository info
 	repoInfo, err := daemon.RegistryService.ResolveRepository(ref)

+ 1 - 0
daemon/info_unix.go

@@ -13,6 +13,7 @@ import (
 	"github.com/docker/docker/pkg/sysinfo"
 )
 
+// FillPlatformInfo fills the platform related info.
 func (daemon *Daemon) FillPlatformInfo(v *types.InfoBase, sysInfo *sysinfo.SysInfo) {
 	v.MemoryLimit = sysInfo.MemoryLimit
 	v.SwapLimit = sysInfo.SwapLimit

+ 1 - 0
daemon/info_windows.go

@@ -5,5 +5,6 @@ import (
 	"github.com/docker/docker/pkg/sysinfo"
 )
 
+// FillPlatformInfo fills the platform related info.
 func (daemon *Daemon) FillPlatformInfo(v *types.InfoBase, sysInfo *sysinfo.SysInfo) {
 }

+ 2 - 0
docs/extend/config.md

@@ -55,6 +55,8 @@ Config provides the base accessible fields for working with V0 plugin format
 
       	- **docker.volumedriver/1.0**
 
+      	- **docker.authz/1.0**
+
     - **`socket`** *string*
 
       socket is the name of the socket the engine should use to communicate with the plugins.

+ 2 - 2
docs/extend/index.md

@@ -199,8 +199,8 @@ drwx------ 19 root root 4096 Aug  8 17:56 rootfs
 The `rootfs` directory represents the root filesystem of the plugin. In this
 example, it was created from a Dockerfile:
 
->**Note:** The `/run/docker/plugins` directory is mandatory for docker to communicate with
-the plugin.
+>**Note:** The `/run/docker/plugins` directory is mandatory inside of the
+plugin's filesystem for docker to communicate with the plugin.
 
 ```bash
 $ git clone https://github.com/vieux/docker-volume-sshfs

+ 3 - 0
docs/reference/api/docker_remote_api.md

@@ -165,6 +165,7 @@ This section lists each version from latest to oldest.  Each listing includes a
 * `POST /containers/create` now takes `StopTimeout` field.
 * `POST /services/create` and `POST /services/(id or name)/update` now accept `Monitor` and `MaxFailureRatio` parameters, which control the response to failures during service updates.
 * `POST /services/(id or name)/update` now accepts a `ForceUpdate` parameter inside the `TaskTemplate`, which causes the service to be updated even if there are no changes which would ordinarily trigger an update.
+* `POST /services/create` and `POST /services/(id or name)/update` now return a `Warnings` array.
 * `GET /networks/(name)` now returns field `Created` in response to show network created time.
 * `POST /containers/(id or name)/exec` now accepts an `Env` field, which holds a list of environment variables to be set in the context of the command execution.
 * `GET /volumes`, `GET /volumes/(name)`, and `POST /volumes/create` now return the `Options` field which holds the driver specific options to use for when creating the volume.
@@ -193,6 +194,8 @@ This section lists each version from latest to oldest.  Each listing includes a
 * `POST /plugins/(plugin name)/push` push a plugin.
 * `POST /plugins/create?name=(plugin name)` create a plugin.
 * `DELETE /plugins/(plugin name)` delete a plugin.
+* `POST /node/(id or name)/update` now accepts both `id` or `name` to identify the node to update.
+* `GET /images/json` now support a `reference` filter.
 
 
 ### v1.24 API changes

+ 6 - 6
docs/reference/api/docker_remote_api_v1.18.md

@@ -1044,7 +1044,7 @@ Remove the container `id` from the filesystem
 
 **Example request**:
 
-    DELETE /containers/16253994b7c4?v=1 HTTP/1.1
+    DELETE /v1.18/containers/16253994b7c4?v=1 HTTP/1.1
 
 **Example response**:
 
@@ -1462,7 +1462,7 @@ Remove the image `name` from the filesystem
 
 **Example request**:
 
-    DELETE /images/test HTTP/1.1
+    DELETE /v1.18/images/test HTTP/1.1
 
 **Example response**:
 
@@ -1765,7 +1765,7 @@ Docker images report the following events:
 
 **Example request**:
 
-    GET /events?since=1374067924
+    GET /v1.18/events?since=1374067924
 
 **Example response**:
 
@@ -1807,7 +1807,7 @@ See the [image tarball format](#image-tarball-format) for more details.
 
 **Example request**
 
-    GET /images/ubuntu/get
+    GET /v1.18/images/ubuntu/get
 
 **Example response**:
 
@@ -1836,7 +1836,7 @@ See the [image tarball format](#image-tarball-format) for more details.
 
 **Example request**
 
-    GET /images/get?names=myname%2Fmyapp%3Alatest&names=busybox
+    GET /v1.18/images/get?names=myname%2Fmyapp%3Alatest&names=busybox
 
 **Example response**:
 
@@ -1859,7 +1859,7 @@ See the [image tarball format](#image-tarball-format) for more details.
 
 **Example request**
 
-    POST /images/load
+    POST /v1.18/images/load
     Content-Type: application/x-tar
 
     Tarball in body

+ 6 - 6
docs/reference/api/docker_remote_api_v1.19.md

@@ -1083,7 +1083,7 @@ Remove the container `id` from the filesystem
 
 **Example request**:
 
-    DELETE /containers/16253994b7c4?v=1 HTTP/1.1
+    DELETE /v1.19/containers/16253994b7c4?v=1 HTTP/1.1
 
 **Example response**:
 
@@ -1528,7 +1528,7 @@ Remove the image `name` from the filesystem
 
 **Example request**:
 
-    DELETE /images/test HTTP/1.1
+    DELETE /v1.19/images/test HTTP/1.1
 
 **Example response**:
 
@@ -1845,7 +1845,7 @@ Docker images report the following events:
 
 **Example request**:
 
-    GET /events?since=1374067924
+    GET /v1.19/events?since=1374067924
 
 **Example response**:
 
@@ -1887,7 +1887,7 @@ See the [image tarball format](#image-tarball-format) for more details.
 
 **Example request**
 
-    GET /images/ubuntu/get
+    GET /v1.19/images/ubuntu/get
 
 **Example response**:
 
@@ -1916,7 +1916,7 @@ See the [image tarball format](#image-tarball-format) for more details.
 
 **Example request**
 
-    GET /images/get?names=myname%2Fmyapp%3Alatest&names=busybox
+    GET /v1.19/images/get?names=myname%2Fmyapp%3Alatest&names=busybox
 
 **Example response**:
 
@@ -1939,7 +1939,7 @@ See the [image tarball format](#image-tarball-format) for more details.
 
 **Example request**
 
-    POST /images/load
+    POST /v1.19/images/load
     Content-Type: application/x-tar
 
     Tarball in body

+ 7 - 7
docs/reference/api/docker_remote_api_v1.20.md

@@ -1090,7 +1090,7 @@ Remove the container `id` from the filesystem
 
 **Example request**:
 
-    DELETE /containers/16253994b7c4?v=1 HTTP/1.1
+    DELETE /v1.20/containers/16253994b7c4?v=1 HTTP/1.1
 
 **Example response**:
 
@@ -1235,7 +1235,7 @@ Upload a tar archive to be extracted to a path in the filesystem of container
 
 **Example request**:
 
-    PUT /containers/8cce319429b2/archive?path=/vol1 HTTP/1.1
+    PUT /v1.20/containers/8cce319429b2/archive?path=/vol1 HTTP/1.1
     Content-Type: application/x-tar
 
     {% raw %}
@@ -1682,7 +1682,7 @@ Remove the image `name` from the filesystem
 
 **Example request**:
 
-    DELETE /images/test HTTP/1.1
+    DELETE /v1.20/images/test HTTP/1.1
 
 **Example response**:
 
@@ -2000,7 +2000,7 @@ Docker images report the following events:
 
 **Example request**:
 
-    GET /events?since=1374067924
+    GET /v1.20/events?since=1374067924
 
 **Example response**:
 
@@ -2042,7 +2042,7 @@ See the [image tarball format](#image-tarball-format) for more details.
 
 **Example request**
 
-    GET /images/ubuntu/get
+    GET /v1.20/images/ubuntu/get
 
 **Example response**:
 
@@ -2071,7 +2071,7 @@ See the [image tarball format](#image-tarball-format) for more details.
 
 **Example request**
 
-    GET /images/get?names=myname%2Fmyapp%3Alatest&names=busybox
+    GET /v1.20/images/get?names=myname%2Fmyapp%3Alatest&names=busybox
 
 **Example response**:
 
@@ -2094,7 +2094,7 @@ See the [image tarball format](#image-tarball-format) for more details.
 
 **Example request**
 
-    POST /images/load
+    POST /v1.20/images/load
     Content-Type: application/x-tar
 
     Tarball in body

+ 9 - 9
docs/reference/api/docker_remote_api_v1.21.md

@@ -1173,7 +1173,7 @@ Remove the container `id` from the filesystem
 
 **Example request**:
 
-    DELETE /containers/16253994b7c4?v=1 HTTP/1.1
+    DELETE /v1.21/containers/16253994b7c4?v=1 HTTP/1.1
 
 **Example response**:
 
@@ -1318,7 +1318,7 @@ Upload a tar archive to be extracted to a path in the filesystem of container
 
 **Example request**:
 
-    PUT /containers/8cce319429b2/archive?path=/vol1 HTTP/1.1
+    PUT /v1.21/containers/8cce319429b2/archive?path=/vol1 HTTP/1.1
     Content-Type: application/x-tar
 
     {% raw %}
@@ -1835,7 +1835,7 @@ Remove the image `name` from the filesystem
 
 **Example request**:
 
-    DELETE /images/test HTTP/1.1
+    DELETE /v1.21/images/test HTTP/1.1
 
 **Example response**:
 
@@ -2155,7 +2155,7 @@ Docker images report the following events:
 
 **Example request**:
 
-    GET /events?since=1374067924
+    GET /v1.21/events?since=1374067924
 
 **Example response**:
 
@@ -2198,7 +2198,7 @@ See the [image tarball format](#image-tarball-format) for more details.
 
 **Example request**
 
-    GET /images/ubuntu/get
+    GET /v1.21/images/ubuntu/get
 
 **Example response**:
 
@@ -2227,7 +2227,7 @@ See the [image tarball format](#image-tarball-format) for more details.
 
 **Example request**
 
-    GET /images/get?names=myname%2Fmyapp%3Alatest&names=busybox
+    GET /v1.21/images/get?names=myname%2Fmyapp%3Alatest&names=busybox
 
 **Example response**:
 
@@ -2250,7 +2250,7 @@ See the [image tarball format](#image-tarball-format) for more details.
 
 **Example request**
 
-    POST /images/load
+    POST /v1.21/images/load
     Content-Type: application/x-tar
 
     Tarball in body
@@ -2637,7 +2637,7 @@ Instruct the driver to remove the volume (`name`).
 
 **Example request**:
 
-    DELETE /volumes/tardis HTTP/1.1
+    DELETE /v1.21/volumes/tardis HTTP/1.1
 
 **Example response**:
 
@@ -2912,7 +2912,7 @@ Instruct the driver to remove the network (`id`).
 
 **Example request**:
 
-    DELETE /networks/22be93d5babb089c5aab8dbc369042fad48ff791584ca2da2100db837a1c7c30 HTTP/1.1
+    DELETE /v1.21/networks/22be93d5babb089c5aab8dbc369042fad48ff791584ca2da2100db837a1c7c30 HTTP/1.1
 
 **Example response**:
 

+ 12 - 9
docs/reference/api/docker_remote_api_v1.22.md

@@ -257,6 +257,7 @@ Create a container
            "StopSignal": "SIGTERM",
            "HostConfig": {
              "Binds": ["/tmp:/tmp"],
+             "Tmpfs": { "/run": "rw,noexec,nosuid,size=65536k" },
              "Links": ["redis3:redis"],
              "Memory": 0,
              "MemorySwap": 0,
@@ -364,6 +365,8 @@ Create a container
              _absolute_ path.
            + `volume-name:container-dest:ro` to mount the volume read-only
              inside the container.  `container-dest` must be an _absolute_ path.
+    -   **Tmpfs** – A map of container directories which should be replaced by tmpfs mounts, and their corresponding
+          mount options. A JSON object in the form `{ "/run": "rw,noexec,nosuid,size=65536k" }`.
     -   **Links** - A list of links for the container. Each link entry should be
           in the form of `container_name:alias`.
     -   **Memory** - Memory limit in bytes.
@@ -1349,7 +1352,7 @@ Remove the container `id` from the filesystem
 
 **Example request**:
 
-    DELETE /containers/16253994b7c4?v=1 HTTP/1.1
+    DELETE /v1.22/containers/16253994b7c4?v=1 HTTP/1.1
 
 **Example response**:
 
@@ -1494,7 +1497,7 @@ Upload a tar archive to be extracted to a path in the filesystem of container
 
 **Example request**:
 
-    PUT /containers/8cce319429b2/archive?path=/vol1 HTTP/1.1
+    PUT /v1.22/containers/8cce319429b2/archive?path=/vol1 HTTP/1.1
     Content-Type: application/x-tar
 
     {% raw %}
@@ -2049,7 +2052,7 @@ Remove the image `name` from the filesystem
 
 **Example request**:
 
-    DELETE /images/test HTTP/1.1
+    DELETE /v1.22/images/test HTTP/1.1
 
 **Example response**:
 
@@ -2394,7 +2397,7 @@ Docker networks report the following events:
 
 **Example request**:
 
-    GET /events?since=1374067924
+    GET /v1.22/events?since=1374067924
 
 **Example response**:
 
@@ -2586,7 +2589,7 @@ See the [image tarball format](#image-tarball-format) for more details.
 
 **Example request**
 
-    GET /images/ubuntu/get
+    GET /v1.22/images/ubuntu/get
 
 **Example response**:
 
@@ -2615,7 +2618,7 @@ See the [image tarball format](#image-tarball-format) for more details.
 
 **Example request**
 
-    GET /images/get?names=myname%2Fmyapp%3Alatest&names=busybox
+    GET /v1.22/images/get?names=myname%2Fmyapp%3Alatest&names=busybox
 
 **Example response**:
 
@@ -2638,7 +2641,7 @@ See the [image tarball format](#image-tarball-format) for more details.
 
 **Example request**
 
-    POST /images/load
+    POST /v1.22/images/load
     Content-Type: application/x-tar
 
     Tarball in body
@@ -2947,7 +2950,7 @@ Instruct the driver to remove the volume (`name`).
 
 **Example request**:
 
-    DELETE /volumes/tardis HTTP/1.1
+    DELETE /v1.22/volumes/tardis HTTP/1.1
 
 **Example response**:
 
@@ -3247,7 +3250,7 @@ Instruct the driver to remove the network (`id`).
 
 **Example request**:
 
-    DELETE /networks/22be93d5babb089c5aab8dbc369042fad48ff791584ca2da2100db837a1c7c30 HTTP/1.1
+    DELETE /v1.22/networks/22be93d5babb089c5aab8dbc369042fad48ff791584ca2da2100db837a1c7c30 HTTP/1.1
 
 **Example response**:
 

+ 13 - 10
docs/reference/api/docker_remote_api_v1.23.md

@@ -281,6 +281,7 @@ Create a container
            "StopSignal": "SIGTERM",
            "HostConfig": {
              "Binds": ["/tmp:/tmp"],
+             "Tmpfs": { "/run": "rw,noexec,nosuid,size=65536k" },
              "Links": ["redis3:redis"],
              "Memory": 0,
              "MemorySwap": 0,
@@ -389,6 +390,8 @@ Create a container
              _absolute_ path.
            + `volume-name:container-dest:ro` to mount the volume read-only
              inside the container.  `container-dest` must be an _absolute_ path.
+    -   **Tmpfs** – A map of container directories which should be replaced by tmpfs mounts, and their corresponding
+          mount options. A JSON object in the form `{ "/run": "rw,noexec,nosuid,size=65536k" }`.
     -   **Links** - A list of links for the container. Each link entry should be
           in the form of `container_name:alias`.
     -   **Memory** - Memory limit in bytes.
@@ -1384,7 +1387,7 @@ Remove the container `id` from the filesystem
 
 **Example request**:
 
-    DELETE /containers/16253994b7c4?v=1 HTTP/1.1
+    DELETE /v1.23/containers/16253994b7c4?v=1 HTTP/1.1
 
 **Example response**:
 
@@ -1529,7 +1532,7 @@ Upload a tar archive to be extracted to a path in the filesystem of container
 
 **Example request**:
 
-    PUT /containers/8cce319429b2/archive?path=/vol1 HTTP/1.1
+    PUT /v1.23/containers/8cce319429b2/archive?path=/vol1 HTTP/1.1
     Content-Type: application/x-tar
 
     {% raw %}
@@ -2092,7 +2095,7 @@ Remove the image `name` from the filesystem
 
 **Example request**:
 
-    DELETE /images/test HTTP/1.1
+    DELETE /v1.23/images/test HTTP/1.1
 
 **Example response**:
 
@@ -2444,7 +2447,7 @@ Docker networks report the following events:
 
 **Example request**:
 
-    GET /events?since=1374067924
+    GET /v1.23/events?since=1374067924
 
 **Example response**:
 
@@ -2636,7 +2639,7 @@ See the [image tarball format](#image-tarball-format) for more details.
 
 **Example request**
 
-    GET /images/ubuntu/get
+    GET /v1.23/images/ubuntu/get
 
 **Example response**:
 
@@ -2665,7 +2668,7 @@ See the [image tarball format](#image-tarball-format) for more details.
 
 **Example request**
 
-    GET /images/get?names=myname%2Fmyapp%3Alatest&names=busybox
+    GET /v1.23/images/get?names=myname%2Fmyapp%3Alatest&names=busybox
 
 **Example response**:
 
@@ -2688,7 +2691,7 @@ See the [image tarball format](#image-tarball-format) for more details.
 
 **Example request**
 
-    POST /images/load
+    POST /v1.23/images/load
     Content-Type: application/x-tar
 
     Tarball in body
@@ -3005,7 +3008,7 @@ Return low-level information on the volume `name`
 
 **Example request**:
 
-    GET /volumes/tardis
+    GET /v1.23/volumes/tardis
 
 **Example response**:
 
@@ -3036,7 +3039,7 @@ Instruct the driver to remove the volume (`name`).
 
 **Example request**:
 
-    DELETE /volumes/tardis HTTP/1.1
+    DELETE /v1.23/volumes/tardis HTTP/1.1
 
 **Example response**:
 
@@ -3364,7 +3367,7 @@ Instruct the driver to remove the network (`id`).
 
 **Example request**:
 
-    DELETE /networks/22be93d5babb089c5aab8dbc369042fad48ff791584ca2da2100db837a1c7c30 HTTP/1.1
+    DELETE /v1.23/networks/22be93d5babb089c5aab8dbc369042fad48ff791584ca2da2100db837a1c7c30 HTTP/1.1
 
 **Example response**:
 

+ 23 - 20
docs/reference/api/docker_remote_api_v1.24.md

@@ -290,6 +290,7 @@ Create a container
            "StopSignal": "SIGTERM",
            "HostConfig": {
              "Binds": ["/tmp:/tmp"],
+             "Tmpfs": { "/run": "rw,noexec,nosuid,size=65536k" },
              "Links": ["redis3:redis"],
              "Memory": 0,
              "MemorySwap": 0,
@@ -404,6 +405,8 @@ Create a container
              _absolute_ path.
            + `volume-name:container-dest:ro` to mount the volume read-only
              inside the container.  `container-dest` must be an _absolute_ path.
+    -   **Tmpfs** – A map of container directories which should be replaced by tmpfs mounts, and their corresponding
+          mount options. A JSON object in the form `{ "/run": "rw,noexec,nosuid,size=65536k" }`.
     -   **Links** - A list of links for the container. Each link entry should be
           in the form of `container_name:alias`.
     -   **Memory** - Memory limit in bytes.
@@ -1411,7 +1414,7 @@ Remove the container `id` from the filesystem
 
 **Example request**:
 
-    DELETE /containers/16253994b7c4?v=1 HTTP/1.1
+    DELETE /v1.24/containers/16253994b7c4?v=1 HTTP/1.1
 
 **Example response**:
 
@@ -1524,7 +1527,7 @@ Upload a tar archive to be extracted to a path in the filesystem of container
 
 **Example request**:
 
-    PUT /containers/8cce319429b2/archive?path=/vol1 HTTP/1.1
+    PUT /v1.24/containers/8cce319429b2/archive?path=/vol1 HTTP/1.1
     Content-Type: application/x-tar
 
     {% raw %}
@@ -2088,7 +2091,7 @@ Remove the image `name` from the filesystem
 
 **Example request**:
 
-    DELETE /images/test HTTP/1.1
+    DELETE /v1.24/images/test HTTP/1.1
 
 **Example response**:
 
@@ -2453,13 +2456,13 @@ Docker daemon report the following event:
 
 **Example request**:
 
-    GET /events?since=1374067924
+    GET /v1.24/events?since=1374067924
 
 **Example response**:
 
     HTTP/1.1 200 OK
     Content-Type: application/json
-    Server: Docker/1.11.0 (linux)
+    Server: Docker/1.12.0 (linux)
     Date: Fri, 29 Apr 2016 15:18:06 GMT
     Transfer-Encoding: chunked
 
@@ -2646,7 +2649,7 @@ See the [image tarball format](#image-tarball-format) for more details.
 
 **Example request**
 
-    GET /images/ubuntu/get
+    GET /v1.24/images/ubuntu/get
 
 **Example response**:
 
@@ -2675,7 +2678,7 @@ See the [image tarball format](#image-tarball-format) for more details.
 
 **Example request**
 
-    GET /images/get?names=myname%2Fmyapp%3Alatest&names=busybox
+    GET /v1.24/images/get?names=myname%2Fmyapp%3Alatest&names=busybox
 
 **Example response**:
 
@@ -2698,7 +2701,7 @@ See the [image tarball format](#image-tarball-format) for more details.
 
 **Example request**
 
-    POST /images/load
+    POST /v1.24/images/load
     Content-Type: application/x-tar
 
     Tarball in body
@@ -3030,7 +3033,7 @@ Return low-level information on the volume `name`
 
 **Example request**:
 
-    GET /volumes/tardis
+    GET /v1.24/volumes/tardis
 
 **Example response**:
 
@@ -3082,7 +3085,7 @@ Instruct the driver to remove the volume (`name`).
 
 **Example request**:
 
-    DELETE /volumes/tardis HTTP/1.1
+    DELETE /v1.24/volumes/tardis HTTP/1.1
 
 **Example response**:
 
@@ -3414,7 +3417,7 @@ Instruct the driver to remove the network (`id`).
 
 **Example request**:
 
-    DELETE /networks/22be93d5babb089c5aab8dbc369042fad48ff791584ca2da2100db837a1c7c30 HTTP/1.1
+    DELETE /v1.24/networks/22be93d5babb089c5aab8dbc369042fad48ff791584ca2da2100db837a1c7c30 HTTP/1.1
 
 **Example response**:
 
@@ -3818,7 +3821,7 @@ Removes a plugin
 **Example request**:
 
 ```
-DELETE /plugins/tiborvass/no-remove:latest HTTP/1.1
+DELETE /v1.24/plugins/tiborvass/no-remove:latest HTTP/1.1
 ```
 
 The `:latest` tag is optional, and is used as default if omitted.
@@ -3912,7 +3915,7 @@ List nodes
             "MemoryBytes": 8272408576
           },
           "Engine": {
-            "EngineVersion": "1.12.0-dev",
+            "EngineVersion": "1.12.0",
             "Labels": {
                 "foo": "bar",
             }
@@ -3965,7 +3968,7 @@ List nodes
 ### Inspect a node
 
 
-`GET /nodes/<id>`
+`GET /nodes/(id or name)`
 
 Return low-level information on the node `id`
 
@@ -4004,7 +4007,7 @@ Return low-level information on the node `id`
           "MemoryBytes": 8272408576
         },
         "Engine": {
-          "EngineVersion": "1.12.0-dev",
+          "EngineVersion": "1.12.0",
           "Labels": {
               "foo": "bar",
           }
@@ -4047,13 +4050,13 @@ Return low-level information on the node `id`
 ### Remove a node
 
 
-`DELETE /nodes/(id)`
+`DELETE /nodes/(id or name)`
 
-Remove a node [`id`] from the swarm.
+Remove a node from the swarm.
 
 **Example request**:
 
-    DELETE /nodes/24ifsmvkjbyhk HTTP/1.1
+    DELETE /v1.24/nodes/24ifsmvkjbyhk HTTP/1.1
 
 **Example response**:
 
@@ -4077,7 +4080,7 @@ Remove a node [`id`] from the swarm.
 
 `POST /nodes/(id)/update`
 
-Update the node `id`.
+Update a node.
 
 The payload of the `POST` request is the new `NodeSpec` and
 overrides the current `NodeSpec` for the specified node.
@@ -4693,7 +4696,7 @@ Stop and remove the service `id`
 
 **Example request**:
 
-    DELETE /services/16253994b7c4 HTTP/1.1
+    DELETE /v1.24/services/16253994b7c4 HTTP/1.1
 
 **Example response**:
 

+ 50 - 36
docs/reference/api/docker_remote_api_v1.25.md

@@ -295,6 +295,7 @@ Create a container
            "StopTimeout": 10,
            "HostConfig": {
              "Binds": ["/tmp:/tmp"],
+             "Tmpfs": { "/run": "rw,noexec,nosuid,size=65536k" },
              "Links": ["redis3:redis"],
              "Memory": 0,
              "MemorySwap": 0,
@@ -418,6 +419,8 @@ Create a container
              _absolute_ path.
            + `volume-name:container-dest:ro` to mount the volume read-only
              inside the container.  `container-dest` must be an _absolute_ path.
+    -   **Tmpfs** – A map of container directories which should be replaced by tmpfs mounts, and their corresponding
+          mount options. A JSON object in the form `{ "/run": "rw,noexec,nosuid,size=65536k" }`.
     -   **Links** - A list of links for the container. Each link entry should be
           in the form of `container_name:alias`.
     -   **Memory** - Memory limit in bytes.
@@ -1467,7 +1470,7 @@ Remove the container `id` from the filesystem
 
 **Example request**:
 
-    DELETE /containers/16253994b7c4?v=1 HTTP/1.1
+    DELETE /v1.25/containers/16253994b7c4?v=1 HTTP/1.1
 
 **Example response**:
 
@@ -1580,7 +1583,7 @@ Upload a tar archive to be extracted to a path in the filesystem of container
 
 **Example request**:
 
-    PUT /containers/8cce319429b2/archive?path=/vol1 HTTP/1.1
+    PUT /v1.25/containers/8cce319429b2/archive?path=/vol1 HTTP/1.1
     Content-Type: application/x-tar
 
     {% raw %}
@@ -2272,7 +2275,7 @@ Remove the image `name` from the filesystem
 
 **Example request**:
 
-    DELETE /images/test HTTP/1.1
+    DELETE /v1.25/images/test HTTP/1.1
 
 **Example response**:
 
@@ -2610,7 +2613,7 @@ Display system-wide information
         "Name": "WIN-V0V70C0LU5P",
         "Labels": null,
         "ExperimentalBuild": false,
-        "ServerVersion": "1.13.0-dev",
+        "ServerVersion": "1.13.0",
         "ClusterStore": "",
         "ClusterAdvertise": "",
         "SecurityOptions": null,
@@ -2898,13 +2901,13 @@ Docker daemon report the following event:
 
 **Example request**:
 
-    GET /events?since=1374067924
+    GET /v1.25/events?since=1374067924
 
 **Example response**:
 
     HTTP/1.1 200 OK
     Content-Type: application/json
-    Server: Docker/1.11.0 (linux)
+    Server: Docker/1.13.0 (linux)
     Date: Fri, 29 Apr 2016 15:18:06 GMT
     Transfer-Encoding: chunked
 
@@ -3091,7 +3094,7 @@ See the [image tarball format](#image-tarball-format) for more details.
 
 **Example request**
 
-    GET /images/ubuntu/get
+    GET /v1.25/images/ubuntu/get
 
 **Example response**:
 
@@ -3120,7 +3123,7 @@ See the [image tarball format](#image-tarball-format) for more details.
 
 **Example request**
 
-    GET /images/get?names=myname%2Fmyapp%3Alatest&names=busybox
+    GET /v1.25/images/get?names=myname%2Fmyapp%3Alatest&names=busybox
 
 **Example response**:
 
@@ -3143,7 +3146,7 @@ See the [image tarball format](#image-tarball-format) for more details.
 
 **Example request**
 
-    POST /images/load
+    POST /v1.25/images/load
     Content-Type: application/x-tar
 
     Tarball in body
@@ -3490,7 +3493,7 @@ Return low-level information on the volume `name`
 
 **Example request**:
 
-    GET /volumes/tardis
+    GET /v1.25/volumes/tardis
 
 **Example response**:
 
@@ -3547,7 +3550,7 @@ Instruct the driver to remove the volume (`name`).
 
 **Example request**:
 
-    DELETE /volumes/tardis HTTP/1.1
+    DELETE /v1.25/volumes/tardis HTTP/1.1
 
 **Example response**:
 
@@ -3920,7 +3923,7 @@ Instruct the driver to remove the network (`id`).
 
 **Example request**:
 
-    DELETE /networks/22be93d5babb089c5aab8dbc369042fad48ff791584ca2da2100db837a1c7c30 HTTP/1.1
+    DELETE /v1.25/networks/22be93d5babb089c5aab8dbc369042fad48ff791584ca2da2100db837a1c7c30 HTTP/1.1
 
 **Example response**:
 
@@ -4296,7 +4299,7 @@ Content-Type: application/json
 **Example request**:
 
 
-    POST /plugins/tiborvass/no-remove/set
+    POST /v1.25/plugins/tiborvass/no-remove/set
     Content-Type: application/json
 
     ["DEBUG=1"]
@@ -4375,7 +4378,7 @@ Removes a plugin
 **Example request**:
 
 ```
-DELETE /plugins/tiborvass/no-remove:latest HTTP/1.1
+DELETE /v1.25/plugins/tiborvass/no-remove:latest HTTP/1.1
 ```
 
 The `:latest` tag is optional, and is used as default if omitted.
@@ -4510,7 +4513,7 @@ List nodes
             "MemoryBytes": 8272408576
           },
           "Engine": {
-            "EngineVersion": "1.12.0-dev",
+            "EngineVersion": "1.13.0",
             "Labels": {
                 "foo": "bar",
             }
@@ -4564,7 +4567,7 @@ List nodes
 ### Inspect a node
 
 
-`GET /nodes/<id>`
+`GET /nodes/(id or name)`
 
 Return low-level information on the node `id`
 
@@ -4603,7 +4606,7 @@ Return low-level information on the node `id`
           "MemoryBytes": 8272408576
         },
         "Engine": {
-          "EngineVersion": "1.12.0-dev",
+          "EngineVersion": "1.13.0",
           "Labels": {
               "foo": "bar",
           }
@@ -4647,13 +4650,13 @@ Return low-level information on the node `id`
 ### Remove a node
 
 
-`DELETE /nodes/(id)`
+`DELETE /nodes/(id or name)`
 
-Remove a node [`id`] from the swarm.
+Remove a node from the swarm.
 
 **Example request**:
 
-    DELETE /nodes/24ifsmvkjbyhk HTTP/1.1
+    DELETE /v1.25/nodes/24ifsmvkjbyhk HTTP/1.1
 
 **Example response**:
 
@@ -4675,9 +4678,9 @@ Remove a node [`id`] from the swarm.
 ### Update a node
 
 
-`POST /nodes/(id)/update`
+`POST /nodes/(id or name)/update`
 
-Update the node `id`.
+Update a node.
 
 The payload of the `POST` request is the new `NodeSpec` and
 overrides the current `NodeSpec` for the specified node.
@@ -4813,7 +4816,7 @@ Initialize a new swarm. The body of the HTTP response includes the node ID.
     Content-Length: 28
     Content-Type: application/json
     Date: Thu, 01 Sep 2016 21:49:13 GMT
-    Server: Docker/1.12.0 (linux)
+    Server: Docker/1.13.0 (linux)
 
     "7v2t30z9blmxuhnyo6s4cpenp"
 
@@ -4821,7 +4824,7 @@ Initialize a new swarm. The body of the HTTP response includes the node ID.
 
 - **200** – no error
 - **400** – bad parameter
-- **406** – node is already part of a swarm
+- **503** – node is already part of a swarm
 
 JSON Parameters:
 
@@ -4890,7 +4893,7 @@ Join an existing swarm
 
 - **200** – no error
 - **400** – bad parameter
-- **406** – node is already part of a swarm
+- **503** – node is already part of a swarm
 
 JSON Parameters:
 
@@ -4928,7 +4931,7 @@ Leave a swarm
 **Status codes**:
 
 - **200** – no error
-- **406** – node is not part of a swarm
+- **503** – node is not part of a swarm
 
 ### Retrieve the swarm's unlock key
 
@@ -5024,7 +5027,7 @@ Update a swarm
 
 - **200** – no error
 - **400** – bad parameter
-- **406** – node is not part of a swarm
+- **503** – node is not part of a swarm
 
 JSON Parameters:
 
@@ -5262,14 +5265,15 @@ image](#create-an-image) section for more details.
     Content-Type: application/json
 
     {
-      "ID":"ak7w3gjqoa3kuz8xcpnyy0pvl"
+      "ID": "ak7w3gjqoa3kuz8xcpnyy0pvl",
+      "Warnings": ["unable to pin image doesnotexist:latest to digest: image library/doesnotexist:latest not found"]
     }
 
 **Status codes**:
 
 - **201** – no error
-- **406** – server error or node is not part of a swarm
 - **409** – name conflicts with an existing object
+- **503** – server error or node is not part of a swarm
 
 **JSON Parameters**:
 
@@ -5367,7 +5371,7 @@ Stop and remove the service `id`
 
 **Example request**:
 
-    DELETE /services/16253994b7c4 HTTP/1.1
+    DELETE /v1.25/services/16253994b7c4 HTTP/1.1
 
 **Example response**:
 
@@ -5628,6 +5632,16 @@ image](#create-an-image) section for more details.
 -   **404** – no such service
 -   **500** – server error
 
+**Example response**:
+
+    HTTP/1.1 200 OK
+    Content-Type: application/json
+
+    {
+      "Warnings": ["unable to pin image doesnotexist:latest to digest: image library/doesnotexist:latest not found"]
+    }
+
+
 ### Get service logs
 
 `GET /services/(id or name)/logs`
@@ -5639,7 +5653,7 @@ Get `stdout` and `stderr` logs from the service ``id``
 
 **Example request**:
 
-     GET /services/4fa6e0f0c678/logs?stderr=1&stdout=1&timestamps=1&follow=1&tail=10&since=1428990821 HTTP/1.1
+     GET /v1.25/services/4fa6e0f0c678/logs?stderr=1&stdout=1&timestamps=1&follow=1&tail=10&since=1428990821 HTTP/1.1
 
 **Example response**:
 
@@ -5988,7 +6002,7 @@ List secrets
 
 **Example request**:
 
-    GET /secrets HTTP/1.1
+    GET /v1.25/secrets HTTP/1.1
 
 **Example response**:
 
@@ -6026,7 +6040,7 @@ Create a secret
 
 **Example request**:
 
-    POST /secrets/create HTTP/1.1
+    POST /v1.25/secrets/create HTTP/1.1
     Content-Type: application/json
 
     {
@@ -6049,8 +6063,8 @@ Create a secret
 **Status codes**:
 
 - **201** – no error
-- **406** – server error or node is not part of a swarm
 - **409** – name conflicts with an existing object
+- **503** – server error or node is not part of a swarm
 
 **JSON Parameters**:
 
@@ -6066,7 +6080,7 @@ Get details on the secret `id`
 
 **Example request**:
 
-    GET /secrets/ktnbjxoalbkvbvedmg1urrz8h HTTP/1.1
+    GET /v1.25/secrets/ktnbjxoalbkvbvedmg1urrz8h HTTP/1.1
 
 **Example response**:
 
@@ -6099,7 +6113,7 @@ Remove the secret `id` from the secret store
 
 **Example request**:
 
-    DELETE /secrets/ktnbjxoalbkvbvedmg1urrz8h HTTP/1.1
+    DELETE /v1.25/secrets/ktnbjxoalbkvbvedmg1urrz8h HTTP/1.1
 
 **Example response**:
 

+ 19 - 0
docs/reference/commandline/images.md

@@ -28,6 +28,7 @@ Options:
                         - label=<key> or label=<key>=<value>
                         - before=(<image-name>[:tag]|<image-id>|<image@digest>)
                         - since=(<image-name>[:tag]|<image-id>|<image@digest>)
+                        - reference=(pattern of an image reference)
       --format string   Pretty-print images using a Go template
       --help            Print usage
       --no-trunc        Don't truncate output
@@ -229,6 +230,24 @@ Filtering with `since` would give:
     image1              latest              eeae25ada2aa        4 minutes ago        188.3 MB
     image2              latest              dea752e4e117        9 minutes ago        188.3 MB
 
+#### Reference
+
+The `reference` filter shows only images whose reference matches
+the specified pattern.
+
+    $ docker images
+    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
+    busybox             latest              e02e811dd08f        5 weeks ago         1.09 MB
+    busybox             uclibc              e02e811dd08f        5 weeks ago         1.09 MB
+    busybox             musl                733eb3059dce        5 weeks ago         1.21 MB
+    busybox             glibc               21c16b6787c6        5 weeks ago         4.19 MB
+
+Filtering with `reference` would give:
+
+    $ docker images --filter=reference='busy*:*libc'
+    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
+    busybox             uclibc              e02e811dd08f        5 weeks ago         1.09 MB
+    busybox             glibc               21c16b6787c6        5 weeks ago         4.19 MB
 
 ## Formatting
 

+ 50 - 27
docs/reference/commandline/info.md

@@ -47,7 +47,7 @@ available on the volume where `/var/lib/docker` is mounted.
 
 ## Display Docker system information
 
-Here is a sample output for a daemon running on Ubuntu, using the overlay
+Here is a sample output for a daemon running on Ubuntu, using the overlay2
 storage driver and a node that is part of a 2-node swarm:
 
     $ docker -D info
@@ -56,49 +56,72 @@ storage driver and a node that is part of a 2-node swarm:
      Paused: 1
      Stopped: 10
     Images: 52
-    Server Version: 1.12.0-dev
-    Storage Driver: overlay
+    Server Version: 1.13.0
+    Storage Driver: overlay2
      Backing Filesystem: extfs
+     Supports d_type: true
+     Native Overlay Diff: false
     Logging Driver: json-file
     Cgroup Driver: cgroupfs
     Plugins:
      Volume: local
-     Network: bridge null host overlay
-    Swarm:
-     NodeID: 0gac67oclbxq7
+     Network: bridge host macvlan null overlay
+    Swarm: active
+     NodeID: rdjq45w1op418waxlairloqbm
      Is Manager: true
-     Managers: 2
+     ClusterID: te8kdyw33n36fqiz74bfjeixd
+     Managers: 1
      Nodes: 2
-    Runtimes: default
-    Default Runtime: default
-    Security Options: apparmor seccomp
-    Kernel Version: 4.4.0-21-generic
-    Operating System: Ubuntu 16.04 LTS
+     Orchestration:
+      Task History Retention Limit: 5
+     Raft:
+      Snapshot Interval: 10000
+      Number of Old Snapshots to Retain: 0
+      Heartbeat Tick: 1
+      Election Tick: 3
+     Dispatcher:
+      Heartbeat Period: 5 seconds
+     CA Configuration:
+      Expiry Duration: 3 months
+     Node Address: 172.16.66.128 172.16.66.129
+     Manager Addresses:
+      172.16.66.128:2477
+    Runtimes: runc
+    Default Runtime: runc
+    Init Binary: docker-init
+    containerd version: 8517738ba4b82aff5662c97ca4627e7e4d03b531
+    runc version: ac031b5bf1cc92239461125f4c1ffb760522bbf2
+    init version: N/A (expected: v0.13.0)
+    Security Options:
+     apparmor
+     seccomp
+      Profile: default
+    Kernel Version: 4.4.0-31-generic
+    Operating System: Ubuntu 16.04.1 LTS
     OSType: linux
     Architecture: x86_64
-    CPUs: 24
-    Total Memory: 62.86 GiB
-    Name: docker
-    ID: I54V:OLXT:HVMM:TPKO:JPHQ:CQCD:JNLC:O3BZ:4ZVJ:43XJ:PFHZ:6N2S
+    CPUs: 2
+    Total Memory: 1.937 GiB
+    Name: ubuntu
+    ID: H52R:7ZR6:EIIA:76JG:ORIY:BVKF:GSFU:HNPG:B5MK:APSC:SZ3Q:N326
     Docker Root Dir: /var/lib/docker
-    Debug mode (client): true
-    Debug mode (server): true
-     File Descriptors: 59
-     Goroutines: 159
-     System Time: 2016-04-26T10:04:06.14689342-04:00
+    Debug Mode (client): true
+    Debug Mode (server): true
+     File Descriptors: 30
+     Goroutines: 123
+     System Time: 2016-11-12T17:24:37.955404361-08:00
      EventsListeners: 0
-    Http Proxy: http://test:test@localhost:8080
-    Https Proxy: https://test:test@localhost:8080
+    Http Proxy: http://proxy.example.com:80/
     No Proxy: localhost,127.0.0.1,docker-registry.somecorporation.com
-    Username: svendowideit
     Registry: https://index.docker.io/v1/
     WARNING: No swap limit support
     Labels:
      storage=ssd
      staging=true
-    Insecure registries:
-     myinsecurehost:5000
+    Experimental: false
+    Insecure Registries:
      127.0.0.0/8
+    Live Restore Enabled: false
 
 The global `-D` option tells all `docker` commands to output debug information.
 
@@ -168,7 +191,7 @@ Here is a sample output for a daemon running on Windows Server 2016:
      Paused: 0
      Stopped: 1
     Images: 17
-    Server Version: 1.13.0-dev
+    Server Version: 1.13.0
     Storage Driver: windowsfilter
      Windows:
     Logging Driver: json-file

+ 7 - 4
docs/reference/commandline/stats.md

@@ -21,9 +21,10 @@ Usage:  docker stats [OPTIONS] [CONTAINER...]
 Display a live stream of container(s) resource usage statistics
 
 Options:
-  -a, --all         Show all containers (default shows just running)
-      --help        Print usage
-      --no-stream   Disable streaming stats and only pull the first result
+  -a, --all             Show all containers (default shows just running)
+      --format string   Pretty-print images using a Go template
+      --help            Print usage
+      --no-stream       Disable streaming stats and only pull the first result
 ```
 
 The `docker stats` command returns a live data stream for running containers. To limit data to one or more specific containers, specify a list of container names or ids separated by a space. You can specify a stopped container but stopped containers do not return any data.
@@ -77,7 +78,9 @@ Valid placeholders for the Go template are listed below:
 
 Placeholder  | Description
 ------------ | --------------------------------------------
-`.Container` | Container name or ID
+`.Container` | Container name or ID (user input)
+`.Name`      | Container name
+`.ID`        | Container ID
 `.CPUPerc`   | CPU percentage
 `.MemUsage`  | Memory usage
 `.NetIO`     | Network IO

+ 2 - 2
docs/reference/commandline/tag.md

@@ -16,9 +16,9 @@ keywords: "tag, name, image"
 # tag
 
 ```markdown
-Usage:  docker tag IMAGE[:TAG] IMAGE[:TAG]
+Usage:  docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
 
-Tag an image into a repository
+Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
 
 Options:
       --help   Print usage

+ 3 - 3
hack/dockerfile/binaries-commits

@@ -1,8 +1,8 @@
 #!/bin/sh
 
 TOMLV_COMMIT=9baf8a8a9f2ed20a8e54160840c492f937eeaf9a
-RUNC_COMMIT=ac031b5bf1cc92239461125f4c1ffb760522bbf2
-CONTAINERD_COMMIT=8517738ba4b82aff5662c97ca4627e7e4d03b531
-TINI_COMMIT=v0.13.0
+RUNC_COMMIT=51371867a01c467f08af739783b8beafc15
+CONTAINERD_COMMIT=03e5862ec0d8d3b3f750e19fca3ee367e13c090e
+TINI_COMMIT=949e6facb77383876aeff8a6944dde66b3089574
 LIBNETWORK_COMMIT=0f534354b813003a754606689722fe253101bc4e
 VNDR_COMMIT=f56bd4504b4fad07a357913687fb652ee54bb3b0

+ 2 - 1
hack/generate-swagger-api.sh

@@ -8,7 +8,8 @@ swagger generate model -f api/swagger.yaml \
     -n ImageSummary \
     -n Plugin -n PluginDevice -n PluginMount -n PluginEnv -n PluginInterfaceType \
     -n ErrorResponse \
-    -n IdResponse
+    -n IdResponse \
+    -n ServiceUpdateResponse
 
 swagger generate operation -f api/swagger.yaml \
     -t api -a types -m types -C api/swagger-gen.yaml \

+ 1 - 1
hack/validate/vet

@@ -4,7 +4,7 @@ export SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
 source "${SCRIPTDIR}/.validate"
 
 IFS=$'\n'
-files=( $(validate_diff --diff-filter=ACMR --name-only -- '*.go' | grep -v '^vendor/' || true) )
+files=( $(validate_diff --diff-filter=ACMR --name-only -- '*.go' | grep -v '^vendor/' | grep -v '^api/types/container/' || true) )
 unset IFS
 
 errors=()

+ 4 - 1
image/tarexport/load.go

@@ -21,6 +21,7 @@ import (
 	"github.com/docker/docker/pkg/streamformatter"
 	"github.com/docker/docker/pkg/stringid"
 	"github.com/docker/docker/pkg/symlink"
+	"github.com/docker/docker/pkg/system"
 	"github.com/docker/docker/reference"
 )
 
@@ -164,7 +165,9 @@ func (l *tarexporter) setParentID(id, parentID image.ID) error {
 }
 
 func (l *tarexporter) loadLayer(filename string, rootFS image.RootFS, id string, foreignSrc distribution.Descriptor, progressOutput progress.Output) (layer.Layer, error) {
-	rawTar, err := os.Open(filename)
+	// We use system.OpenSequential to use sequential file access on Windows, avoiding
+	// depleting the standby list. On Linux, this equates to a regular os.Open.
+	rawTar, err := system.OpenSequential(filename)
 	if err != nil {
 		logrus.Debugf("Error reading embedded tar: %v", err)
 		return nil, err

+ 4 - 2
image/tarexport/save.go

@@ -315,8 +315,10 @@ func (s *saveSession) saveLayer(id layer.ChainID, legacyImg image.V1Image, creat
 		}
 		os.Symlink(relPath, layerPath)
 	} else {
-
-		tarFile, err := os.Create(layerPath)
+		// Use system.CreateSequential rather than os.Create. This ensures sequential
+		// file access on Windows to avoid eating into MM standby list.
+		// On Linux, this equates to a regular os.Create.
+		tarFile, err := system.CreateSequential(layerPath)
 		if err != nil {
 			return distribution.Descriptor{}, err
 		}

+ 1 - 1
integration-cli/daemon.go

@@ -495,7 +495,7 @@ func (d *Daemon) SockRequest(method, endpoint string, data interface{}) (int, []
 	return res.StatusCode, b, err
 }
 
-// SockRequestRaw executes a socket request on a daemon and returns a http
+// SockRequestRaw executes a socket request on a daemon and returns an http
 // response and a reader for the output data.
 func (d *Daemon) SockRequestRaw(method, endpoint string, data io.Reader, ct string) (*http.Response, io.ReadCloser, error) {
 	return sockRequestRawToDaemon(method, endpoint, data, ct, d.sock())

+ 23 - 27
integration-cli/docker_cli_build_test.go

@@ -1865,6 +1865,10 @@ func (s *DockerSuite) TestBuildWindowsWorkdirProcessing(c *check.C) {
 func (s *DockerSuite) TestBuildWindowsAddCopyPathProcessing(c *check.C) {
 	testRequires(c, DaemonIsWindows)
 	name := "testbuildwindowsaddcopypathprocessing"
+	// TODO Windows (@jhowardmsft). Needs a follow-up PR to 22181 to
+	// support backslash such as .\\ being equivalent to ./ and c:\\ being
+	// equivalent to c:/. This is not currently (nor ever has been) supported
+	// by docker on the Windows platform.
 	dockerfile := `
 		FROM busybox
 			# No trailing slash on COPY/ADD
@@ -1874,8 +1878,8 @@ func (s *DockerSuite) TestBuildWindowsAddCopyPathProcessing(c *check.C) {
 			WORKDIR /wc2
 			ADD wc2 c:/wc2
 			WORKDIR c:/
-			RUN sh -c "[ $(cat c:/wc1/wc1) = 'hellowc1' ]"
-			RUN sh -c "[ $(cat c:/wc2/wc2) = 'worldwc2' ]"
+			RUN sh -c "[ $(cat c:/wc1) = 'hellowc1' ]"
+			RUN sh -c "[ $(cat c:/wc2) = 'worldwc2' ]"
 
 			# Trailing slash on COPY/ADD, Windows-style path.
 			WORKDIR /wd1
@@ -7172,31 +7176,6 @@ RUN echo vegeta
 	c.Assert(out, checker.Contains, "Step 3/3 : RUN echo vegeta")
 }
 
-// Verifies if COPY file . when WORKDIR is set to a non-existing directory,
-// the directory is created and the file is copied into the directory,
-// as opposed to the file being copied as a file with the name of the
-// directory. Fix for 27545 (found on Windows, but regression good for Linux too)
-func (s *DockerSuite) TestBuildCopyFileDotWithWorkdir(c *check.C) {
-	name := "testbuildcopyfiledotwithworkdir"
-
-	ctx, err := fakeContext(`FROM busybox
-WORKDIR /foo
-COPY file .
-RUN ["cat", "/foo/file"]
-`,
-		map[string]string{})
-	if err != nil {
-		c.Fatal(err)
-	}
-	defer ctx.Close()
-	if err := ctx.Add("file", "content"); err != nil {
-		c.Fatal(err)
-	}
-	if _, err = buildImageFromContext(name, ctx, true); err != nil {
-		c.Fatal(err)
-	}
-}
-
 func (s *DockerSuite) TestBuildSquashParent(c *check.C) {
 	testRequires(c, ExperimentalDaemon)
 	dockerFile := `
@@ -7287,3 +7266,20 @@ func (s *DockerSuite) TestBuildOpaqueDirectory(c *check.C) {
 	_, err := buildImage("testopaquedirectory", dockerFile, false)
 	c.Assert(err, checker.IsNil)
 }
+
+// Windows test for USER in dockerfile
+func (s *DockerSuite) TestBuildWindowsUser(c *check.C) {
+	testRequires(c, DaemonIsWindows)
+	name := "testbuildwindowsuser"
+	_, out, err := buildImageWithOut(name,
+		`FROM `+WindowsBaseImage+`
+		RUN net user user /add
+		USER user
+		RUN set username
+		`,
+		true)
+	if err != nil {
+		c.Fatal(err)
+	}
+	c.Assert(strings.ToLower(out), checker.Contains, "username=user")
+}

+ 1 - 1
integration-cli/docker_cli_help_test.go

@@ -196,7 +196,7 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) {
 	stdout, stderr, _, err = runCommandWithStdoutStderr(cmd)
 	c.Assert(err, checker.NotNil)
 	c.Assert(stdout, checker.Equals, "")
-	c.Assert(stderr, checker.Equals, "docker: 'BadCmd' is not a docker command.\nSee 'docker --help'.\n", check.Commentf("Unexcepted output for 'docker badCmd'\n"))
+	c.Assert(stderr, checker.Equals, "docker: 'BadCmd' is not a docker command.\nSee 'docker --help'\n", check.Commentf("Unexcepted output for 'docker badCmd'\n"))
 }
 
 func testCommand(cmd string, newEnvs []string, scanForHome bool, home string) error {

+ 16 - 0
integration-cli/docker_cli_swarm_test.go

@@ -1072,3 +1072,19 @@ func (s *DockerSwarmSuite) TestSwarmManagerAddress(c *check.C) {
 	c.Assert(err, checker.IsNil)
 	c.Assert(out, checker.Contains, expectedOutput)
 }
+
+func (s *DockerSwarmSuite) TestSwarmServiceInspectPretty(c *check.C) {
+	d := s.AddDaemon(c, true, true)
+
+	name := "top"
+	out, err := d.Cmd("service", "create", "--name", name, "--limit-cpu=0.5", "busybox", "top")
+	c.Assert(err, checker.IsNil, check.Commentf(out))
+
+	expectedOutput := `
+Resources:
+ Limits:
+  CPU:		0.5`
+	out, err = d.Cmd("service", "inspect", "--pretty", name)
+	c.Assert(err, checker.IsNil, check.Commentf(out))
+	c.Assert(out, checker.Contains, expectedOutput, check.Commentf(out))
+}

+ 1 - 1
libcontainerd/remote_unix.go

@@ -67,7 +67,7 @@ type remote struct {
 func New(stateDir string, options ...RemoteOption) (_ Remote, err error) {
 	defer func() {
 		if err != nil {
-			err = fmt.Errorf("Failed to connect to containerd. Please make sure containerd is installed in your PATH or you have specificed the correct address. Got error: %v", err)
+			err = fmt.Errorf("Failed to connect to containerd. Please make sure containerd is installed in your PATH or you have specified the correct address. Got error: %v", err)
 		}
 	}()
 	r := &remote{

+ 52 - 27
man/docker-info.1.md

@@ -39,7 +39,7 @@ available on the volume where `/var/lib/docker` is mounted.
 
 ## Display Docker system information
 
-Here is a sample output for a daemon running on Ubuntu, using the overlay
+Here is a sample output for a daemon running on Ubuntu, using the overlay2
 storage driver:
 
     $ docker -D info
@@ -48,49 +48,74 @@ storage driver:
      Paused: 1
      Stopped: 10
     Images: 52
-    Server Version: 1.12.0-dev
-    Storage Driver: overlay
+    Server Version: 1.13.0
+    Storage Driver: overlay2
      Backing Filesystem: extfs
+     Supports d_type: true
+     Native Overlay Diff: false
     Logging Driver: json-file
     Cgroup Driver: cgroupfs
     Plugins:
      Volume: local
-     Network: bridge null host overlay
-    Swarm: 
-     NodeID: 0gac67oclbxq7
-     IsManager: YES
-     Managers: 2
+     Network: bridge host macvlan null overlay
+    Swarm: active
+     NodeID: rdjq45w1op418waxlairloqbm
+     Is Manager: true
+     ClusterID: te8kdyw33n36fqiz74bfjeixd
+     Managers: 1
      Nodes: 2
-    Runtimes: default
-    Default Runtime: default
-    Security Options: apparmor seccomp
-    Kernel Version: 4.4.0-21-generic
-    Operating System: Ubuntu 16.04 LTS
+     Orchestration:
+      Task History Retention Limit: 5
+     Raft:
+      Snapshot Interval: 10000
+      Number of Old Snapshots to Retain: 0
+      Heartbeat Tick: 1
+      Election Tick: 3
+     Dispatcher:
+      Heartbeat Period: 5 seconds
+     CA Configuration:
+      Expiry Duration: 3 months
+     Node Address: 172.16.66.128 172.16.66.129
+     Manager Addresses:
+      172.16.66.128:2477
+    Runtimes: runc
+    Default Runtime: runc
+    Init Binary: docker-init
+    containerd version: 8517738ba4b82aff5662c97ca4627e7e4d03b531
+    runc version: ac031b5bf1cc92239461125f4c1ffb760522bbf2
+    init version: N/A (expected: v0.13.0)
+    Security Options:
+     apparmor
+     seccomp
+      Profile: default
+    Kernel Version: 4.4.0-31-generic
+    Operating System: Ubuntu 16.04.1 LTS
     OSType: linux
     Architecture: x86_64
-    CPUs: 24
-    Total Memory: 62.86 GiB
-    Name: docker
-    ID: I54V:OLXT:HVMM:TPKO:JPHQ:CQCD:JNLC:O3BZ:4ZVJ:43XJ:PFHZ:6N2S
+    CPUs: 2
+    Total Memory: 1.937 GiB
+    Name: ubuntu
+    ID: H52R:7ZR6:EIIA:76JG:ORIY:BVKF:GSFU:HNPG:B5MK:APSC:SZ3Q:N326
     Docker Root Dir: /var/lib/docker
-    Debug mode (client): true
-    Debug mode (server): true
-     File Descriptors: 59
-     Goroutines: 159
-     System Time: 2016-04-26T10:04:06.14689342-04:00
+    Debug Mode (client): true
+    Debug Mode (server): true
+     File Descriptors: 30
+     Goroutines: 123
+     System Time: 2016-11-12T17:24:37.955404361-08:00
      EventsListeners: 0
-    Http Proxy: http://test:test@localhost:8080
-    Https Proxy: https://test:test@localhost:8080
+    Http Proxy: http://proxy.example.com:80/
     No Proxy: localhost,127.0.0.1,docker-registry.somecorporation.com
-    Username: svendowideit
     Registry: https://index.docker.io/v1/
     WARNING: No swap limit support
     Labels:
      storage=ssd
      staging=true
-    Insecure registries:
-     myinsecurehost:5000
+    Experimental: false
+    Insecure Registries:
      127.0.0.0/8
+    Live Restore Enabled: false
+
+
 
 The global `-D` option tells all `docker` commands to output debug information.
 

+ 1 - 1
man/docker-run.1.md

@@ -907,7 +907,7 @@ should fix the problem.
 ## Mapping Ports for External Usage
 
 The exposed port of an application can be mapped to a host port using the **-p**
-flag. For example, a httpd port 80 can be mapped to the host port 8080 using the
+flag. For example, an httpd port 80 can be mapped to the host port 8080 using the
 following:
 
     # docker run -p 8080:80 -d -i -t fedora/httpd

+ 2 - 0
man/docker-stats.1.md

@@ -30,6 +30,8 @@ Display a live stream of one or more containers' resource usage statistics
    Pretty-print containers statistics using a Go template.
    Valid placeholders:
       .Container - Container name or ID.
+      .Name - Container name.
+      .ID - Container ID.
       .CPUPerc - CPU percentage.
       .MemUsage - Memory usage.
       .NetIO - Network IO.

+ 2 - 2
man/docker-tag.1.md

@@ -2,12 +2,12 @@
 % Docker Community
 % JUNE 2014
 # NAME
-docker-tag - Tag an image into a repository
+docker-tag - Create a tag `TARGET_IMAGE` that refers to `SOURCE_IMAGE`
 
 # SYNOPSIS
 **docker tag**
 [**--help**]
-NAME[:TAG] NAME[:TAG]
+SOURCE_NAME[:TAG] TARGET_NAME[:TAG]
 
 # DESCRIPTION
 Assigns a new alias to an image in a registry. An alias refers to the

+ 1 - 0
opts/port.go

@@ -16,6 +16,7 @@ const (
 	portOptMode          = "mode"
 )
 
+// PortOpt represents a port config in swarm mode.
 type PortOpt struct {
 	ports []swarm.PortConfig
 }

+ 8 - 3
pkg/archive/archive.go

@@ -374,7 +374,10 @@ func (ta *tarAppender) addTarFile(path, name string) error {
 	}
 
 	if hdr.Typeflag == tar.TypeReg && hdr.Size > 0 {
-		file, err := os.Open(path)
+		// We use system.OpenSequential to ensure we use sequential file
+		// access on Windows to avoid depleting the standby list.
+		// On Linux, this equates to a regular os.Open.
+		file, err := system.OpenSequential(path)
 		if err != nil {
 			return err
 		}
@@ -412,8 +415,10 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
 		}
 
 	case tar.TypeReg, tar.TypeRegA:
-		// Source is regular file
-		file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, hdrInfo.Mode())
+		// Source is regular file. We use system.OpenFileSequential to use sequential
+		// file access to avoid depleting the standby list on Windows.
+		// On Linux, this equates to a regular os.OpenFile
+		file, err := system.OpenFileSequential(path, os.O_CREATE|os.O_WRONLY, hdrInfo.Mode())
 		if err != nil {
 			return err
 		}

+ 1 - 1
pkg/devicemapper/devmapper_wrapper_no_deferred_remove.go

@@ -2,7 +2,7 @@
 
 package devicemapper
 
-// LibraryDeferredRemovalsupport is not supported when statically linked.
+// LibraryDeferredRemovalSupport is not supported when statically linked.
 const LibraryDeferredRemovalSupport = false
 
 func dmTaskDeferredRemoveFct(task *cdmTask) int {

+ 1 - 1
pkg/discovery/backends.go

@@ -86,7 +86,7 @@ func ParseAdvertise(advertise string) (string, error) {
 		break
 	}
 	if addr == "" {
-		return "", fmt.Errorf("couldnt find a valid ip-address in interface %s", advertise)
+		return "", fmt.Errorf("could not find a valid ip-address in interface %s", advertise)
 	}
 
 	addr = net.JoinHostPort(addr, port)

+ 4 - 4
pkg/ioutils/multireader.go

@@ -155,18 +155,18 @@ func (r *multiReadSeeker) Read(b []byte) (int, error) {
 		r.pos = &pos{0, 0}
 	}
 
-	bCap := int64(cap(b))
+	bLen := int64(len(b))
 	buf := bytes.NewBuffer(nil)
 	var rdr io.ReadSeeker
 
 	for _, rdr = range r.readers[r.pos.idx:] {
-		readBytes, err := io.CopyN(buf, rdr, bCap)
+		readBytes, err := io.CopyN(buf, rdr, bLen)
 		if err != nil && err != io.EOF {
 			return -1, err
 		}
-		bCap -= readBytes
+		bLen -= readBytes
 
-		if bCap == 0 {
+		if bLen == 0 {
 			break
 		}
 	}

+ 21 - 0
pkg/ioutils/multireader_test.go

@@ -2,6 +2,7 @@ package ioutils
 
 import (
 	"bytes"
+	"encoding/binary"
 	"fmt"
 	"io"
 	"io/ioutil"
@@ -188,3 +189,23 @@ func TestMultiReadSeekerCurAfterSet(t *testing.T) {
 		t.Fatalf("reader size does not match, got %d, expected %d", size, mid+18)
 	}
 }
+
+func TestMultiReadSeekerSmallReads(t *testing.T) {
+	readers := []io.ReadSeeker{}
+	for i := 0; i < 10; i++ {
+		integer := make([]byte, 4, 4)
+		binary.BigEndian.PutUint32(integer, uint32(i))
+		readers = append(readers, bytes.NewReader(integer))
+	}
+
+	reader := MultiReadSeeker(readers...)
+	for i := 0; i < 10; i++ {
+		var integer uint32
+		if err := binary.Read(reader, binary.BigEndian, &integer); err != nil {
+			t.Fatalf("Read from NewMultiReadSeeker failed: %v", err)
+		}
+		if uint32(i) != integer {
+			t.Fatalf("Read wrong value from NewMultiReadSeeker: %d != %d", i, integer)
+		}
+	}
+}

+ 29 - 0
pkg/system/filesys.go

@@ -23,3 +23,32 @@ func MkdirAll(path string, perm os.FileMode) error {
 func IsAbs(path string) bool {
 	return filepath.IsAbs(path)
 }
+
+// The functions below here are wrappers for the equivalents in the os package.
+// They are passthrough on Unix platforms, and only relevant on Windows.
+
+// CreateSequential creates the named file with mode 0666 (before umask), truncating
+// it if it already exists. If successful, methods on the returned
+// File can be used for I/O; the associated file descriptor has mode
+// O_RDWR.
+// If there is an error, it will be of type *PathError.
+func CreateSequential(name string) (*os.File, error) {
+	return os.Create(name)
+}
+
+// OpenSequential opens the named file for reading. If successful, methods on
+// the returned file can be used for reading; the associated file
+// descriptor has mode O_RDONLY.
+// If there is an error, it will be of type *PathError.
+func OpenSequential(name string) (*os.File, error) {
+	return os.Open(name)
+}
+
+// OpenFileSequential is the generalized open call; most users will use Open
+// or Create instead. It opens the named file with specified flag
+// (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
+// methods on the returned File can be used for I/O.
+// If there is an error, it will be of type *PathError.
+func OpenFileSequential(name string, flag int, perm os.FileMode) (*os.File, error) {
+	return os.OpenFile(name, flag, perm)
+}

+ 106 - 3
pkg/system/filesys_windows.go

@@ -98,7 +98,7 @@ func mkdirWithACL(name string) error {
 	sddl := "D:P(A;OICI;GA;;;BA)(A;OICI;GA;;;SY)"
 	sd, err := winio.SddlToSecurityDescriptor(sddl)
 	if err != nil {
-		return &os.PathError{"mkdir", name, err}
+		return &os.PathError{Op: "mkdir", Path: name, Err: err}
 	}
 	sa.Length = uint32(unsafe.Sizeof(sa))
 	sa.InheritHandle = 1
@@ -106,12 +106,12 @@ func mkdirWithACL(name string) error {
 
 	namep, err := syscall.UTF16PtrFromString(name)
 	if err != nil {
-		return &os.PathError{"mkdir", name, err}
+		return &os.PathError{Op: "mkdir", Path: name, Err: err}
 	}
 
 	e := syscall.CreateDirectory(namep, &sa)
 	if e != nil {
-		return &os.PathError{"mkdir", name, e}
+		return &os.PathError{Op: "mkdir", Path: name, Err: e}
 	}
 	return nil
 }
@@ -131,3 +131,106 @@ func IsAbs(path string) bool {
 	}
 	return true
 }
+
+// The origin of the functions below here are the golang OS and syscall packages,
+// slightly modified to only cope with files, not directories due to the
+// specific use case.
+//
+// The alteration is to allow a file on Windows to be opened with
+// FILE_FLAG_SEQUENTIAL_SCAN (particular for docker load), to avoid eating
+// the standby list, particularly when accessing large files such as layer.tar.
+
+// CreateSequential creates the named file with mode 0666 (before umask), truncating
+// it if it already exists. If successful, methods on the returned
+// File can be used for I/O; the associated file descriptor has mode
+// O_RDWR.
+// If there is an error, it will be of type *PathError.
+func CreateSequential(name string) (*os.File, error) {
+	return OpenFileSequential(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0)
+}
+
+// OpenSequential opens the named file for reading. If successful, methods on
+// the returned file can be used for reading; the associated file
+// descriptor has mode O_RDONLY.
+// If there is an error, it will be of type *PathError.
+func OpenSequential(name string) (*os.File, error) {
+	return OpenFileSequential(name, os.O_RDONLY, 0)
+}
+
+// OpenFileSequential is the generalized open call; most users will use Open
+// or Create instead.
+// If there is an error, it will be of type *PathError.
+func OpenFileSequential(name string, flag int, _ os.FileMode) (*os.File, error) {
+	if name == "" {
+		return nil, &os.PathError{Op: "open", Path: name, Err: syscall.ENOENT}
+	}
+	r, errf := syscallOpenFileSequential(name, flag, 0)
+	if errf == nil {
+		return r, nil
+	}
+	return nil, &os.PathError{Op: "open", Path: name, Err: errf}
+}
+
+func syscallOpenFileSequential(name string, flag int, _ os.FileMode) (file *os.File, err error) {
+	r, e := syscallOpenSequential(name, flag|syscall.O_CLOEXEC, 0)
+	if e != nil {
+		return nil, e
+	}
+	return os.NewFile(uintptr(r), name), nil
+}
+
+func makeInheritSa() *syscall.SecurityAttributes {
+	var sa syscall.SecurityAttributes
+	sa.Length = uint32(unsafe.Sizeof(sa))
+	sa.InheritHandle = 1
+	return &sa
+}
+
+func syscallOpenSequential(path string, mode int, _ uint32) (fd syscall.Handle, err error) {
+	if len(path) == 0 {
+		return syscall.InvalidHandle, syscall.ERROR_FILE_NOT_FOUND
+	}
+	pathp, err := syscall.UTF16PtrFromString(path)
+	if err != nil {
+		return syscall.InvalidHandle, err
+	}
+	var access uint32
+	switch mode & (syscall.O_RDONLY | syscall.O_WRONLY | syscall.O_RDWR) {
+	case syscall.O_RDONLY:
+		access = syscall.GENERIC_READ
+	case syscall.O_WRONLY:
+		access = syscall.GENERIC_WRITE
+	case syscall.O_RDWR:
+		access = syscall.GENERIC_READ | syscall.GENERIC_WRITE
+	}
+	if mode&syscall.O_CREAT != 0 {
+		access |= syscall.GENERIC_WRITE
+	}
+	if mode&syscall.O_APPEND != 0 {
+		access &^= syscall.GENERIC_WRITE
+		access |= syscall.FILE_APPEND_DATA
+	}
+	sharemode := uint32(syscall.FILE_SHARE_READ | syscall.FILE_SHARE_WRITE)
+	var sa *syscall.SecurityAttributes
+	if mode&syscall.O_CLOEXEC == 0 {
+		sa = makeInheritSa()
+	}
+	var createmode uint32
+	switch {
+	case mode&(syscall.O_CREAT|syscall.O_EXCL) == (syscall.O_CREAT | syscall.O_EXCL):
+		createmode = syscall.CREATE_NEW
+	case mode&(syscall.O_CREAT|syscall.O_TRUNC) == (syscall.O_CREAT | syscall.O_TRUNC):
+		createmode = syscall.CREATE_ALWAYS
+	case mode&syscall.O_CREAT == syscall.O_CREAT:
+		createmode = syscall.OPEN_ALWAYS
+	case mode&syscall.O_TRUNC == syscall.O_TRUNC:
+		createmode = syscall.TRUNCATE_EXISTING
+	default:
+		createmode = syscall.OPEN_EXISTING
+	}
+	// Use FILE_FLAG_SEQUENTIAL_SCAN rather than FILE_ATTRIBUTE_NORMAL as implemented in golang.
+	//https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
+	const fileFlagSequentialScan = 0x08000000 // FILE_FLAG_SEQUENTIAL_SCAN
+	h, e := syscall.CreateFile(pathp, access, sharemode, sa, createmode, fileFlagSequentialScan, 0)
+	return h, e
+}

Some files were not shown because too many files changed in this diff