docker_api_build_test.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. package main
  2. import (
  3. "archive/tar"
  4. "bytes"
  5. "net/http"
  6. "github.com/docker/docker/pkg/integration/checker"
  7. "github.com/go-check/check"
  8. )
  9. func (s *DockerSuite) TestBuildApiDockerfilePath(c *check.C) {
  10. // Test to make sure we stop people from trying to leave the
  11. // build context when specifying the path to the dockerfile
  12. buffer := new(bytes.Buffer)
  13. tw := tar.NewWriter(buffer)
  14. defer tw.Close()
  15. dockerfile := []byte("FROM busybox")
  16. err := tw.WriteHeader(&tar.Header{
  17. Name: "Dockerfile",
  18. Size: int64(len(dockerfile)),
  19. })
  20. //failed to write tar file header
  21. c.Assert(err, checker.IsNil)
  22. _, err = tw.Write(dockerfile)
  23. // failed to write tar file content
  24. c.Assert(err, checker.IsNil)
  25. // failed to close tar archive
  26. c.Assert(tw.Close(), checker.IsNil)
  27. res, body, err := sockRequestRaw("POST", "/build?dockerfile=../Dockerfile", buffer, "application/x-tar")
  28. c.Assert(err, checker.IsNil)
  29. c.Assert(res.StatusCode, checker.Equals, http.StatusInternalServerError)
  30. out, err := readBody(body)
  31. c.Assert(err, checker.IsNil)
  32. // Didn't complain about leaving build context
  33. c.Assert(string(out), checker.Contains, "Forbidden path outside the build context")
  34. }
  35. func (s *DockerSuite) TestBuildApiDockerFileRemote(c *check.C) {
  36. testRequires(c, NotUserNamespace)
  37. testRequires(c, DaemonIsLinux)
  38. server, err := fakeStorage(map[string]string{
  39. "testD": `FROM busybox
  40. COPY * /tmp/
  41. RUN find / -name ba*
  42. RUN find /tmp/`,
  43. })
  44. c.Assert(err, checker.IsNil)
  45. defer server.Close()
  46. res, body, err := sockRequestRaw("POST", "/build?dockerfile=baz&remote="+server.URL()+"/testD", nil, "application/json")
  47. c.Assert(err, checker.IsNil)
  48. c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
  49. buf, err := readBody(body)
  50. c.Assert(err, checker.IsNil)
  51. // Make sure Dockerfile exists.
  52. // Make sure 'baz' doesn't exist ANYWHERE despite being mentioned in the URL
  53. out := string(buf)
  54. c.Assert(out, checker.Contains, "/tmp/Dockerfile")
  55. c.Assert(out, checker.Not(checker.Contains), "baz")
  56. }
  57. func (s *DockerSuite) TestBuildApiRemoteTarballContext(c *check.C) {
  58. testRequires(c, DaemonIsLinux)
  59. buffer := new(bytes.Buffer)
  60. tw := tar.NewWriter(buffer)
  61. defer tw.Close()
  62. dockerfile := []byte("FROM busybox")
  63. err := tw.WriteHeader(&tar.Header{
  64. Name: "Dockerfile",
  65. Size: int64(len(dockerfile)),
  66. })
  67. // failed to write tar file header
  68. c.Assert(err, checker.IsNil)
  69. _, err = tw.Write(dockerfile)
  70. // failed to write tar file content
  71. c.Assert(err, checker.IsNil)
  72. // failed to close tar archive
  73. c.Assert(tw.Close(), checker.IsNil)
  74. server, err := fakeBinaryStorage(map[string]*bytes.Buffer{
  75. "testT.tar": buffer,
  76. })
  77. c.Assert(err, checker.IsNil)
  78. defer server.Close()
  79. res, b, err := sockRequestRaw("POST", "/build?remote="+server.URL()+"/testT.tar", nil, "application/tar")
  80. c.Assert(err, checker.IsNil)
  81. c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
  82. b.Close()
  83. }
  84. func (s *DockerSuite) TestBuildApiRemoteTarballContextWithCustomDockerfile(c *check.C) {
  85. testRequires(c, DaemonIsLinux)
  86. buffer := new(bytes.Buffer)
  87. tw := tar.NewWriter(buffer)
  88. defer tw.Close()
  89. dockerfile := []byte(`FROM busybox
  90. RUN echo 'wrong'`)
  91. err := tw.WriteHeader(&tar.Header{
  92. Name: "Dockerfile",
  93. Size: int64(len(dockerfile)),
  94. })
  95. // failed to write tar file header
  96. c.Assert(err, checker.IsNil)
  97. _, err = tw.Write(dockerfile)
  98. // failed to write tar file content
  99. c.Assert(err, checker.IsNil)
  100. custom := []byte(`FROM busybox
  101. RUN echo 'right'
  102. `)
  103. err = tw.WriteHeader(&tar.Header{
  104. Name: "custom",
  105. Size: int64(len(custom)),
  106. })
  107. // failed to write tar file header
  108. c.Assert(err, checker.IsNil)
  109. _, err = tw.Write(custom)
  110. // failed to write tar file content
  111. c.Assert(err, checker.IsNil)
  112. // failed to close tar archive
  113. c.Assert(tw.Close(), checker.IsNil)
  114. server, err := fakeBinaryStorage(map[string]*bytes.Buffer{
  115. "testT.tar": buffer,
  116. })
  117. c.Assert(err, checker.IsNil)
  118. defer server.Close()
  119. url := "/build?dockerfile=custom&remote=" + server.URL() + "/testT.tar"
  120. res, body, err := sockRequestRaw("POST", url, nil, "application/tar")
  121. c.Assert(err, checker.IsNil)
  122. c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
  123. defer body.Close()
  124. content, err := readBody(body)
  125. c.Assert(err, checker.IsNil)
  126. // Build used the wrong dockerfile.
  127. c.Assert(string(content), checker.Not(checker.Contains), "wrong")
  128. }
  129. func (s *DockerSuite) TestBuildApiLowerDockerfile(c *check.C) {
  130. testRequires(c, DaemonIsLinux)
  131. git, err := newFakeGit("repo", map[string]string{
  132. "dockerfile": `FROM busybox
  133. RUN echo from dockerfile`,
  134. }, false)
  135. c.Assert(err, checker.IsNil)
  136. defer git.Close()
  137. res, body, err := sockRequestRaw("POST", "/build?remote="+git.RepoURL, nil, "application/json")
  138. c.Assert(err, checker.IsNil)
  139. c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
  140. buf, err := readBody(body)
  141. c.Assert(err, checker.IsNil)
  142. out := string(buf)
  143. c.Assert(out, checker.Contains, "from dockerfile")
  144. }
  145. func (s *DockerSuite) TestBuildApiBuildGitWithF(c *check.C) {
  146. testRequires(c, DaemonIsLinux)
  147. git, err := newFakeGit("repo", map[string]string{
  148. "baz": `FROM busybox
  149. RUN echo from baz`,
  150. "Dockerfile": `FROM busybox
  151. RUN echo from Dockerfile`,
  152. }, false)
  153. c.Assert(err, checker.IsNil)
  154. defer git.Close()
  155. // Make sure it tries to 'dockerfile' query param value
  156. res, body, err := sockRequestRaw("POST", "/build?dockerfile=baz&remote="+git.RepoURL, nil, "application/json")
  157. c.Assert(err, checker.IsNil)
  158. c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
  159. buf, err := readBody(body)
  160. c.Assert(err, checker.IsNil)
  161. out := string(buf)
  162. c.Assert(out, checker.Contains, "from baz")
  163. }
  164. func (s *DockerSuite) TestBuildApiDoubleDockerfile(c *check.C) {
  165. testRequires(c, UnixCli) // dockerfile overwrites Dockerfile on Windows
  166. git, err := newFakeGit("repo", map[string]string{
  167. "Dockerfile": `FROM busybox
  168. RUN echo from Dockerfile`,
  169. "dockerfile": `FROM busybox
  170. RUN echo from dockerfile`,
  171. }, false)
  172. c.Assert(err, checker.IsNil)
  173. defer git.Close()
  174. // Make sure it tries to 'dockerfile' query param value
  175. res, body, err := sockRequestRaw("POST", "/build?remote="+git.RepoURL, nil, "application/json")
  176. c.Assert(err, checker.IsNil)
  177. c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
  178. buf, err := readBody(body)
  179. c.Assert(err, checker.IsNil)
  180. out := string(buf)
  181. c.Assert(out, checker.Contains, "from Dockerfile")
  182. }
  183. func (s *DockerSuite) TestBuildApiDockerfileSymlink(c *check.C) {
  184. // Test to make sure we stop people from trying to leave the
  185. // build context when specifying a symlink as the path to the dockerfile
  186. buffer := new(bytes.Buffer)
  187. tw := tar.NewWriter(buffer)
  188. defer tw.Close()
  189. err := tw.WriteHeader(&tar.Header{
  190. Name: "Dockerfile",
  191. Typeflag: tar.TypeSymlink,
  192. Linkname: "/etc/passwd",
  193. })
  194. // failed to write tar file header
  195. c.Assert(err, checker.IsNil)
  196. // failed to close tar archive
  197. c.Assert(tw.Close(), checker.IsNil)
  198. res, body, err := sockRequestRaw("POST", "/build", buffer, "application/x-tar")
  199. c.Assert(err, checker.IsNil)
  200. c.Assert(res.StatusCode, checker.Equals, http.StatusInternalServerError)
  201. out, err := readBody(body)
  202. c.Assert(err, checker.IsNil)
  203. // The reason the error is "Cannot locate specified Dockerfile" is because
  204. // in the builder, the symlink is resolved within the context, therefore
  205. // Dockerfile -> /etc/passwd becomes etc/passwd from the context which is
  206. // a nonexistent file.
  207. c.Assert(string(out), checker.Contains, "Cannot locate specified Dockerfile: Dockerfile", check.Commentf("Didn't complain about leaving build context"))
  208. }