github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/integration-cli/docker_api_build_test.go (about) 1 package main 2 3 import ( 4 "archive/tar" 5 "bytes" 6 "encoding/json" 7 "io/ioutil" 8 "net/http" 9 "regexp" 10 "strings" 11 12 "github.com/docker/docker/integration-cli/checker" 13 "github.com/docker/docker/integration-cli/cli/build/fakecontext" 14 "github.com/docker/docker/integration-cli/cli/build/fakegit" 15 "github.com/docker/docker/integration-cli/cli/build/fakestorage" 16 "github.com/docker/docker/integration-cli/request" 17 "github.com/docker/docker/pkg/testutil" 18 "github.com/go-check/check" 19 "github.com/stretchr/testify/assert" 20 "github.com/stretchr/testify/require" 21 "golang.org/x/net/context" 22 ) 23 24 func (s *DockerSuite) TestBuildAPIDockerFileRemote(c *check.C) { 25 testRequires(c, NotUserNamespace) 26 var testD string 27 if testEnv.DaemonPlatform() == "windows" { 28 testD = `FROM busybox 29 RUN find / -name ba* 30 RUN find /tmp/` 31 } else { 32 // -xdev is required because sysfs can cause EPERM 33 testD = `FROM busybox 34 RUN find / -xdev -name ba* 35 RUN find /tmp/` 36 } 37 server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{"testD": testD})) 38 defer server.Close() 39 40 res, body, err := request.Post("/build?dockerfile=baz&remote="+server.URL()+"/testD", request.JSON) 41 c.Assert(err, checker.IsNil) 42 c.Assert(res.StatusCode, checker.Equals, http.StatusOK) 43 44 buf, err := testutil.ReadBody(body) 45 c.Assert(err, checker.IsNil) 46 47 // Make sure Dockerfile exists. 48 // Make sure 'baz' doesn't exist ANYWHERE despite being mentioned in the URL 49 out := string(buf) 50 c.Assert(out, checker.Contains, "RUN find /tmp") 51 c.Assert(out, checker.Not(checker.Contains), "baz") 52 } 53 54 func (s *DockerSuite) TestBuildAPIRemoteTarballContext(c *check.C) { 55 buffer := new(bytes.Buffer) 56 tw := tar.NewWriter(buffer) 57 defer tw.Close() 58 59 dockerfile := []byte("FROM busybox") 60 err := tw.WriteHeader(&tar.Header{ 61 Name: "Dockerfile", 62 Size: int64(len(dockerfile)), 63 }) 64 // failed to write tar file header 65 c.Assert(err, checker.IsNil) 66 67 _, err = tw.Write(dockerfile) 68 // failed to write tar file content 69 c.Assert(err, checker.IsNil) 70 71 // failed to close tar archive 72 c.Assert(tw.Close(), checker.IsNil) 73 74 server := fakestorage.New(c, "", fakecontext.WithBinaryFiles(map[string]*bytes.Buffer{ 75 "testT.tar": buffer, 76 })) 77 defer server.Close() 78 79 res, b, err := request.Post("/build?remote="+server.URL()+"/testT.tar", request.ContentType("application/tar")) 80 c.Assert(err, checker.IsNil) 81 c.Assert(res.StatusCode, checker.Equals, http.StatusOK) 82 b.Close() 83 } 84 85 func (s *DockerSuite) TestBuildAPIRemoteTarballContextWithCustomDockerfile(c *check.C) { 86 buffer := new(bytes.Buffer) 87 tw := tar.NewWriter(buffer) 88 defer tw.Close() 89 90 dockerfile := []byte(`FROM busybox 91 RUN echo 'wrong'`) 92 err := tw.WriteHeader(&tar.Header{ 93 Name: "Dockerfile", 94 Size: int64(len(dockerfile)), 95 }) 96 // failed to write tar file header 97 c.Assert(err, checker.IsNil) 98 99 _, err = tw.Write(dockerfile) 100 // failed to write tar file content 101 c.Assert(err, checker.IsNil) 102 103 custom := []byte(`FROM busybox 104 RUN echo 'right' 105 `) 106 err = tw.WriteHeader(&tar.Header{ 107 Name: "custom", 108 Size: int64(len(custom)), 109 }) 110 111 // failed to write tar file header 112 c.Assert(err, checker.IsNil) 113 114 _, err = tw.Write(custom) 115 // failed to write tar file content 116 c.Assert(err, checker.IsNil) 117 118 // failed to close tar archive 119 c.Assert(tw.Close(), checker.IsNil) 120 121 server := fakestorage.New(c, "", fakecontext.WithBinaryFiles(map[string]*bytes.Buffer{ 122 "testT.tar": buffer, 123 })) 124 defer server.Close() 125 126 url := "/build?dockerfile=custom&remote=" + server.URL() + "/testT.tar" 127 res, body, err := request.Post(url, request.ContentType("application/tar")) 128 c.Assert(err, checker.IsNil) 129 c.Assert(res.StatusCode, checker.Equals, http.StatusOK) 130 131 defer body.Close() 132 content, err := testutil.ReadBody(body) 133 c.Assert(err, checker.IsNil) 134 135 // Build used the wrong dockerfile. 136 c.Assert(string(content), checker.Not(checker.Contains), "wrong") 137 } 138 139 func (s *DockerSuite) TestBuildAPILowerDockerfile(c *check.C) { 140 git := fakegit.New(c, "repo", map[string]string{ 141 "dockerfile": `FROM busybox 142 RUN echo from dockerfile`, 143 }, false) 144 defer git.Close() 145 146 res, body, err := request.Post("/build?remote="+git.RepoURL, request.JSON) 147 c.Assert(err, checker.IsNil) 148 c.Assert(res.StatusCode, checker.Equals, http.StatusOK) 149 150 buf, err := testutil.ReadBody(body) 151 c.Assert(err, checker.IsNil) 152 153 out := string(buf) 154 c.Assert(out, checker.Contains, "from dockerfile") 155 } 156 157 func (s *DockerSuite) TestBuildAPIBuildGitWithF(c *check.C) { 158 git := fakegit.New(c, "repo", map[string]string{ 159 "baz": `FROM busybox 160 RUN echo from baz`, 161 "Dockerfile": `FROM busybox 162 RUN echo from Dockerfile`, 163 }, false) 164 defer git.Close() 165 166 // Make sure it tries to 'dockerfile' query param value 167 res, body, err := request.Post("/build?dockerfile=baz&remote="+git.RepoURL, request.JSON) 168 c.Assert(err, checker.IsNil) 169 c.Assert(res.StatusCode, checker.Equals, http.StatusOK) 170 171 buf, err := testutil.ReadBody(body) 172 c.Assert(err, checker.IsNil) 173 174 out := string(buf) 175 c.Assert(out, checker.Contains, "from baz") 176 } 177 178 func (s *DockerSuite) TestBuildAPIDoubleDockerfile(c *check.C) { 179 testRequires(c, UnixCli) // dockerfile overwrites Dockerfile on Windows 180 git := fakegit.New(c, "repo", map[string]string{ 181 "Dockerfile": `FROM busybox 182 RUN echo from Dockerfile`, 183 "dockerfile": `FROM busybox 184 RUN echo from dockerfile`, 185 }, false) 186 defer git.Close() 187 188 // Make sure it tries to 'dockerfile' query param value 189 res, body, err := request.Post("/build?remote="+git.RepoURL, request.JSON) 190 c.Assert(err, checker.IsNil) 191 c.Assert(res.StatusCode, checker.Equals, http.StatusOK) 192 193 buf, err := testutil.ReadBody(body) 194 c.Assert(err, checker.IsNil) 195 196 out := string(buf) 197 c.Assert(out, checker.Contains, "from Dockerfile") 198 } 199 200 func (s *DockerSuite) TestBuildAPIUnnormalizedTarPaths(c *check.C) { 201 // Make sure that build context tars with entries of the form 202 // x/./y don't cause caching false positives. 203 204 buildFromTarContext := func(fileContents []byte) string { 205 buffer := new(bytes.Buffer) 206 tw := tar.NewWriter(buffer) 207 defer tw.Close() 208 209 dockerfile := []byte(`FROM busybox 210 COPY dir /dir/`) 211 err := tw.WriteHeader(&tar.Header{ 212 Name: "Dockerfile", 213 Size: int64(len(dockerfile)), 214 }) 215 //failed to write tar file header 216 c.Assert(err, checker.IsNil) 217 218 _, err = tw.Write(dockerfile) 219 // failed to write Dockerfile in tar file content 220 c.Assert(err, checker.IsNil) 221 222 err = tw.WriteHeader(&tar.Header{ 223 Name: "dir/./file", 224 Size: int64(len(fileContents)), 225 }) 226 //failed to write tar file header 227 c.Assert(err, checker.IsNil) 228 229 _, err = tw.Write(fileContents) 230 // failed to write file contents in tar file content 231 c.Assert(err, checker.IsNil) 232 233 // failed to close tar archive 234 c.Assert(tw.Close(), checker.IsNil) 235 236 res, body, err := request.Post("/build", request.RawContent(ioutil.NopCloser(buffer)), request.ContentType("application/x-tar")) 237 c.Assert(err, checker.IsNil) 238 c.Assert(res.StatusCode, checker.Equals, http.StatusOK) 239 240 out, err := testutil.ReadBody(body) 241 c.Assert(err, checker.IsNil) 242 lines := strings.Split(string(out), "\n") 243 c.Assert(len(lines), checker.GreaterThan, 1) 244 c.Assert(lines[len(lines)-2], checker.Matches, ".*Successfully built [0-9a-f]{12}.*") 245 246 re := regexp.MustCompile("Successfully built ([0-9a-f]{12})") 247 matches := re.FindStringSubmatch(lines[len(lines)-2]) 248 return matches[1] 249 } 250 251 imageA := buildFromTarContext([]byte("abc")) 252 imageB := buildFromTarContext([]byte("def")) 253 254 c.Assert(imageA, checker.Not(checker.Equals), imageB) 255 } 256 257 func (s *DockerSuite) TestBuildOnBuildWithCopy(c *check.C) { 258 dockerfile := ` 259 FROM ` + minimalBaseImage() + ` as onbuildbase 260 ONBUILD COPY file /file 261 262 FROM onbuildbase 263 ` 264 ctx := fakecontext.New(c, "", 265 fakecontext.WithDockerfile(dockerfile), 266 fakecontext.WithFile("file", "some content"), 267 ) 268 defer ctx.Close() 269 270 res, body, err := request.Post( 271 "/build", 272 request.RawContent(ctx.AsTarReader(c)), 273 request.ContentType("application/x-tar")) 274 c.Assert(err, checker.IsNil) 275 c.Assert(res.StatusCode, checker.Equals, http.StatusOK) 276 277 out, err := testutil.ReadBody(body) 278 c.Assert(err, checker.IsNil) 279 c.Assert(string(out), checker.Contains, "Successfully built") 280 } 281 282 func (s *DockerSuite) TestBuildOnBuildCache(c *check.C) { 283 build := func(dockerfile string) []byte { 284 ctx := fakecontext.New(c, "", 285 fakecontext.WithDockerfile(dockerfile), 286 ) 287 defer ctx.Close() 288 289 res, body, err := request.Post( 290 "/build", 291 request.RawContent(ctx.AsTarReader(c)), 292 request.ContentType("application/x-tar")) 293 require.NoError(c, err) 294 assert.Equal(c, http.StatusOK, res.StatusCode) 295 296 out, err := testutil.ReadBody(body) 297 require.NoError(c, err) 298 assert.Contains(c, string(out), "Successfully built") 299 return out 300 } 301 302 dockerfile := ` 303 FROM ` + minimalBaseImage() + ` as onbuildbase 304 ENV something=bar 305 ONBUILD ENV foo=bar 306 ` 307 build(dockerfile) 308 309 dockerfile += "FROM onbuildbase" 310 out := build(dockerfile) 311 312 imageIDs := getImageIDsFromBuild(c, out) 313 assert.Len(c, imageIDs, 2) 314 parentID, childID := imageIDs[0], imageIDs[1] 315 316 client, err := request.NewClient() 317 require.NoError(c, err) 318 319 // check parentID is correct 320 image, _, err := client.ImageInspectWithRaw(context.Background(), childID) 321 require.NoError(c, err) 322 assert.Equal(c, parentID, image.Parent) 323 } 324 325 type buildLine struct { 326 Stream string 327 Aux struct { 328 ID string 329 } 330 } 331 332 func getImageIDsFromBuild(c *check.C, output []byte) []string { 333 ids := []string{} 334 for _, line := range bytes.Split(output, []byte("\n")) { 335 if len(line) == 0 { 336 continue 337 } 338 entry := buildLine{} 339 require.NoError(c, json.Unmarshal(line, &entry)) 340 if entry.Aux.ID != "" { 341 ids = append(ids, entry.Aux.ID) 342 } 343 } 344 return ids 345 }