create_test.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. package container // import "github.com/docker/docker/integration/container"
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "strconv"
  7. "testing"
  8. "time"
  9. "github.com/docker/docker/api/types"
  10. "github.com/docker/docker/api/types/container"
  11. "github.com/docker/docker/api/types/network"
  12. ctr "github.com/docker/docker/integration/internal/container"
  13. "github.com/docker/docker/internal/test/request"
  14. "github.com/docker/docker/oci"
  15. "github.com/gotestyourself/gotestyourself/assert"
  16. is "github.com/gotestyourself/gotestyourself/assert/cmp"
  17. "github.com/gotestyourself/gotestyourself/poll"
  18. "github.com/gotestyourself/gotestyourself/skip"
  19. )
  20. func TestCreateFailsWhenIdentifierDoesNotExist(t *testing.T) {
  21. defer setupTest(t)()
  22. client := request.NewAPIClient(t)
  23. testCases := []struct {
  24. doc string
  25. image string
  26. expectedError string
  27. }{
  28. {
  29. doc: "image and tag",
  30. image: "test456:v1",
  31. expectedError: "No such image: test456:v1",
  32. },
  33. {
  34. doc: "image no tag",
  35. image: "test456",
  36. expectedError: "No such image: test456",
  37. },
  38. {
  39. doc: "digest",
  40. image: "sha256:0cb40641836c461bc97c793971d84d758371ed682042457523e4ae701efeaaaa",
  41. expectedError: "No such image: sha256:0cb40641836c461bc97c793971d84d758371ed682042457523e4ae701efeaaaa",
  42. },
  43. }
  44. for _, tc := range testCases {
  45. tc := tc
  46. t.Run(tc.doc, func(t *testing.T) {
  47. t.Parallel()
  48. _, err := client.ContainerCreate(context.Background(),
  49. &container.Config{Image: tc.image},
  50. &container.HostConfig{},
  51. &network.NetworkingConfig{},
  52. "",
  53. )
  54. assert.Check(t, is.ErrorContains(err, tc.expectedError))
  55. })
  56. }
  57. }
  58. func TestCreateWithInvalidEnv(t *testing.T) {
  59. defer setupTest(t)()
  60. client := request.NewAPIClient(t)
  61. testCases := []struct {
  62. env string
  63. expectedError string
  64. }{
  65. {
  66. env: "",
  67. expectedError: "invalid environment variable:",
  68. },
  69. {
  70. env: "=",
  71. expectedError: "invalid environment variable: =",
  72. },
  73. {
  74. env: "=foo",
  75. expectedError: "invalid environment variable: =foo",
  76. },
  77. }
  78. for index, tc := range testCases {
  79. tc := tc
  80. t.Run(strconv.Itoa(index), func(t *testing.T) {
  81. t.Parallel()
  82. _, err := client.ContainerCreate(context.Background(),
  83. &container.Config{
  84. Image: "busybox",
  85. Env: []string{tc.env},
  86. },
  87. &container.HostConfig{},
  88. &network.NetworkingConfig{},
  89. "",
  90. )
  91. assert.Check(t, is.ErrorContains(err, tc.expectedError))
  92. })
  93. }
  94. }
  95. // Test case for #30166 (target was not validated)
  96. func TestCreateTmpfsMountsTarget(t *testing.T) {
  97. skip.If(t, testEnv.DaemonInfo.OSType != "linux")
  98. defer setupTest(t)()
  99. client := request.NewAPIClient(t)
  100. testCases := []struct {
  101. target string
  102. expectedError string
  103. }{
  104. {
  105. target: ".",
  106. expectedError: "mount path must be absolute",
  107. },
  108. {
  109. target: "foo",
  110. expectedError: "mount path must be absolute",
  111. },
  112. {
  113. target: "/",
  114. expectedError: "destination can't be '/'",
  115. },
  116. {
  117. target: "//",
  118. expectedError: "destination can't be '/'",
  119. },
  120. }
  121. for _, tc := range testCases {
  122. _, err := client.ContainerCreate(context.Background(),
  123. &container.Config{
  124. Image: "busybox",
  125. },
  126. &container.HostConfig{
  127. Tmpfs: map[string]string{tc.target: ""},
  128. },
  129. &network.NetworkingConfig{},
  130. "",
  131. )
  132. assert.Check(t, is.ErrorContains(err, tc.expectedError))
  133. }
  134. }
  135. func TestCreateWithCustomMaskedPaths(t *testing.T) {
  136. skip.If(t, testEnv.DaemonInfo.OSType != "linux")
  137. defer setupTest(t)()
  138. client := request.NewAPIClient(t)
  139. ctx := context.Background()
  140. testCases := []struct {
  141. maskedPaths []string
  142. expected []string
  143. }{
  144. {
  145. maskedPaths: []string{},
  146. expected: []string{},
  147. },
  148. {
  149. maskedPaths: nil,
  150. expected: oci.DefaultSpec().Linux.MaskedPaths,
  151. },
  152. {
  153. maskedPaths: []string{"/proc/kcore", "/proc/keys"},
  154. expected: []string{"/proc/kcore", "/proc/keys"},
  155. },
  156. }
  157. checkInspect := func(t *testing.T, ctx context.Context, name string, expected []string) {
  158. _, b, err := client.ContainerInspectWithRaw(ctx, name, false)
  159. assert.NilError(t, err)
  160. var inspectJSON map[string]interface{}
  161. err = json.Unmarshal(b, &inspectJSON)
  162. assert.NilError(t, err)
  163. cfg, ok := inspectJSON["HostConfig"].(map[string]interface{})
  164. assert.Check(t, is.Equal(true, ok), name)
  165. maskedPaths, ok := cfg["MaskedPaths"].([]interface{})
  166. assert.Check(t, is.Equal(true, ok), name)
  167. mps := []string{}
  168. for _, mp := range maskedPaths {
  169. mps = append(mps, mp.(string))
  170. }
  171. assert.DeepEqual(t, expected, mps)
  172. }
  173. for i, tc := range testCases {
  174. name := fmt.Sprintf("create-masked-paths-%d", i)
  175. config := container.Config{
  176. Image: "busybox",
  177. Cmd: []string{"true"},
  178. }
  179. hc := container.HostConfig{}
  180. if tc.maskedPaths != nil {
  181. hc.MaskedPaths = tc.maskedPaths
  182. }
  183. // Create the container.
  184. c, err := client.ContainerCreate(context.Background(),
  185. &config,
  186. &hc,
  187. &network.NetworkingConfig{},
  188. name,
  189. )
  190. assert.NilError(t, err)
  191. checkInspect(t, ctx, name, tc.expected)
  192. // Start the container.
  193. err = client.ContainerStart(ctx, c.ID, types.ContainerStartOptions{})
  194. assert.NilError(t, err)
  195. poll.WaitOn(t, ctr.IsInState(ctx, client, c.ID, "exited"), poll.WithDelay(100*time.Millisecond))
  196. checkInspect(t, ctx, name, tc.expected)
  197. }
  198. }
  199. func TestCreateWithCustomReadonlyPaths(t *testing.T) {
  200. skip.If(t, testEnv.DaemonInfo.OSType != "linux")
  201. defer setupTest(t)()
  202. client := request.NewAPIClient(t)
  203. ctx := context.Background()
  204. testCases := []struct {
  205. doc string
  206. readonlyPaths []string
  207. expected []string
  208. }{
  209. {
  210. readonlyPaths: []string{},
  211. expected: []string{},
  212. },
  213. {
  214. readonlyPaths: nil,
  215. expected: oci.DefaultSpec().Linux.ReadonlyPaths,
  216. },
  217. {
  218. readonlyPaths: []string{"/proc/asound", "/proc/bus"},
  219. expected: []string{"/proc/asound", "/proc/bus"},
  220. },
  221. }
  222. checkInspect := func(t *testing.T, ctx context.Context, name string, expected []string) {
  223. _, b, err := client.ContainerInspectWithRaw(ctx, name, false)
  224. assert.NilError(t, err)
  225. var inspectJSON map[string]interface{}
  226. err = json.Unmarshal(b, &inspectJSON)
  227. assert.NilError(t, err)
  228. cfg, ok := inspectJSON["HostConfig"].(map[string]interface{})
  229. assert.Check(t, is.Equal(true, ok), name)
  230. readonlyPaths, ok := cfg["ReadonlyPaths"].([]interface{})
  231. assert.Check(t, is.Equal(true, ok), name)
  232. rops := []string{}
  233. for _, rop := range readonlyPaths {
  234. rops = append(rops, rop.(string))
  235. }
  236. assert.DeepEqual(t, expected, rops)
  237. }
  238. for i, tc := range testCases {
  239. name := fmt.Sprintf("create-readonly-paths-%d", i)
  240. config := container.Config{
  241. Image: "busybox",
  242. Cmd: []string{"true"},
  243. }
  244. hc := container.HostConfig{}
  245. if tc.readonlyPaths != nil {
  246. hc.ReadonlyPaths = tc.readonlyPaths
  247. }
  248. // Create the container.
  249. c, err := client.ContainerCreate(context.Background(),
  250. &config,
  251. &hc,
  252. &network.NetworkingConfig{},
  253. name,
  254. )
  255. assert.NilError(t, err)
  256. checkInspect(t, ctx, name, tc.expected)
  257. // Start the container.
  258. err = client.ContainerStart(ctx, c.ID, types.ContainerStartOptions{})
  259. assert.NilError(t, err)
  260. poll.WaitOn(t, ctr.IsInState(ctx, client, c.ID, "exited"), poll.WithDelay(100*time.Millisecond))
  261. checkInspect(t, ctx, name, tc.expected)
  262. }
  263. }