Browse code

Hide command options that are related to Windows

Signed-off-by: Boaz Shuster <ripcurld.github@gmail.com>

Boaz Shuster authored on 2017/02/07 21:52:20
Showing 6 changed files
... ...
@@ -43,6 +43,7 @@ func (v VersionMiddleware) WrapHandler(handler func(ctx context.Context, w http.
43 43
 		header := fmt.Sprintf("Docker/%s (%s)", v.serverVersion, runtime.GOOS)
44 44
 		w.Header().Set("Server", header)
45 45
 		w.Header().Set("API-Version", v.defaultVersion)
46
+		w.Header().Set("OSType", runtime.GOOS)
46 47
 		ctx = context.WithValue(ctx, "api-version", apiVersion)
47 48
 		return handler(ctx, w, r, vars)
48 49
 	}
... ...
@@ -97,6 +97,7 @@ type ContainerStats struct {
97 97
 // GET "/_ping"
98 98
 type Ping struct {
99 99
 	APIVersion   string
100
+	OSType       string
100 101
 	Experimental bool
101 102
 }
102 103
 
... ...
@@ -51,6 +51,7 @@ type DockerCli struct {
51 51
 	keyFile         string
52 52
 	client          client.APIClient
53 53
 	hasExperimental bool
54
+	osType          string
54 55
 	defaultVersion  string
55 56
 }
56 57
 
... ...
@@ -59,6 +60,11 @@ func (cli *DockerCli) HasExperimental() bool {
59 59
 	return cli.hasExperimental
60 60
 }
61 61
 
62
+// OSType returns the operating system the daemon is running on.
63
+func (cli *DockerCli) OSType() string {
64
+	return cli.osType
65
+}
66
+
62 67
 // DefaultVersion returns api.defaultVersion of DOCKER_API_VERSION if specified.
63 68
 func (cli *DockerCli) DefaultVersion() string {
64 69
 	return cli.defaultVersion
... ...
@@ -166,6 +172,7 @@ func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions) error {
166 166
 
167 167
 	if ping, err := cli.client.Ping(context.Background()); err == nil {
168 168
 		cli.hasExperimental = ping.Experimental
169
+		cli.osType = ping.OSType
169 170
 
170 171
 		// since the new header was added in 1.25, assume server is 1.24 if header is not present.
171 172
 		if ping.APIVersion == "" {
... ...
@@ -189,6 +189,7 @@ func addFlags(flags *pflag.FlagSet) *containerOptions {
189 189
 	flags.Var(&copts.securityOpt, "security-opt", "Security Options")
190 190
 	flags.StringVar(&copts.usernsMode, "userns", "", "User namespace to use")
191 191
 	flags.StringVar(&copts.credentialSpec, "credentialspec", "", "Credential spec for managed service account (Windows only)")
192
+	flags.SetAnnotation("credentialspec", "ostype", []string{"windows"})
192 193
 
193 194
 	// Network and port publishing flag
194 195
 	flags.Var(&copts.extraHosts, "add-host", "Add a custom host-to-IP mapping (host:ip)")
... ...
@@ -239,7 +240,9 @@ func addFlags(flags *pflag.FlagSet) *containerOptions {
239 239
 	flags.StringVar(&copts.cpusetCpus, "cpuset-cpus", "", "CPUs in which to allow execution (0-3, 0,1)")
240 240
 	flags.StringVar(&copts.cpusetMems, "cpuset-mems", "", "MEMs in which to allow execution (0-3, 0,1)")
241 241
 	flags.Int64Var(&copts.cpuCount, "cpu-count", 0, "CPU count (Windows only)")
242
+	flags.SetAnnotation("cpu-count", "ostype", []string{"windows"})
242 243
 	flags.Int64Var(&copts.cpuPercent, "cpu-percent", 0, "CPU percent (Windows only)")
244
+	flags.SetAnnotation("cpu-percent", "ostype", []string{"windows"})
243 245
 	flags.Int64Var(&copts.cpuPeriod, "cpu-period", 0, "Limit CPU CFS (Completely Fair Scheduler) period")
244 246
 	flags.Int64Var(&copts.cpuQuota, "cpu-quota", 0, "Limit CPU CFS (Completely Fair Scheduler) quota")
245 247
 	flags.Int64Var(&copts.cpuRealtimePeriod, "cpu-rt-period", 0, "Limit CPU real-time period in microseconds")
... ...
@@ -254,7 +257,9 @@ func addFlags(flags *pflag.FlagSet) *containerOptions {
254 254
 	flags.Var(&copts.deviceWriteBps, "device-write-bps", "Limit write rate (bytes per second) to a device")
255 255
 	flags.Var(&copts.deviceWriteIOps, "device-write-iops", "Limit write rate (IO per second) to a device")
256 256
 	flags.Var(&copts.ioMaxBandwidth, "io-maxbandwidth", "Maximum IO bandwidth limit for the system drive (Windows only)")
257
+	flags.SetAnnotation("io-maxbandwidth", "ostype", []string{"windows"})
257 258
 	flags.Uint64Var(&copts.ioMaxIOps, "io-maxiops", 0, "Maximum IOps limit for the system drive (Windows only)")
259
+	flags.SetAnnotation("io-maxiops", "ostype", []string{"windows"})
258 260
 	flags.Var(&copts.kernelMemory, "kernel-memory", "Kernel memory limit")
259 261
 	flags.VarP(&copts.memory, "memory", "m", "Memory limit")
260 262
 	flags.Var(&copts.memoryReservation, "memory-reservation", "Memory soft limit")
... ...
@@ -7,7 +7,7 @@ import (
7 7
 	"golang.org/x/net/context"
8 8
 )
9 9
 
10
-// Ping pings the server and returns the value of the "Docker-Experimental" & "API-Version" headers
10
+// Ping pings the server and returns the value of the "Docker-Experimental", "OS-Type" & "API-Version" headers
11 11
 func (cli *Client) Ping(ctx context.Context) (types.Ping, error) {
12 12
 	var ping types.Ping
13 13
 	req, err := cli.buildRequest("GET", fmt.Sprintf("%s/_ping", cli.basePath), nil, nil)
... ...
@@ -26,5 +26,7 @@ func (cli *Client) Ping(ctx context.Context) (types.Ping, error) {
26 26
 		ping.Experimental = true
27 27
 	}
28 28
 
29
+	ping.OSType = serverResp.header.Get("OSType")
30
+
29 31
 	return ping, nil
30 32
 }
... ...
@@ -49,7 +49,7 @@ func newDockerCommand(dockerCli *command.DockerCli) *cobra.Command {
49 49
 			if err := dockerCli.Initialize(opts); err != nil {
50 50
 				return err
51 51
 			}
52
-			return isSupported(cmd, dockerCli.Client().ClientVersion(), dockerCli.HasExperimental())
52
+			return isSupported(cmd, dockerCli.Client().ClientVersion(), dockerCli.OSType(), dockerCli.HasExperimental())
53 53
 		},
54 54
 	}
55 55
 	cli.SetupRootCommand(cmd)
... ...
@@ -80,7 +80,7 @@ func setFlagErrorFunc(dockerCli *command.DockerCli, cmd *cobra.Command, flags *p
80 80
 	flagErrorFunc := cmd.FlagErrorFunc()
81 81
 	cmd.SetFlagErrorFunc(func(cmd *cobra.Command, err error) error {
82 82
 		initializeDockerCli(dockerCli, flags, opts)
83
-		if err := isSupported(cmd, dockerCli.Client().ClientVersion(), dockerCli.HasExperimental()); err != nil {
83
+		if err := isSupported(cmd, dockerCli.Client().ClientVersion(), dockerCli.OSType(), dockerCli.HasExperimental()); err != nil {
84 84
 			return err
85 85
 		}
86 86
 		return flagErrorFunc(cmd, err)
... ...
@@ -90,12 +90,12 @@ func setFlagErrorFunc(dockerCli *command.DockerCli, cmd *cobra.Command, flags *p
90 90
 func setHelpFunc(dockerCli *command.DockerCli, cmd *cobra.Command, flags *pflag.FlagSet, opts *cliflags.ClientOptions) {
91 91
 	cmd.SetHelpFunc(func(ccmd *cobra.Command, args []string) {
92 92
 		initializeDockerCli(dockerCli, flags, opts)
93
-		if err := isSupported(ccmd, dockerCli.Client().ClientVersion(), dockerCli.HasExperimental()); err != nil {
93
+		if err := isSupported(ccmd, dockerCli.Client().ClientVersion(), dockerCli.OSType(), dockerCli.HasExperimental()); err != nil {
94 94
 			ccmd.Println(err)
95 95
 			return
96 96
 		}
97 97
 
98
-		hideUnsupportedFeatures(ccmd, dockerCli.Client().ClientVersion(), dockerCli.HasExperimental())
98
+		hideUnsupportedFeatures(ccmd, dockerCli.Client().ClientVersion(), dockerCli.OSType(), dockerCli.HasExperimental())
99 99
 
100 100
 		if err := ccmd.Help(); err != nil {
101 101
 			ccmd.Println(err)
... ...
@@ -122,7 +122,7 @@ func setValidateArgs(dockerCli *command.DockerCli, cmd *cobra.Command, flags *pf
122 122
 		cmdArgs := ccmd.Args
123 123
 		ccmd.Args = func(cmd *cobra.Command, args []string) error {
124 124
 			initializeDockerCli(dockerCli, flags, opts)
125
-			if err := isSupported(cmd, dockerCli.Client().ClientVersion(), dockerCli.HasExperimental()); err != nil {
125
+			if err := isSupported(cmd, dockerCli.Client().ClientVersion(), dockerCli.OSType(), dockerCli.HasExperimental()); err != nil {
126 126
 				return err
127 127
 			}
128 128
 			return cmdArgs(cmd, args)
... ...
@@ -198,7 +198,7 @@ func dockerPreRun(opts *cliflags.ClientOptions) {
198 198
 	}
199 199
 }
200 200
 
201
-func hideUnsupportedFeatures(cmd *cobra.Command, clientVersion string, hasExperimental bool) {
201
+func hideUnsupportedFeatures(cmd *cobra.Command, clientVersion, osType string, hasExperimental bool) {
202 202
 	cmd.Flags().VisitAll(func(f *pflag.Flag) {
203 203
 		// hide experimental flags
204 204
 		if !hasExperimental {
... ...
@@ -208,10 +208,9 @@ func hideUnsupportedFeatures(cmd *cobra.Command, clientVersion string, hasExperi
208 208
 		}
209 209
 
210 210
 		// hide flags not supported by the server
211
-		if !isFlagSupported(f, clientVersion) {
211
+		if !isOSTypeSupported(f, osType) || !isVersionSupported(f, clientVersion) {
212 212
 			f.Hidden = true
213 213
 		}
214
-
215 214
 	})
216 215
 
217 216
 	for _, subcmd := range cmd.Commands() {
... ...
@@ -229,7 +228,7 @@ func hideUnsupportedFeatures(cmd *cobra.Command, clientVersion string, hasExperi
229 229
 	}
230 230
 }
231 231
 
232
-func isSupported(cmd *cobra.Command, clientVersion string, hasExperimental bool) error {
232
+func isSupported(cmd *cobra.Command, clientVersion, osType string, hasExperimental bool) error {
233 233
 	// We check recursively so that, e.g., `docker stack ls` will return the same output as `docker stack`
234 234
 	if !hasExperimental {
235 235
 		for curr := cmd; curr != nil; curr = curr.Parent() {
... ...
@@ -247,8 +246,12 @@ func isSupported(cmd *cobra.Command, clientVersion string, hasExperimental bool)
247 247
 
248 248
 	cmd.Flags().VisitAll(func(f *pflag.Flag) {
249 249
 		if f.Changed {
250
-			if !isFlagSupported(f, clientVersion) {
251
-				errs = append(errs, fmt.Sprintf("\"--%s\" requires API version %s, but the Docker daemon API version is %s", f.Name, getFlagVersion(f), clientVersion))
250
+			if !isVersionSupported(f, clientVersion) {
251
+				errs = append(errs, fmt.Sprintf("\"--%s\" requires API version %s, but the Docker daemon API version is %s", f.Name, getFlagAnnotation(f, "version"), clientVersion))
252
+				return
253
+			}
254
+			if !isOSTypeSupported(f, osType) {
255
+				errs = append(errs, fmt.Sprintf("\"--%s\" requires the Docker daemon to run on %s, but the Docker daemon is running on %s", f.Name, getFlagAnnotation(f, "ostype"), osType))
252 256
 				return
253 257
 			}
254 258
 			if _, ok := f.Annotations["experimental"]; ok && !hasExperimental {
... ...
@@ -263,20 +266,27 @@ func isSupported(cmd *cobra.Command, clientVersion string, hasExperimental bool)
263 263
 	return nil
264 264
 }
265 265
 
266
-func getFlagVersion(f *pflag.Flag) string {
267
-	if flagVersion, ok := f.Annotations["version"]; ok && len(flagVersion) == 1 {
268
-		return flagVersion[0]
266
+func getFlagAnnotation(f *pflag.Flag, annotation string) string {
267
+	if value, ok := f.Annotations[annotation]; ok && len(value) == 1 {
268
+		return value[0]
269 269
 	}
270 270
 	return ""
271 271
 }
272 272
 
273
-func isFlagSupported(f *pflag.Flag, clientVersion string) bool {
274
-	if v := getFlagVersion(f); v != "" {
273
+func isVersionSupported(f *pflag.Flag, clientVersion string) bool {
274
+	if v := getFlagAnnotation(f, "version"); v != "" {
275 275
 		return versions.GreaterThanOrEqualTo(clientVersion, v)
276 276
 	}
277 277
 	return true
278 278
 }
279 279
 
280
+func isOSTypeSupported(f *pflag.Flag, osType string) bool {
281
+	if v := getFlagAnnotation(f, "ostype"); v != "" && osType != "" {
282
+		return osType == v
283
+	}
284
+	return true
285
+}
286
+
280 287
 // hasTags return true if any of the command's parents has tags
281 288
 func hasTags(cmd *cobra.Command) bool {
282 289
 	for curr := cmd; curr != nil; curr = curr.Parent() {