diff --git a/cli/command/cli.go b/cli/command/cli.go index 242b5f0358ff..a9cfc779b9ad 100644 --- a/cli/command/cli.go +++ b/cli/command/cli.go @@ -198,7 +198,7 @@ func (cli *DockerCli) initializeFromClient() { ping, err := cli.client.Ping(context.Background()) if err != nil { // Default to true if we fail to connect to daemon - cli.serverInfo = ServerInfo{HasExperimental: true} + cli.serverInfo = ServerInfo{HasExperimental: true, APIVersion: ping.APIVersion} if ping.APIVersion != "" { cli.client.NegotiateAPIVersionPing(ping) @@ -210,6 +210,7 @@ func (cli *DockerCli) initializeFromClient() { HasExperimental: ping.Experimental, OSType: ping.OSType, BuildkitVersion: ping.BuilderVersion, + APIVersion: ping.APIVersion, } cli.client.NegotiateAPIVersionPing(ping) } @@ -244,6 +245,7 @@ type ServerInfo struct { HasExperimental bool OSType string BuildkitVersion types.BuilderVersion + APIVersion string } // ClientInfo stores details about the supported features of the client diff --git a/cli/command/cli_test.go b/cli/command/cli_test.go index a4b06e699753..c56b1cbd2132 100644 --- a/cli/command/cli_test.go +++ b/cli/command/cli_test.go @@ -87,7 +87,7 @@ func TestInitializeFromClient(t *testing.T) { pingFunc: func() (types.Ping, error) { return types.Ping{Experimental: true, OSType: "linux", APIVersion: "v1.30"}, nil }, - expectedServer: ServerInfo{HasExperimental: true, OSType: "linux"}, + expectedServer: ServerInfo{HasExperimental: true, OSType: "linux", APIVersion: "v1.30"}, negotiated: true, }, { @@ -102,7 +102,7 @@ func TestInitializeFromClient(t *testing.T) { pingFunc: func() (types.Ping, error) { return types.Ping{APIVersion: "v1.33"}, errors.New("failed") }, - expectedServer: ServerInfo{HasExperimental: true}, + expectedServer: ServerInfo{HasExperimental: true, APIVersion: "v1.33"}, negotiated: true, }, } diff --git a/cli/command/container/create.go b/cli/command/container/create.go index 62d1a088aa78..ecaa529c7b29 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.ServerInfo().APIVersion); 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..f5f9dab3f024 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.ServerInfo().APIVersion); err != nil { + reportError(dockerCli.Err(), "run", err.Error(), true) + return cli.StatusError{StatusCode: 125} + } return runContainer(dockerCli, ropts, copts, containerConfig) } 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.