devices_windows_test.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. package container // import "github.com/docker/docker/integration/container"
  2. import (
  3. "context"
  4. "strings"
  5. "testing"
  6. "time"
  7. "github.com/docker/docker/api/types"
  8. containertypes "github.com/docker/docker/api/types/container"
  9. "github.com/docker/docker/integration/internal/container"
  10. "gotest.tools/v3/assert"
  11. "gotest.tools/v3/poll"
  12. "gotest.tools/v3/skip"
  13. )
  14. // TestWindowsDevices that Windows Devices are correctly propagated
  15. // via HostConfig.Devices through to the implementation in hcsshim.
  16. func TestWindowsDevices(t *testing.T) {
  17. skip.If(t, testEnv.DaemonInfo.OSType != "windows")
  18. t.Cleanup(setupTest(t))
  19. apiClient := testEnv.APIClient()
  20. ctx := context.Background()
  21. testData := []struct {
  22. doc string
  23. devices []string
  24. isolation containertypes.Isolation
  25. expectedStartFailure bool
  26. expectedStartFailureMessage string
  27. expectedExitCode int
  28. expectedStdout string
  29. expectedStderr string
  30. }{
  31. {
  32. doc: "process/no device mounted",
  33. isolation: containertypes.IsolationProcess,
  34. expectedExitCode: 1,
  35. },
  36. {
  37. doc: "process/class/5B45201D-F2F2-4F3B-85BB-30FF1F953599 mounted",
  38. devices: []string{"class/5B45201D-F2F2-4F3B-85BB-30FF1F953599"},
  39. isolation: containertypes.IsolationProcess,
  40. expectedStdout: "/Windows/System32/HostDriverStore/FileRepository",
  41. },
  42. {
  43. doc: "process/class://5B45201D-F2F2-4F3B-85BB-30FF1F953599 mounted",
  44. devices: []string{"class://5B45201D-F2F2-4F3B-85BB-30FF1F953599"},
  45. isolation: containertypes.IsolationProcess,
  46. expectedStdout: "/Windows/System32/HostDriverStore/FileRepository",
  47. },
  48. {
  49. doc: "process/vpci-class-guid://5B45201D-F2F2-4F3B-85BB-30FF1F953599 mounted",
  50. devices: []string{"vpci-class-guid://5B45201D-F2F2-4F3B-85BB-30FF1F953599"},
  51. isolation: containertypes.IsolationProcess,
  52. expectedStdout: "/Windows/System32/HostDriverStore/FileRepository",
  53. },
  54. {
  55. doc: "hyperv/no device mounted",
  56. isolation: containertypes.IsolationHyperV,
  57. expectedExitCode: 1,
  58. },
  59. {
  60. doc: "hyperv/class/5B45201D-F2F2-4F3B-85BB-30FF1F953599 mounted",
  61. devices: []string{"class/5B45201D-F2F2-4F3B-85BB-30FF1F953599"},
  62. isolation: containertypes.IsolationHyperV,
  63. expectedStartFailure: !testEnv.RuntimeIsWindowsContainerd(),
  64. expectedStartFailureMessage: "device assignment is not supported for HyperV containers",
  65. expectedStdout: "/Windows/System32/HostDriverStore/FileRepository",
  66. },
  67. {
  68. doc: "hyperv/class://5B45201D-F2F2-4F3B-85BB-30FF1F953599 mounted",
  69. devices: []string{"class://5B45201D-F2F2-4F3B-85BB-30FF1F953599"},
  70. isolation: containertypes.IsolationHyperV,
  71. expectedStartFailure: !testEnv.RuntimeIsWindowsContainerd(),
  72. expectedStartFailureMessage: "device assignment is not supported for HyperV containers",
  73. expectedStdout: "/Windows/System32/HostDriverStore/FileRepository",
  74. },
  75. {
  76. doc: "hyperv/vpci-class-guid://5B45201D-F2F2-4F3B-85BB-30FF1F953599 mounted",
  77. devices: []string{"vpci-class-guid://5B45201D-F2F2-4F3B-85BB-30FF1F953599"},
  78. isolation: containertypes.IsolationHyperV,
  79. expectedStartFailure: !testEnv.RuntimeIsWindowsContainerd(),
  80. expectedStartFailureMessage: "device assignment is not supported for HyperV containers",
  81. expectedStdout: "/Windows/System32/HostDriverStore/FileRepository",
  82. },
  83. }
  84. for _, d := range testData {
  85. d := d
  86. t.Run(d.doc, func(t *testing.T) {
  87. t.Parallel()
  88. deviceOptions := []func(*container.TestContainerConfig){container.WithIsolation(d.isolation)}
  89. for _, deviceName := range d.devices {
  90. deviceOptions = append(deviceOptions, container.WithWindowsDevice(deviceName))
  91. }
  92. id := container.Create(ctx, t, apiClient, deviceOptions...)
  93. // Hyper-V isolation is failing even with no actual devices added.
  94. // TODO: Once https://github.com/moby/moby/issues/43395 is resolved,
  95. // remove this skip.If and validate the expected behaviour under Hyper-V.
  96. skip.If(t, d.isolation == containertypes.IsolationHyperV && !d.expectedStartFailure, "FIXME. HyperV isolation setup is probably incorrect in the test")
  97. err := apiClient.ContainerStart(ctx, id, types.ContainerStartOptions{})
  98. if d.expectedStartFailure {
  99. assert.ErrorContains(t, err, d.expectedStartFailureMessage)
  100. return
  101. }
  102. assert.NilError(t, err)
  103. poll.WaitOn(t, container.IsInState(ctx, apiClient, id, "running"), poll.WithDelay(100*time.Millisecond))
  104. // /Windows/System32/HostDriverStore is mounted from the host when class GUID 5B45201D-F2F2-4F3B-85BB-30FF1F953599
  105. // is mounted. See `C:\windows\System32\containers\devices.def` on a Windows host for (slightly more) details.
  106. res, err := container.Exec(ctx, apiClient, id, []string{
  107. "sh", "-c",
  108. "ls -d /Windows/System32/HostDriverStore/* | grep /Windows/System32/HostDriverStore/FileRepository",
  109. })
  110. assert.NilError(t, err)
  111. assert.Equal(t, d.expectedExitCode, res.ExitCode)
  112. if d.expectedExitCode == 0 {
  113. assert.Equal(t, d.expectedStdout, strings.TrimSpace(res.Stdout()))
  114. assert.Equal(t, d.expectedStderr, strings.TrimSpace(res.Stderr()))
  115. }
  116. })
  117. }
  118. }