Visitar URL original
Merge pull request #1606 from jhowardmsft/device · docker/cli@afde31d · GitHub
Skip to content

Commit afde31d

Browse files
Merge pull request #1606 from jhowardmsft/device
Add --device support for Windows
2 parents 896ff57 + 593acf0 commit afde31d

4 files changed

Lines changed: 58 additions & 16 deletions

File tree

‎cli/command/container/create.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func runCreate(dockerCli command.Cli, flags *pflag.FlagSet, options *createOptio
7272
}
7373
}
7474
copts.env = *opts.NewListOptsRef(&newEnv, nil)
75-
containerConfig, err := parse(flags, copts)
75+
containerConfig, err := parse(flags, copts, dockerCli.ServerInfo().OSType)
7676
if err != nil {
7777
reportError(dockerCli.Err(), "create", err.Error(), true)
7878
return cli.StatusError{StatusCode: 125}

‎cli/command/container/opts.go‎

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ func addFlags(flags *pflag.FlagSet) *containerOptions {
141141
deviceReadIOps: opts.NewThrottledeviceOpt(opts.ValidateThrottleIOpsDevice),
142142
deviceWriteBps: opts.NewThrottledeviceOpt(opts.ValidateThrottleBpsDevice),
143143
deviceWriteIOps: opts.NewThrottledeviceOpt(opts.ValidateThrottleIOpsDevice),
144-
devices: opts.NewListOpts(validateDevice),
144+
devices: opts.NewListOpts(nil), // devices can only be validated after we know the server OS
145145
env: opts.NewListOpts(opts.ValidateEnv),
146146
envFile: opts.NewListOpts(nil),
147147
expose: opts.NewListOpts(nil),
@@ -299,7 +299,7 @@ type containerConfig struct {
299299
// a HostConfig and returns them with the specified command.
300300
// If the specified args are not valid, it will return an error.
301301
// nolint: gocyclo
302-
func parse(flags *pflag.FlagSet, copts *containerOptions) (*containerConfig, error) {
302+
func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*containerConfig, error) {
303303
var (
304304
attachStdin = copts.attach.Get("stdin")
305305
attachStdout = copts.attach.Get("stdout")
@@ -417,10 +417,22 @@ func parse(flags *pflag.FlagSet, copts *containerOptions) (*containerConfig, err
417417
}
418418
}
419419

420-
// parse device mappings
420+
// validate and parse device mappings. Note we do late validation of the
421+
// device path (as opposed to during flag parsing), as at the time we are
422+
// parsing flags, we haven't yet sent a _ping to the daemon to determine
423+
// what operating system it is.
421424
deviceMappings := []container.DeviceMapping{}
422425
for _, device := range copts.devices.GetAll() {
423-
deviceMapping, err := parseDevice(device)
426+
var (
427+
validated string
428+
deviceMapping container.DeviceMapping
429+
err error
430+
)
431+
validated, err = validateDevice(device, serverOS)
432+
if err != nil {
433+
return nil, err
434+
}
435+
deviceMapping, err = parseDevice(validated, serverOS)
424436
if err != nil {
425437
return nil, err
426438
}
@@ -747,7 +759,19 @@ func parseStorageOpts(storageOpts []string) (map[string]string, error) {
747759
}
748760

749761
// parseDevice parses a device mapping string to a container.DeviceMapping struct
750-
func parseDevice(device string) (container.DeviceMapping, error) {
762+
func parseDevice(device, serverOS string) (container.DeviceMapping, error) {
763+
switch serverOS {
764+
case "linux":
765+
return parseLinuxDevice(device)
766+
case "windows":
767+
return parseWindowsDevice(device)
768+
}
769+
return container.DeviceMapping{}, errors.Errorf("unknown server OS: %s", serverOS)
770+
}
771+
772+
// parseLinuxDevice parses a device mapping string to a container.DeviceMapping struct
773+
// knowing that the target is a Linux daemon
774+
func parseLinuxDevice(device string) (container.DeviceMapping, error) {
751775
src := ""
752776
dst := ""
753777
permissions := "rwm"
@@ -781,6 +805,12 @@ func parseDevice(device string) (container.DeviceMapping, error) {
781805
return deviceMapping, nil
782806
}
783807

808+
// parseWindowsDevice parses a device mapping string to a container.DeviceMapping struct
809+
// knowing that the target is a Windows daemon
810+
func parseWindowsDevice(device string) (container.DeviceMapping, error) {
811+
return container.DeviceMapping{PathOnHost: device}, nil
812+
}
813+
784814
// validateDeviceCgroupRule validates a device cgroup rule string format
785815
// It will make sure 'val' is in the form:
786816
// 'type major:minor mode'
@@ -813,14 +843,23 @@ func validDeviceMode(mode string) bool {
813843
}
814844

815845
// validateDevice validates a path for devices
846+
func validateDevice(val string, serverOS string) (string, error) {
847+
switch serverOS {
848+
case "linux":
849+
return validateLinuxPath(val, validDeviceMode)
850+
case "windows":
851+
// Windows does validation entirely server-side
852+
return val, nil
853+
}
854+
return "", errors.Errorf("unknown server OS: %s", serverOS)
855+
}
856+
857+
// validateLinuxPath is the implementation of validateDevice knowing that the
858+
// target server operating system is a Linux daemon.
816859
// It will make sure 'val' is in the form:
817860
// [host-dir:]container-path[:mode]
818861
// It also validates the device mode.
819-
func validateDevice(val string) (string, error) {
820-
return validatePath(val, validDeviceMode)
821-
}
822-
823-
func validatePath(val string, validator func(string) bool) (string, error) {
862+
func validateLinuxPath(val string, validator func(string) bool) (string, error) {
824863
var containerPath string
825864
var mode string
826865

‎cli/command/container/opts_test.go‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/spf13/pflag"
1717
"gotest.tools/assert"
1818
is "gotest.tools/assert/cmp"
19+
"gotest.tools/skip"
1920
)
2021

2122
func TestValidateAttach(t *testing.T) {
@@ -48,7 +49,7 @@ func parseRun(args []string) (*container.Config, *container.HostConfig, *network
4849
return nil, nil, nil, err
4950
}
5051
// TODO: fix tests to accept ContainerConfig
51-
containerConfig, err := parse(flags, copts)
52+
containerConfig, err := parse(flags, copts, runtime.GOOS)
5253
if err != nil {
5354
return nil, nil, nil, err
5455
}
@@ -351,6 +352,7 @@ func TestParseWithExpose(t *testing.T) {
351352
}
352353

353354
func TestParseDevice(t *testing.T) {
355+
skip.If(t, runtime.GOOS == "windows") // Windows validates server-side
354356
valids := map[string]container.DeviceMapping{
355357
"/dev/snd": {
356358
PathOnHost: "/dev/snd",
@@ -393,7 +395,7 @@ func TestParseModes(t *testing.T) {
393395
flags, copts := setupRunFlags()
394396
args := []string{"--pid=container:", "img", "cmd"}
395397
assert.NilError(t, flags.Parse(args))
396-
_, err := parse(flags, copts)
398+
_, err := parse(flags, copts, runtime.GOOS)
397399
assert.ErrorContains(t, err, "--pid: invalid PID mode")
398400

399401
// pid ok
@@ -615,6 +617,7 @@ func TestParseEntryPoint(t *testing.T) {
615617
}
616618

617619
func TestValidateDevice(t *testing.T) {
620+
skip.If(t, runtime.GOOS == "windows") // Windows validates server-side
618621
valid := []string{
619622
"/home",
620623
"/home:/home",
@@ -649,13 +652,13 @@ func TestValidateDevice(t *testing.T) {
649652
}
650653

651654
for _, path := range valid {
652-
if _, err := validateDevice(path); err != nil {
655+
if _, err := validateDevice(path, runtime.GOOS); err != nil {
653656
t.Fatalf("ValidateDevice(`%q`) should succeed: error %q", path, err)
654657
}
655658
}
656659

657660
for path, expectedError := range invalid {
658-
if _, err := validateDevice(path); err == nil {
661+
if _, err := validateDevice(path, runtime.GOOS); err == nil {
659662
t.Fatalf("ValidateDevice(`%q`) should have failed validation", path)
660663
} else {
661664
if err.Error() != expectedError {

‎cli/command/container/run.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func runRun(dockerCli command.Cli, flags *pflag.FlagSet, ropts *runOptions, copt
7878
}
7979
}
8080
copts.env = *opts.NewListOptsRef(&newEnv, nil)
81-
containerConfig, err := parse(flags, copts)
81+
containerConfig, err := parse(flags, copts, dockerCli.ServerInfo().OSType)
8282
// just in case the parse does not exit
8383
if err != nil {
8484
reportError(dockerCli.Err(), "run", err.Error(), true)

0 commit comments

Comments
 (0)