diff --git a/builder/dockerfile/evaluator.go b/builder/dockerfile/evaluator.go index deeda66b05..6ee4f2cfce 100644 --- a/builder/dockerfile/evaluator.go +++ b/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 { diff --git a/integration-cli/docker_api_attach_test.go b/integration-cli/docker_api_attach_test.go index 88dba3e974..11f7340c1f 100644 --- a/integration-cli/docker_api_attach_test.go +++ b/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) diff --git a/integration-cli/docker_api_build_test.go b/integration-cli/docker_api_build_test.go index 12d3374dd5..64ad7c3251 100644 --- a/integration-cli/docker_api_build_test.go +++ b/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 +} diff --git a/integration-cli/request/request.go b/integration-cli/request/request.go index be3628b9b2..1cb3ffec12 100644 --- a/integration-cli/request/request.go +++ b/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