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