diff --git a/cli/command/container/create.go b/cli/command/container/create.go index 62d1a088aa78..5a7805c3c020 100644 --- a/cli/command/container/create.go +++ b/cli/command/container/create.go @@ -65,6 +65,10 @@ func runCreate(dockerCli command.Cli, flags *pflag.FlagSet, opts *createOptions, reportError(dockerCli.Err(), "create", err.Error(), true) return cli.StatusError{StatusCode: 125} } + if err = validateAPIVersion(containerConfig, dockerCli.Client().ClientVersion()); err != nil { + reportError(dockerCli.Err(), "create", err.Error(), true) + return cli.StatusError{StatusCode: 125} + } response, err := createContainer(context.Background(), dockerCli, containerConfig, opts) if err != nil { return err diff --git a/cli/command/container/opts.go b/cli/command/container/opts.go index 97906b672252..af9d44ea7d1f 100644 --- a/cli/command/container/opts.go +++ b/cli/command/container/opts.go @@ -16,6 +16,7 @@ import ( "github.com/docker/docker/api/types/container" networktypes "github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/strslice" + "github.com/docker/docker/api/types/versions" "github.com/docker/docker/pkg/signal" "github.com/docker/go-connections/nat" "github.com/pkg/errors" @@ -866,3 +867,12 @@ func validateAttach(val string) (string, error) { } return val, errors.Errorf("valid streams are STDIN, STDOUT and STDERR") } + +func validateAPIVersion(c *containerConfig, serverAPIVersion string) error { + for _, m := range c.HostConfig.Mounts { + if m.BindOptions != nil && m.BindOptions.NoRecursive && versions.LessThan(serverAPIVersion, "1.40") { + return errors.Errorf("bind-norecursive requires API v1.40 or later") + } + } + return nil +} diff --git a/cli/command/container/run.go b/cli/command/container/run.go index d2ca58739f85..e1faadfd8e56 100644 --- a/cli/command/container/run.go +++ b/cli/command/container/run.go @@ -114,6 +114,10 @@ func runRun(dockerCli command.Cli, flags *pflag.FlagSet, ropts *runOptions, copt reportError(dockerCli.Err(), "run", err.Error(), true) return cli.StatusError{StatusCode: 125} } + if err = validateAPIVersion(containerConfig, dockerCli.Client().ClientVersion()); err != nil { + reportError(dockerCli.Err(), "run", err.Error(), true) + return cli.StatusError{StatusCode: 125} + } return runContainer(dockerCli, ropts, copts, containerConfig) } diff --git a/cli/command/service/create.go b/cli/command/service/create.go index ec74eb43c3f6..c045682e0328 100644 --- a/cli/command/service/create.go +++ b/cli/command/service/create.go @@ -79,6 +79,10 @@ func runCreate(dockerCli command.Cli, flags *pflag.FlagSet, opts *serviceOptions return err } + if err = validateAPIVersion(service, dockerCli.Client().ClientVersion()); err != nil { + return err + } + specifiedSecrets := opts.secrets.Value() if len(specifiedSecrets) > 0 { // parse and validate secrets diff --git a/cli/command/service/opts.go b/cli/command/service/opts.go index 834b53704876..71b1b7c52145 100644 --- a/cli/command/service/opts.go +++ b/cli/command/service/opts.go @@ -12,6 +12,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/swarm" + "github.com/docker/docker/api/types/versions" "github.com/docker/docker/client" "github.com/docker/swarmkit/api" "github.com/docker/swarmkit/api/defaults" @@ -909,3 +910,12 @@ const ( flagConfigRemove = "config-rm" flagIsolation = "isolation" ) + +func validateAPIVersion(c swarm.ServiceSpec, serverAPIVersion string) error { + for _, m := range c.TaskTemplate.ContainerSpec.Mounts { + if m.BindOptions != nil && m.BindOptions.NoRecursive && versions.LessThan(serverAPIVersion, "1.40") { + return errors.Errorf("bind-norecursive requires API v1.40 or later") + } + } + return nil +} diff --git a/opts/mount.go b/opts/mount.go index 3aa9849421ac..9ba221b703ec 100644 --- a/opts/mount.go +++ b/opts/mount.go @@ -76,6 +76,9 @@ func (m *MountOpt) Set(value string) error { case "volume-nocopy": volumeOptions().NoCopy = true continue + case "bind-norecursive": + bindOptions().NoRecursive = true + continue } } diff --git a/vendor/github.com/docker/docker/api/common.go b/vendor/github.com/docker/docker/api/common.go index 4582eb92e0c3..aa146cdaeb1a 100644 --- a/vendor/github.com/docker/docker/api/common.go +++ b/vendor/github.com/docker/docker/api/common.go @@ -3,7 +3,7 @@ package api // import "github.com/docker/docker/api" // Common constants for daemon and client. const ( // DefaultVersion of Current REST API - DefaultVersion = "1.39" + DefaultVersion = "1.40" // NoBaseImageSpecifier is the symbol used by the FROM // command to specify that no base image is to be used. diff --git a/vendor/github.com/docker/docker/api/types/mount/mount.go b/vendor/github.com/docker/docker/api/types/mount/mount.go index 3fef974df883..fc8610f61b95 100644 --- a/vendor/github.com/docker/docker/api/types/mount/mount.go +++ b/vendor/github.com/docker/docker/api/types/mount/mount.go @@ -80,6 +80,7 @@ const ( // BindOptions defines options specific to mounts of type "bind". type BindOptions struct { Propagation Propagation `json:",omitempty"` + NoRecursive bool `json:",omitempty"` } // VolumeOptions represents the options for a mount of type volume.