Просмотр исходного кода

Merge pull request #10745 from jfrazelle/device-dir

Mounting a dir of devices like /dev/snd should mount all child devices
Andrea Luzzardi 10 лет назад
Родитель
Сommit
b9be50b578
2 измененных файлов с 72 добавлено и 6 удалено
  1. 45 6
      daemon/container.go
  2. 27 0
      integration-cli/docker_cli_run_unix_test.go

+ 45 - 6
daemon/container.go

@@ -215,6 +215,45 @@ func (container *Container) getRootResourcePath(path string) (string, error) {
 	return symlink.FollowSymlinkInScope(filepath.Join(container.root, cleanPath), container.root)
 }
 
+func getDevicesFromPath(deviceMapping runconfig.DeviceMapping) (devs []*configs.Device, err error) {
+	device, err := devices.DeviceFromPath(deviceMapping.PathOnHost, deviceMapping.CgroupPermissions)
+	// if there was no error, return the device
+	if err == nil {
+		device.Path = deviceMapping.PathInContainer
+		return append(devs, device), nil
+	}
+
+	// if the device is not a device node
+	// try to see if it's a directory holding many devices
+	if err == devices.ErrNotADevice {
+
+		// check if it is a directory
+		if src, e := os.Stat(deviceMapping.PathOnHost); e == nil && src.IsDir() {
+
+			// mount the internal devices recursively
+			filepath.Walk(deviceMapping.PathOnHost, func(dpath string, f os.FileInfo, e error) error {
+				childDevice, e := devices.DeviceFromPath(dpath, deviceMapping.CgroupPermissions)
+				if e != nil {
+					// ignore the device
+					return nil
+				}
+
+				// add the device to userSpecified devices
+				childDevice.Path = strings.Replace(dpath, deviceMapping.PathOnHost, deviceMapping.PathInContainer, 1)
+				devs = append(devs, childDevice)
+
+				return nil
+			})
+		}
+	}
+
+	if len(devs) > 0 {
+		return devs, nil
+	}
+
+	return devs, fmt.Errorf("error gathering device information while adding custom device %q: %s", deviceMapping.PathOnHost, err)
+}
+
 func populateCommand(c *Container, env []string) error {
 	en := &execdriver.Network{
 		Mtu:       c.daemon.config.Mtu,
@@ -267,14 +306,14 @@ func populateCommand(c *Container, env []string) error {
 	pid.HostPid = c.hostConfig.PidMode.IsHost()
 
 	// Build lists of devices allowed and created within the container.
-	userSpecifiedDevices := make([]*configs.Device, len(c.hostConfig.Devices))
-	for i, deviceMapping := range c.hostConfig.Devices {
-		device, err := devices.DeviceFromPath(deviceMapping.PathOnHost, deviceMapping.CgroupPermissions)
+	var userSpecifiedDevices []*configs.Device
+	for _, deviceMapping := range c.hostConfig.Devices {
+		devs, err := getDevicesFromPath(deviceMapping)
 		if err != nil {
-			return fmt.Errorf("error gathering device information while adding custom device %q: %s", deviceMapping.PathOnHost, err)
+			return err
 		}
-		device.Path = deviceMapping.PathInContainer
-		userSpecifiedDevices[i] = device
+
+		userSpecifiedDevices = append(userSpecifiedDevices, devs...)
 	}
 	allowedDevices := append(configs.DefaultAllowedDevices, userSpecifiedDevices...)
 

+ 27 - 0
integration-cli/docker_cli_run_unix_test.go

@@ -173,3 +173,30 @@ func TestRunContainerWithCgroupParentAbsPath(t *testing.T) {
 
 	logDone("run - cgroup parent with absolute cgroup path")
 }
+
+func TestRunDeviceDirectory(t *testing.T) {
+	defer deleteAllContainers()
+	cmd := exec.Command(dockerBinary, "run", "--device", "/dev/snd:/dev/snd", "busybox", "sh", "-c", "ls /dev/snd/")
+
+	out, _, err := runCommandWithOutput(cmd)
+	if err != nil {
+		t.Fatal(err, out)
+	}
+
+	if actual := strings.Trim(out, "\r\n"); !strings.Contains(out, "timer") {
+		t.Fatalf("expected output /dev/snd/timer, received %s", actual)
+	}
+
+	cmd = exec.Command(dockerBinary, "run", "--device", "/dev/snd:/dev/othersnd", "busybox", "sh", "-c", "ls /dev/othersnd/")
+
+	out, _, err = runCommandWithOutput(cmd)
+	if err != nil {
+		t.Fatal(err, out)
+	}
+
+	if actual := strings.Trim(out, "\r\n"); !strings.Contains(out, "seq") {
+		t.Fatalf("expected output /dev/othersnd/timer, received %s", actual)
+	}
+
+	logDone("run - test --device directory mounts all internal devices")
+}