docker_api_build_test.go 7.4 KB

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