Browse Source

Fix Cache with ONBUILD

Signed-off-by: Daniel Nephin <dnephin@docker.com>
Daniel Nephin 8 years ago
parent
commit
f1ade82d82

+ 2 - 4
builder/dockerfile/evaluator.go

@@ -171,11 +171,9 @@ func (b *Builder) dispatch(options dispatchOptions) (*dispatchState, error) {
 		buildsFailed.WithValues(metricsUnknownInstructionError).Inc()
 		return nil, fmt.Errorf("unknown instruction: %s", upperCasedCmd)
 	}
-	if err := f(newDispatchRequestFromOptions(options, b, args)); err != nil {
-		return nil, err
-	}
 	options.state.updateRunConfig()
-	return options.state, nil
+	err = f(newDispatchRequestFromOptions(options, b, args))
+	return options.state, err
 }
 
 type dispatchOptions struct {

+ 1 - 1
integration-cli/docker_api_attach_test.go

@@ -74,7 +74,7 @@ func (s *DockerSuite) TestGetContainersAttachWebsocket(c *check.C) {
 
 // regression gh14320
 func (s *DockerSuite) TestPostContainersAttachContainerNotFound(c *check.C) {
-	client, err := request.NewClient(daemonHost())
+	client, err := request.NewHTTPClient(daemonHost())
 	c.Assert(err, checker.IsNil)
 	req, err := request.New(daemonHost(), "/containers/doesnotexist/attach", request.Method(http.MethodPost))
 	resp, err := client.Do(req)

+ 69 - 0
integration-cli/docker_api_build_test.go

@@ -3,6 +3,7 @@ package main
 import (
 	"archive/tar"
 	"bytes"
+	"encoding/json"
 	"io/ioutil"
 	"net/http"
 	"regexp"
@@ -15,6 +16,9 @@ import (
 	"github.com/docker/docker/integration-cli/request"
 	"github.com/docker/docker/pkg/testutil"
 	"github.com/go-check/check"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+	"golang.org/x/net/context"
 )
 
 func (s *DockerSuite) TestBuildAPIDockerFileRemote(c *check.C) {
@@ -274,3 +278,68 @@ func (s *DockerSuite) TestBuildOnBuildWithCopy(c *check.C) {
 	c.Assert(err, checker.IsNil)
 	c.Assert(string(out), checker.Contains, "Successfully built")
 }
+
+func (s *DockerSuite) TestBuildOnBuildCache(c *check.C) {
+	build := func(dockerfile string) []byte {
+		ctx := fakecontext.New(c, "",
+			fakecontext.WithDockerfile(dockerfile),
+		)
+		defer ctx.Close()
+
+		res, body, err := request.Post(
+			"/build",
+			request.RawContent(ctx.AsTarReader(c)),
+			request.ContentType("application/x-tar"))
+		require.NoError(c, err)
+		assert.Equal(c, http.StatusOK, res.StatusCode)
+
+		out, err := testutil.ReadBody(body)
+		require.NoError(c, err)
+		assert.Contains(c, string(out), "Successfully built")
+		return out
+	}
+
+	dockerfile := `
+		FROM ` + minimalBaseImage() + ` as onbuildbase
+		ENV something=bar
+		ONBUILD ENV foo=bar
+	`
+	build(dockerfile)
+
+	dockerfile += "FROM onbuildbase"
+	out := build(dockerfile)
+
+	imageIDs := getImageIDsFromBuild(c, out)
+	assert.Len(c, imageIDs, 2)
+	parentID, childID := imageIDs[0], imageIDs[1]
+
+	client, err := request.NewClient()
+	require.NoError(c, err)
+
+	// check parentID is correct
+	image, _, err := client.ImageInspectWithRaw(context.Background(), childID)
+	require.NoError(c, err)
+	assert.Equal(c, parentID, image.Parent)
+}
+
+type buildLine struct {
+	Stream string
+	Aux    struct {
+		ID string
+	}
+}
+
+func getImageIDsFromBuild(c *check.C, output []byte) []string {
+	ids := []string{}
+	for _, line := range bytes.Split(output, []byte("\n")) {
+		if len(line) == 0 {
+			continue
+		}
+		entry := buildLine{}
+		require.NoError(c, json.Unmarshal(line, &entry))
+		if entry.Aux.ID != "" {
+			ids = append(ids, entry.Aux.ID)
+		}
+	}
+	return ids
+}

+ 13 - 3
integration-cli/request/request.go

@@ -100,7 +100,7 @@ func DoOnHost(host, endpoint string, modifiers ...func(*http.Request) error) (*h
 	if err != nil {
 		return nil, nil, err
 	}
-	client, err := NewClient(host)
+	client, err := NewHTTPClient(host)
 	if err != nil {
 		return nil, nil, err
 	}
@@ -140,8 +140,8 @@ func New(host, endpoint string, modifiers ...func(*http.Request) error) (*http.R
 	return req, nil
 }
 
-// NewClient creates an http client for the specific host
-func NewClient(host string) (*http.Client, error) {
+// NewHTTPClient creates an http client for the specific host
+func NewHTTPClient(host string) (*http.Client, error) {
 	// FIXME(vdemeester) 10*time.Second timeout of SockRequest… ?
 	proto, addr, _, err := dclient.ParseHost(host)
 	if err != nil {
@@ -163,6 +163,16 @@ func NewClient(host string) (*http.Client, error) {
 	}, err
 }
 
+// NewClient returns a new Docker API client
+func NewClient() (dclient.APIClient, error) {
+	host := DaemonHost()
+	httpClient, err := NewHTTPClient(host)
+	if err != nil {
+		return nil, err
+	}
+	return dclient.NewClient(host, "", httpClient, nil)
+}
+
 // FIXME(vdemeester) httputil.ClientConn is deprecated, use http.Client instead (closer to actual client)
 // Deprecated: Use New instead of NewRequestClient
 // Deprecated: use request.Do (or Get, Delete, Post) instead