Skip to content

Commit

Permalink
Ensure RUN instruction to run without Healthcheck
Browse files Browse the repository at this point in the history
Before this commit Healthcheck run if HEALTHCHECK
instruction appears before RUN instruction.
By passing `withoutHealthcheck` to `copyRunConfig`,
always RUN instruction run without Healthcheck.

Fix: moby#37362

Signed-off-by: Yuichiro Kaneko <spiketeika@gmail.com>
  • Loading branch information
yui-knk committed Jul 8, 2018
1 parent ae1160b commit 44e08d8
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 1 deletion.
3 changes: 2 additions & 1 deletion builder/dockerfile/dispatchers.go
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,8 @@ func dispatchRun(d dispatchRequest, c *instructions.RunCommand) error {
runConfig := copyRunConfig(stateRunConfig,
withCmd(cmdFromArgs),
withEnv(append(stateRunConfig.Env, buildArgs...)),
withEntrypointOverride(saveCmd, strslice.StrSlice{""}))
withEntrypointOverride(saveCmd, strslice.StrSlice{""}),
withoutHealthcheck())

// set config as already being escaped, this prevents double escaping on windows
runConfig.ArgsEscaped = true
Expand Down
61 changes: 61 additions & 0 deletions builder/dockerfile/dispatchers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -473,3 +473,64 @@ func TestRunWithBuildArgs(t *testing.T) {
// Check that runConfig.Cmd has not been modified by run
assert.Check(t, is.DeepEqual(origCmd, sb.state.runConfig.Cmd))
}

func TestRunIgnoresHealthcheck(t *testing.T) {
b := newBuilderWithMockBackend()
args := NewBuildArgs(make(map[string]*string))
sb := newDispatchRequest(b, '`', nil, args, newStagesBuildResults())
b.disableCommit = false

origCmd := strslice.StrSlice([]string{"cmd", "in", "from", "image"})

imageCache := &mockImageCache{
getCacheFunc: func(parentID string, cfg *container.Config) (string, error) {
return "", nil
},
}

mockBackend := b.docker.(*MockBackend)
mockBackend.makeImageCacheFunc = func(_ []string) builder.ImageCache {
return imageCache
}
b.imageProber = newImageProber(mockBackend, nil, false)
mockBackend.getImageFunc = func(_ string) (builder.Image, builder.ROLayer, error) {
return &mockImage{
id: "abcdef",
config: &container.Config{Cmd: origCmd},
}, nil, nil
}
mockBackend.containerCreateFunc = func(config types.ContainerCreateConfig) (container.ContainerCreateCreatedBody, error) {
return container.ContainerCreateCreatedBody{ID: "12345"}, nil
}
mockBackend.commitFunc = func(cfg backend.CommitConfig) (image.ID, error) {
return "", nil
}
from := &instructions.Stage{BaseName: "abcdef"}
err := initializeStage(sb, from)
assert.NilError(t, err)

expectedTest := []string{"CMD-SHELL", "curl -f http://localhost/ || exit 1"}
cmd := &instructions.HealthCheckCommand{
Health: &container.HealthConfig{
Test: expectedTest,
},
}
assert.NilError(t, dispatch(sb, cmd))
assert.Assert(t, sb.state.runConfig.Healthcheck != nil)

mockBackend.containerCreateFunc = func(config types.ContainerCreateConfig) (container.ContainerCreateCreatedBody, error) {
// Check the Healthcheck is disabled.
assert.Check(t, is.DeepEqual([]string{"NONE"}, config.Config.Healthcheck.Test))
return container.ContainerCreateCreatedBody{ID: "123456"}, nil
}

sb.state.buildArgs.AddArg("one", strPtr("two"))
run := &instructions.RunCommand{
ShellDependantCmdLine: instructions.ShellDependantCmdLine{
CmdLine: strslice.StrSlice{"echo foo"},
PrependShell: true,
},
}
assert.NilError(t, dispatch(sb, run))
assert.Check(t, is.DeepEqual(expectedTest, sb.state.runConfig.Healthcheck.Test))
}
12 changes: 12 additions & 0 deletions builder/dockerfile/internals.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,18 @@ func withEntrypointOverride(cmd []string, entrypoint []string) runConfigModifier
}
}

// withoutHealthcheck disables healthcheck.
//
// The dockerfile RUN instruction expect to run without healthcheck
// so the runConfig Healthcheck needs to be disabled.
func withoutHealthcheck() runConfigModifier {
return func(runConfig *container.Config) {
runConfig.Healthcheck = &container.HealthConfig{
Test: []string{"NONE"},
}
}
}

func copyRunConfig(runConfig *container.Config, modifiers ...runConfigModifier) *container.Config {
copy := *runConfig
copy.Cmd = copyStringSlice(runConfig.Cmd)
Expand Down

0 comments on commit 44e08d8

Please sign in to comment.