Browse code

client: add API-version dependent validation for mount options

[docker/cli@fc6976d] added support for recursive readonly mounts in the
CLI, adding a ValidateMountWithAPIVersion utility to verify if options
used were supported by the API version.

We usually keep API-version dependent checks in the client, so that
docker/cli (and other users of the client) don't have to implement
their own validation for these.

This patch moves the functionality of ValidateMountWithAPIVersion to
the client.

Once the docker/cli vendoring was updated, we can remove the utility
there.

[docker/cli@fc6976d]: https://github.com/docker/cli/commit/fc6976db45e24cc2baff50d806402ae2a8468a13

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Sebastiaan van Stijn authored on 2025/03/10 06:03:00
Showing 2 changed files
... ...
@@ -3,6 +3,7 @@ package client // import "github.com/docker/docker/client"
3 3
 import (
4 4
 	"context"
5 5
 	"encoding/json"
6
+	"errors"
6 7
 	"net/url"
7 8
 	"path"
8 9
 	"sort"
... ...
@@ -54,6 +55,19 @@ func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config
54 54
 			// When using API under 1.42, the Linux daemon doesn't respect the ConsoleSize
55 55
 			hostConfig.ConsoleSize = [2]uint{0, 0}
56 56
 		}
57
+		if versions.LessThan(cli.ClientVersion(), "1.44") {
58
+			for _, m := range hostConfig.Mounts {
59
+				if m.BindOptions != nil {
60
+					// ReadOnlyNonRecursive can be safely ignored when API < 1.44
61
+					if m.BindOptions.ReadOnlyForceRecursive {
62
+						return response, errors.New("bind-recursive=readonly requires API v1.44 or later")
63
+					}
64
+					if m.BindOptions.NonRecursive && versions.LessThan(cli.ClientVersion(), "1.40") {
65
+						return response, errors.New("bind-recursive=disabled requires API v1.40 or later")
66
+					}
67
+				}
68
+			}
69
+		}
57 70
 
58 71
 		hostConfig.CapAdd = normalizeCapabilities(hostConfig.CapAdd)
59 72
 		hostConfig.CapDrop = normalizeCapabilities(hostConfig.CapDrop)
... ...
@@ -37,6 +37,11 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec,
37 37
 	if err := validateServiceSpec(service); err != nil {
38 38
 		return response, err
39 39
 	}
40
+	if versions.LessThan(cli.version, "1.30") {
41
+		if err := validateAPIVersion(service, cli.version); err != nil {
42
+			return response, err
43
+		}
44
+	}
40 45
 
41 46
 	// ensure that the image is tagged
42 47
 	var resolveWarning string
... ...
@@ -191,3 +196,18 @@ func validateServiceSpec(s swarm.ServiceSpec) error {
191 191
 	}
192 192
 	return nil
193 193
 }
194
+
195
+func validateAPIVersion(c swarm.ServiceSpec, apiVersion string) error {
196
+	for _, m := range c.TaskTemplate.ContainerSpec.Mounts {
197
+		if m.BindOptions != nil {
198
+			if m.BindOptions.NonRecursive && versions.LessThan(apiVersion, "1.40") {
199
+				return errors.Errorf("bind-recursive=disabled requires API v1.40 or later")
200
+			}
201
+			// ReadOnlyNonRecursive can be safely ignored when API < 1.44
202
+			if m.BindOptions.ReadOnlyForceRecursive && versions.LessThan(apiVersion, "1.44") {
203
+				return errors.Errorf("bind-recursive=readonly requires API v1.44 or later")
204
+			}
205
+		}
206
+	}
207
+	return nil
208
+}