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

1.13.0-rc2 cherry-picks : part 2
This commit is contained in:
Brian Goff 2016-11-20 10:43:55 -05:00 committed by GitHub
commit f7ae8204cb
117 changed files with 1166 additions and 534 deletions

View file

@ -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
}
}

View file

@ -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)),
}
}

View file

@ -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,
}
}

View file

@ -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)

View file

@ -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),

View file

@ -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 {

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -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"`
}

View file

@ -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"`

View file

@ -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

View file

@ -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"`

View file

@ -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"`

View file

@ -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

View file

@ -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),

View file

@ -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

View file

@ -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),

View file

@ -59,20 +59,18 @@ func newListCommand(dockerCli *command.DockerCli) *cobra.Command {
return &cmd
}
type preProcessor struct {
types.Container
opts *types.ContainerListOptions
// 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
// 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
// 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
}

View file

@ -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 {

View file

@ -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()

View file

@ -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
}

View file

@ -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),

View file

@ -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
}

View file

@ -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]

View file

@ -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),

View file

@ -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),

View file

@ -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(

View file

@ -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),

View file

@ -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),

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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),

View file

@ -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
}

View file

@ -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
}

View file

@ -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),

View file

@ -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),

View file

@ -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),

View file

@ -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)

View file

@ -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}
}
}

View file

@ -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
}

View file

@ -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)
}

View file

@ -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
}

View file

@ -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...)
}

View file

@ -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))
}

View file

@ -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")
}

View file

@ -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:'

View file

@ -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) \

View file

@ -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,

View file

@ -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)

View file

@ -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)

View file

@ -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
}

View file

@ -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 {

View file

@ -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 {

View file

@ -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
}

View file

@ -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)
}

View file

@ -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 {

View file

@ -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"}
}

View file

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

View file

@ -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)

View file

@ -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

View file

@ -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) {
}

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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**:

View file

@ -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**:

View file

@ -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**:

View file

@ -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**:

View file

@ -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**:

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 \

View file

@ -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=()

View file

@ -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

View file

@ -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
}

View file

@ -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())

View file

@ -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")
}

View file

@ -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 {

View file

@ -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))
}

View file

@ -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{

View file

@ -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.

View file

@ -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

View file

@ -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.

View file

@ -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

View file

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

View file

@ -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
}

View file

@ -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 {

View file

@ -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)

View file

@ -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
}
}

View file

@ -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)
}
}
}

View file

@ -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)
}

View file

@ -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 have changed in this diff Show more