docker_api_build_test.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. package main
  2. import (
  3. "archive/tar"
  4. "bytes"
  5. "net/http"
  6. "regexp"
  7. "strings"
  8. "github.com/docker/docker/pkg/integration/checker"
  9. "github.com/go-check/check"
  10. )
  11. func (s *DockerSuite) TestBuildApiDockerFileRemote(c *check.C) {
  12. testRequires(c, NotUserNamespace)
  13. var testD string
  14. if daemonPlatform == "windows" {
  15. testD = `FROM busybox
  16. COPY * /tmp/
  17. RUN find / -name ba*
  18. RUN find /tmp/`
  19. } else {
  20. // -xdev is required because sysfs can cause EPERM
  21. testD = `FROM busybox
  22. COPY * /tmp/
  23. RUN find / -xdev -name ba*
  24. RUN find /tmp/`
  25. }
  26. server, err := fakeStorage(map[string]string{"testD": testD})
  27. c.Assert(err, checker.IsNil)
  28. defer server.Close()
  29. res, body, err := sockRequestRaw("POST", "/build?dockerfile=baz&remote="+server.URL()+"/testD", nil, "application/json")
  30. c.Assert(err, checker.IsNil)
  31. c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
  32. buf, err := readBody(body)
  33. c.Assert(err, checker.IsNil)
  34. // Make sure Dockerfile exists.
  35. // Make sure 'baz' doesn't exist ANYWHERE despite being mentioned in the URL
  36. out := string(buf)
  37. c.Assert(out, checker.Contains, "/tmp/Dockerfile")
  38. c.Assert(out, checker.Not(checker.Contains), "baz")
  39. }
  40. func (s *DockerSuite) TestBuildApiRemoteTarballContext(c *check.C) {
  41. buffer := new(bytes.Buffer)
  42. tw := tar.NewWriter(buffer)
  43. defer tw.Close()
  44. dockerfile := []byte("FROM busybox")
  45. err := tw.WriteHeader(&tar.Header{
  46. Name: "Dockerfile",
  47. Size: int64(len(dockerfile)),
  48. })
  49. // failed to write tar file header
  50. c.Assert(err, checker.IsNil)
  51. _, err = tw.Write(dockerfile)
  52. // failed to write tar file content
  53. c.Assert(err, checker.IsNil)
  54. // failed to close tar archive
  55. c.Assert(tw.Close(), checker.IsNil)
  56. server, err := fakeBinaryStorage(map[string]*bytes.Buffer{
  57. "testT.tar": buffer,
  58. })
  59. c.Assert(err, checker.IsNil)
  60. defer server.Close()
  61. res, b, err := sockRequestRaw("POST", "/build?remote="+server.URL()+"/testT.tar", nil, "application/tar")
  62. c.Assert(err, checker.IsNil)
  63. c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
  64. b.Close()
  65. }
  66. func (s *DockerSuite) TestBuildApiRemoteTarballContextWithCustomDockerfile(c *check.C) {
  67. buffer := new(bytes.Buffer)
  68. tw := tar.NewWriter(buffer)
  69. defer tw.Close()
  70. dockerfile := []byte(`FROM busybox
  71. RUN echo 'wrong'`)
  72. err := tw.WriteHeader(&tar.Header{
  73. Name: "Dockerfile",
  74. Size: int64(len(dockerfile)),
  75. })
  76. // failed to write tar file header
  77. c.Assert(err, checker.IsNil)
  78. _, err = tw.Write(dockerfile)
  79. // failed to write tar file content
  80. c.Assert(err, checker.IsNil)
  81. custom := []byte(`FROM busybox
  82. RUN echo 'right'
  83. `)
  84. err = tw.WriteHeader(&tar.Header{
  85. Name: "custom",
  86. Size: int64(len(custom)),
  87. })
  88. // failed to write tar file header
  89. c.Assert(err, checker.IsNil)
  90. _, err = tw.Write(custom)
  91. // failed to write tar file content
  92. c.Assert(err, checker.IsNil)
  93. // failed to close tar archive
  94. c.Assert(tw.Close(), checker.IsNil)
  95. server, err := fakeBinaryStorage(map[string]*bytes.Buffer{
  96. "testT.tar": buffer,
  97. })
  98. c.Assert(err, checker.IsNil)
  99. defer server.Close()
  100. url := "/build?dockerfile=custom&remote=" + server.URL() + "/testT.tar"
  101. res, body, err := sockRequestRaw("POST", url, nil, "application/tar")
  102. c.Assert(err, checker.IsNil)
  103. c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
  104. defer body.Close()
  105. content, err := readBody(body)
  106. c.Assert(err, checker.IsNil)
  107. // Build used the wrong dockerfile.
  108. c.Assert(string(content), checker.Not(checker.Contains), "wrong")
  109. }
  110. func (s *DockerSuite) TestBuildApiLowerDockerfile(c *check.C) {
  111. git, err := newFakeGit("repo", map[string]string{
  112. "dockerfile": `FROM busybox
  113. RUN echo from dockerfile`,
  114. }, false)
  115. c.Assert(err, checker.IsNil)
  116. defer git.Close()
  117. res, body, err := sockRequestRaw("POST", "/build?remote="+git.RepoURL, nil, "application/json")
  118. c.Assert(err, checker.IsNil)
  119. c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
  120. buf, err := readBody(body)
  121. c.Assert(err, checker.IsNil)
  122. out := string(buf)
  123. c.Assert(out, checker.Contains, "from dockerfile")
  124. }
  125. func (s *DockerSuite) TestBuildApiBuildGitWithF(c *check.C) {
  126. git, err := newFakeGit("repo", map[string]string{
  127. "baz": `FROM busybox
  128. RUN echo from baz`,
  129. "Dockerfile": `FROM busybox
  130. RUN echo from Dockerfile`,
  131. }, false)
  132. c.Assert(err, checker.IsNil)
  133. defer git.Close()
  134. // Make sure it tries to 'dockerfile' query param value
  135. res, body, err := sockRequestRaw("POST", "/build?dockerfile=baz&remote="+git.RepoURL, nil, "application/json")
  136. c.Assert(err, checker.IsNil)
  137. c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
  138. buf, err := readBody(body)
  139. c.Assert(err, checker.IsNil)
  140. out := string(buf)
  141. c.Assert(out, checker.Contains, "from baz")
  142. }
  143. func (s *DockerSuite) TestBuildApiDoubleDockerfile(c *check.C) {
  144. testRequires(c, UnixCli) // dockerfile overwrites Dockerfile on Windows
  145. git, err := newFakeGit("repo", map[string]string{
  146. "Dockerfile": `FROM busybox
  147. RUN echo from Dockerfile`,
  148. "dockerfile": `FROM busybox
  149. RUN echo from dockerfile`,
  150. }, false)
  151. c.Assert(err, checker.IsNil)
  152. defer git.Close()
  153. // Make sure it tries to 'dockerfile' query param value
  154. res, body, err := sockRequestRaw("POST", "/build?remote="+git.RepoURL, nil, "application/json")
  155. c.Assert(err, checker.IsNil)
  156. c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
  157. buf, err := readBody(body)
  158. c.Assert(err, checker.IsNil)
  159. out := string(buf)
  160. c.Assert(out, checker.Contains, "from Dockerfile")
  161. }
  162. func (s *DockerSuite) TestBuildApiUnnormalizedTarPaths(c *check.C) {
  163. // Make sure that build context tars with entries of the form
  164. // x/./y don't cause caching false positives.
  165. buildFromTarContext := func(fileContents []byte) string {
  166. buffer := new(bytes.Buffer)
  167. tw := tar.NewWriter(buffer)
  168. defer tw.Close()
  169. dockerfile := []byte(`FROM busybox
  170. COPY dir /dir/`)
  171. err := tw.WriteHeader(&tar.Header{
  172. Name: "Dockerfile",
  173. Size: int64(len(dockerfile)),
  174. })
  175. //failed to write tar file header
  176. c.Assert(err, checker.IsNil)
  177. _, err = tw.Write(dockerfile)
  178. // failed to write Dockerfile in tar file content
  179. c.Assert(err, checker.IsNil)
  180. err = tw.WriteHeader(&tar.Header{
  181. Name: "dir/./file",
  182. Size: int64(len(fileContents)),
  183. })
  184. //failed to write tar file header
  185. c.Assert(err, checker.IsNil)
  186. _, err = tw.Write(fileContents)
  187. // failed to write file contents in tar file content
  188. c.Assert(err, checker.IsNil)
  189. // failed to close tar archive
  190. c.Assert(tw.Close(), checker.IsNil)
  191. res, body, err := sockRequestRaw("POST", "/build", buffer, "application/x-tar")
  192. c.Assert(err, checker.IsNil)
  193. c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
  194. out, err := readBody(body)
  195. c.Assert(err, checker.IsNil)
  196. lines := strings.Split(string(out), "\n")
  197. c.Assert(len(lines), checker.GreaterThan, 1)
  198. c.Assert(lines[len(lines)-2], checker.Matches, ".*Successfully built [0-9a-f]{12}.*")
  199. re := regexp.MustCompile("Successfully built ([0-9a-f]{12})")
  200. matches := re.FindStringSubmatch(lines[len(lines)-2])
  201. return matches[1]
  202. }
  203. imageA := buildFromTarContext([]byte("abc"))
  204. imageB := buildFromTarContext([]byte("def"))
  205. c.Assert(imageA, checker.Not(checker.Equals), imageB)
  206. }