diff --git a/api/server/router/image/image_routes.go b/api/server/router/image/image_routes.go index dabab3bcf9..fd95420ef8 100644 --- a/api/server/router/image/image_routes.go +++ b/api/server/router/image/image_routes.go @@ -13,7 +13,6 @@ import ( "github.com/docker/docker/api/server/httputils" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/backend" - "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/versions" "github.com/docker/docker/pkg/ioutils" @@ -46,9 +45,6 @@ func (s *imageRouter) postCommit(ctx context.Context, w http.ResponseWriter, r * if err != nil && err != io.EOF { //Do not fail if body is empty. return err } - if c == nil { - c = &container.Config{} - } commitCfg := &backend.ContainerCommitConfig{ ContainerCommitConfig: types.ContainerCommitConfig{ diff --git a/builder/dockerfile/builder.go b/builder/dockerfile/builder.go index b62d6fc024..20f1650825 100644 --- a/builder/dockerfile/builder.go +++ b/builder/dockerfile/builder.go @@ -396,7 +396,8 @@ func BuildFromConfig(config *container.Config, changes []string) (*container.Con } dispatchRequest := newDispatchRequest(b, dockerfile.EscapeToken, nil, newBuildArgs(b.options.BuildArgs), newStagesBuildResults()) - dispatchRequest.state.runConfig = config + // We make mutations to the configuration, ensure we have a copy + dispatchRequest.state.runConfig = copyRunConfig(config) dispatchRequest.state.imageID = config.Image for _, cmd := range commands { err := dispatch(dispatchRequest, cmd) diff --git a/daemon/commit.go b/daemon/commit.go index 005313224b..1bdbd6be4f 100644 --- a/daemon/commit.go +++ b/daemon/commit.go @@ -149,6 +149,10 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str defer daemon.containerUnpause(container) } + if c.MergeConfigs && c.Config == nil { + c.Config = container.Config + } + newConfig, err := dockerfile.BuildFromConfig(c.Config, c.Changes) if err != nil { return "", err diff --git a/integration-cli/docker_cli_commit_test.go b/integration-cli/docker_cli_commit_test.go index 58a50ce0b8..057c2d6f14 100644 --- a/integration-cli/docker_cli_commit_test.go +++ b/integration-cli/docker_cli_commit_test.go @@ -121,11 +121,19 @@ func (s *DockerSuite) TestCommitChange(c *check.C) { "test", "test-commit") imageID = strings.TrimSpace(imageID) + // The ordering here is due to `PATH` being overridden from the container's + // ENV. On windows, the container doesn't have a `PATH` ENV variable so + // the ordering is the same as the cli. + expectedEnv := "[PATH=/foo DEBUG=true test=1]" + if testEnv.DaemonPlatform() == "windows" { + expectedEnv = "[DEBUG=true test=1 PATH=/foo]" + } + prefix, slash := getPrefixAndSlashFromDaemonPlatform() prefix = strings.ToUpper(prefix) // Force C: as that's how WORKDIR is normalized on Windows expected := map[string]string{ "Config.ExposedPorts": "map[8080/tcp:{}]", - "Config.Env": "[DEBUG=true test=1 PATH=/foo]", + "Config.Env": expectedEnv, "Config.Labels": "map[foo:bar]", "Config.Cmd": "[/bin/sh]", "Config.WorkingDir": prefix + slash + "opt", diff --git a/integration/image/commit_test.go b/integration/image/commit_test.go new file mode 100644 index 0000000000..13edbe1175 --- /dev/null +++ b/integration/image/commit_test.go @@ -0,0 +1,47 @@ +package image + +import ( + "context" + "testing" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/integration/util/request" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestCommitInheritsEnv(t *testing.T) { + defer setupTest(t)() + client := request.NewAPIClient(t) + ctx := context.Background() + + createResp1, err := client.ContainerCreate(ctx, &container.Config{Image: "busybox"}, nil, nil, "") + require.NoError(t, err) + + commitResp1, err := client.ContainerCommit(ctx, createResp1.ID, types.ContainerCommitOptions{ + Changes: []string{"ENV PATH=/bin"}, + Reference: "test-commit-image", + }) + require.NoError(t, err) + + image1, _, err := client.ImageInspectWithRaw(ctx, commitResp1.ID) + require.NoError(t, err) + + expectedEnv1 := []string{"PATH=/bin"} + assert.Equal(t, expectedEnv1, image1.Config.Env) + + createResp2, err := client.ContainerCreate(ctx, &container.Config{Image: image1.ID}, nil, nil, "") + require.NoError(t, err) + + commitResp2, err := client.ContainerCommit(ctx, createResp2.ID, types.ContainerCommitOptions{ + Changes: []string{"ENV PATH=/usr/bin:$PATH"}, + Reference: "test-commit-image", + }) + require.NoError(t, err) + + image2, _, err := client.ImageInspectWithRaw(ctx, commitResp2.ID) + require.NoError(t, err) + expectedEnv2 := []string{"PATH=/usr/bin:/bin"} + assert.Equal(t, expectedEnv2, image2.Config.Env) +}