| package container // import "github.com/docker/docker/integration/container" | |
| import ( | |
| "strings" | |
| "testing" | |
| containertypes "github.com/docker/docker/api/types/container" | |
| "github.com/docker/docker/integration/internal/container" | |
| "github.com/docker/docker/testutil" | |
| "gotest.tools/v3/assert" | |
| "gotest.tools/v3/skip" | |
| ) | |
| // TestWindowsDevices that Windows Devices are correctly propagated | |
| // via HostConfig.Devices through to the implementation in hcsshim. | |
| func TestWindowsDevices(t *testing.T) { | |
| skip.If(t, testEnv.DaemonInfo.OSType != "windows") | |
| ctx := setupTest(t) | |
| apiClient := testEnv.APIClient() | |
| testData := []struct { | |
| doc string | |
| devices []string | |
| isolation containertypes.Isolation | |
| expectedStartFailure bool | |
| expectedStartFailureMessage string | |
| expectedExitCode int | |
| expectedStdout string | |
| expectedStderr string | |
| }{ | |
| { | |
| doc: "process/no device mounted", | |
| isolation: containertypes.IsolationProcess, | |
| expectedExitCode: 1, | |
| }, | |
| { | |
| doc: "process/class/5B45201D-F2F2-4F3B-85BB-30FF1F953599 mounted", | |
| devices: []string{"class/5B45201D-F2F2-4F3B-85BB-30FF1F953599"}, | |
| isolation: containertypes.IsolationProcess, | |
| expectedStdout: "/Windows/System32/HostDriverStore/FileRepository", | |
| }, | |
| { | |
| doc: "process/class://5B45201D-F2F2-4F3B-85BB-30FF1F953599 mounted", | |
| devices: []string{"class://5B45201D-F2F2-4F3B-85BB-30FF1F953599"}, | |
| isolation: containertypes.IsolationProcess, | |
| expectedStdout: "/Windows/System32/HostDriverStore/FileRepository", | |
| }, | |
| { | |
| doc: "process/vpci-class-guid://5B45201D-F2F2-4F3B-85BB-30FF1F953599 mounted", | |
| devices: []string{"vpci-class-guid://5B45201D-F2F2-4F3B-85BB-30FF1F953599"}, | |
| isolation: containertypes.IsolationProcess, | |
| expectedStdout: "/Windows/System32/HostDriverStore/FileRepository", | |
| }, | |
| { | |
| doc: "hyperv/no device mounted", | |
| isolation: containertypes.IsolationHyperV, | |
| expectedExitCode: 1, | |
| }, | |
| { | |
| doc: "hyperv/class/5B45201D-F2F2-4F3B-85BB-30FF1F953599 mounted", | |
| devices: []string{"class/5B45201D-F2F2-4F3B-85BB-30FF1F953599"}, | |
| isolation: containertypes.IsolationHyperV, | |
| expectedStartFailure: !testEnv.RuntimeIsWindowsContainerd(), | |
| expectedStartFailureMessage: "device assignment is not supported for HyperV containers", | |
| expectedStdout: "/Windows/System32/HostDriverStore/FileRepository", | |
| }, | |
| { | |
| doc: "hyperv/class://5B45201D-F2F2-4F3B-85BB-30FF1F953599 mounted", | |
| devices: []string{"class://5B45201D-F2F2-4F3B-85BB-30FF1F953599"}, | |
| isolation: containertypes.IsolationHyperV, | |
| expectedStartFailure: !testEnv.RuntimeIsWindowsContainerd(), | |
| expectedStartFailureMessage: "device assignment is not supported for HyperV containers", | |
| expectedStdout: "/Windows/System32/HostDriverStore/FileRepository", | |
| }, | |
| { | |
| doc: "hyperv/vpci-class-guid://5B45201D-F2F2-4F3B-85BB-30FF1F953599 mounted", | |
| devices: []string{"vpci-class-guid://5B45201D-F2F2-4F3B-85BB-30FF1F953599"}, | |
| isolation: containertypes.IsolationHyperV, | |
| expectedStartFailure: !testEnv.RuntimeIsWindowsContainerd(), | |
| expectedStartFailureMessage: "device assignment is not supported for HyperV containers", | |
| expectedStdout: "/Windows/System32/HostDriverStore/FileRepository", | |
| }, | |
| } | |
| for _, d := range testData { | |
| d := d | |
| t.Run(d.doc, func(t *testing.T) { | |
| t.Parallel() | |
| ctx := testutil.StartSpan(ctx, t) | |
| deviceOptions := []func(*container.TestContainerConfig){container.WithIsolation(d.isolation)} | |
| for _, deviceName := range d.devices { | |
| deviceOptions = append(deviceOptions, container.WithWindowsDevice(deviceName)) | |
| } | |
| id := container.Create(ctx, t, apiClient, deviceOptions...) | |
| // Hyper-V isolation is failing even with no actual devices added. | |
| // TODO: Once https://github.com/moby/moby/issues/43395 is resolved, | |
| // remove this skip.If and validate the expected behaviour under Hyper-V. | |
| skip.If(t, d.isolation == containertypes.IsolationHyperV && !d.expectedStartFailure, "FIXME. HyperV isolation setup is probably incorrect in the test") | |
| err := apiClient.ContainerStart(ctx, id, containertypes.StartOptions{}) | |
| if d.expectedStartFailure { | |
| assert.ErrorContains(t, err, d.expectedStartFailureMessage) | |
| return | |
| } | |
| assert.NilError(t, err) | |
| // /Windows/System32/HostDriverStore is mounted from the host when class GUID 5B45201D-F2F2-4F3B-85BB-30FF1F953599 | |
| // is mounted. See `C:\windows\System32\containers\devices.def` on a Windows host for (slightly more) details. | |
| res, err := container.Exec(ctx, apiClient, id, []string{ | |
| "sh", "-c", | |
| "ls -d /Windows/System32/HostDriverStore/* | grep /Windows/System32/HostDriverStore/FileRepository", | |
| }) | |
| assert.NilError(t, err) | |
| assert.Equal(t, d.expectedExitCode, res.ExitCode) | |
| if d.expectedExitCode == 0 { | |
| assert.Equal(t, d.expectedStdout, strings.TrimSpace(res.Stdout())) | |
| assert.Equal(t, d.expectedStderr, strings.TrimSpace(res.Stderr())) | |
| } | |
| }) | |
| } | |
| } |