Browse code

print error if unsupported flags are used

Docker 1.13 and up allows a client to communicate
with older daemons. As a result, flags may be
present that are not supported by the older daemon.

The client already _hides_ flags that are not
supported yet, but this doesn't present users
from using those flags.

This change shows an error if a flag is used
that is not supported by the daemon (either
based on the API version, or because experimental
features are not enabled).

Note that for some options, a check is already
in place in the API client. For those
options, this is just a minor enhancement
to more clearly indicate which _flag_ is
not supported.

Before this change;

DOCKER_API_VERSION=1.24 docker run -d --stop-timeout=30 busybox top
mjfyt3qpvnq0iwmun3sjwth9i

echo -e "FROM busybox\nRUN echo foo > bar" | DOCKER_API_VERSION=1.24 docker build --squash -
"squash" requires API version 1.25, but the Docker server is version 1.24

After this change;

DOCKER_API_VERSION=1.24 docker run -d --stop-timeout=30 busybox top
"--stop-timeout" requires API version 1.25, but the Docker daemon is version 1.24

echo -e "FROM busybox\nRUN echo foo > bar" | DOCKER_API_VERSION=1.24 docker build --squash -
"--squash" requires API version 1.25, but the Docker daemon is version 1.24

echo -e "FROM busybox\nRUN echo foo > bar" | docker build --squash -
"--squash" is only supported on a Docker daemon with experimental features enabled

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

Sebastiaan van Stijn authored on 2017/01/16 23:35:27
Showing 2 changed files
... ...
@@ -229,7 +229,7 @@ func IsErrPluginPermissionDenied(err error) bool {
229 229
 // if less than the current supported version
230 230
 func (cli *Client) NewVersionError(APIrequired, feature string) error {
231 231
 	if versions.LessThan(cli.version, APIrequired) {
232
-		return fmt.Errorf("%q requires API version %s, but the Docker server is version %s", feature, APIrequired, cli.version)
232
+		return fmt.Errorf("%q requires API version %s, but the Docker daemon API version is %s", feature, APIrequired, cli.version)
233 233
 	}
234 234
 	return nil
235 235
 }
... ...
@@ -17,6 +17,7 @@ import (
17 17
 	"github.com/docker/docker/pkg/term"
18 18
 	"github.com/spf13/cobra"
19 19
 	"github.com/spf13/pflag"
20
+	"strings"
20 21
 )
21 22
 
22 23
 func newDockerCommand(dockerCli *command.DockerCli) *cobra.Command {
... ...
@@ -144,7 +145,7 @@ func hideUnsupportedFeatures(cmd *cobra.Command, clientVersion string, hasExperi
144 144
 		}
145 145
 
146 146
 		// hide flags not supported by the server
147
-		if flagVersion, ok := f.Annotations["version"]; ok && len(flagVersion) == 1 && versions.LessThan(clientVersion, flagVersion[0]) {
147
+		if !isFlagSupported(f, clientVersion) {
148 148
 			f.Hidden = true
149 149
 		}
150 150
 
... ...
@@ -168,13 +169,44 @@ func hideUnsupportedFeatures(cmd *cobra.Command, clientVersion string, hasExperi
168 168
 func isSupported(cmd *cobra.Command, clientVersion string, hasExperimental bool) error {
169 169
 	if !hasExperimental {
170 170
 		if _, ok := cmd.Tags["experimental"]; ok {
171
-			return errors.New("only supported with experimental daemon")
171
+			return errors.New("only supported on a Docker daemon with experimental features enabled")
172 172
 		}
173 173
 	}
174 174
 
175 175
 	if cmdVersion, ok := cmd.Tags["version"]; ok && versions.LessThan(clientVersion, cmdVersion) {
176
-		return fmt.Errorf("only supported with daemon version >= %s", cmdVersion)
176
+		return fmt.Errorf("requires API version %s, but the Docker daemon API version is %s", cmdVersion, clientVersion)
177
+	}
178
+
179
+	errs := []string{}
180
+
181
+	cmd.Flags().VisitAll(func(f *pflag.Flag) {
182
+		if f.Changed {
183
+			if !isFlagSupported(f, clientVersion) {
184
+				errs = append(errs, fmt.Sprintf("\"--%s\" requires API version %s, but the Docker daemon API version is %s", f.Name, getFlagVersion(f), clientVersion))
185
+				return
186
+			}
187
+			if _, ok := f.Annotations["experimental"]; ok && !hasExperimental {
188
+				errs = append(errs, fmt.Sprintf("\"--%s\" is only supported on a Docker daemon with experimental features enabled", f.Name))
189
+			}
190
+		}
191
+	})
192
+	if len(errs) > 0 {
193
+		return errors.New(strings.Join(errs, "\n"))
177 194
 	}
178 195
 
179 196
 	return nil
180 197
 }
198
+
199
+func getFlagVersion(f *pflag.Flag) string {
200
+	if flagVersion, ok := f.Annotations["version"]; ok && len(flagVersion) == 1 {
201
+		return flagVersion[0]
202
+	}
203
+	return ""
204
+}
205
+
206
+func isFlagSupported(f *pflag.Flag, clientVersion string) bool {
207
+	if v := getFlagVersion(f); v != "" {
208
+		return versions.GreaterThanOrEqualTo(clientVersion, v)
209
+	}
210
+	return true
211
+}