diff --git a/integration/dockerfiles/Dockerfile_test_cmd b/integration/dockerfiles/Dockerfile_test_cmd new file mode 100644 index 000000000..631b93fd8 --- /dev/null +++ b/integration/dockerfiles/Dockerfile_test_cmd @@ -0,0 +1,5 @@ +FROM scratch AS first +CMD ["mycmd"] + +FROM first +ENTRYPOINT ["myentrypoint"] # This should clear out CMD in the config metadata diff --git a/pkg/executor/build.go b/pkg/executor/build.go index 27f58d70f..10cbeca9e 100644 --- a/pkg/executor/build.go +++ b/pkg/executor/build.go @@ -145,6 +145,9 @@ func DoBuild(opts *config.KanikoOptions) (v1.Image, error) { return nil, err } } + if err := reviewConfig(stage, &imageConfig.Config); err != nil { + return nil, err + } sourceImage, err = mutate.Config(sourceImage, imageConfig.Config) if err != nil { return nil, err @@ -228,3 +231,24 @@ func resolveOnBuild(stage *config.KanikoStage, config *v1.Config) error { config.OnBuild = nil return nil } + +// reviewConfig makes sure the value of CMD is correct after building the stage +// If ENTRYPOINT was set in this stage but CMD wasn't, then CMD should be cleared out +// See Issue #346 for more info +func reviewConfig(stage config.KanikoStage, config *v1.Config) error { + entrypoint := false + cmd := false + + for _, c := range stage.Commands { + if c.Name() == "cmd" { + cmd = true + } + if c.Name() == "entrypoint" { + entrypoint = true + } + } + if entrypoint && !cmd { + config.Cmd = []string{} + } + return nil +} diff --git a/pkg/executor/build_test.go b/pkg/executor/build_test.go new file mode 100644 index 000000000..e1f120433 --- /dev/null +++ b/pkg/executor/build_test.go @@ -0,0 +1,76 @@ +/* +Copyright 2018 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package executor + +import ( + "testing" + + "github.com/GoogleContainerTools/kaniko/pkg/config" + "github.com/GoogleContainerTools/kaniko/pkg/dockerfile" + "github.com/GoogleContainerTools/kaniko/testutil" + "github.com/google/go-containerregistry/pkg/v1" +) + +func Test_reviewConfig(t *testing.T) { + tests := []struct { + name string + dockerfile string + originalCmd []string + originalEntrypoint []string + expectedCmd []string + }{ + { + name: "entrypoint and cmd declared", + dockerfile: ` + FROM scratch + CMD ["mycmd"] + ENTRYPOINT ["myentrypoint"]`, + originalEntrypoint: []string{"myentrypoint"}, + originalCmd: []string{"mycmd"}, + expectedCmd: []string{"mycmd"}, + }, + { + name: "only entrypoint declared", + dockerfile: ` + FROM scratch + ENTRYPOINT ["myentrypoint"]`, + originalEntrypoint: []string{"myentrypoint"}, + originalCmd: []string{"mycmd"}, + expectedCmd: []string{}, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + config := &v1.Config{ + Cmd: test.originalCmd, + Entrypoint: test.originalEntrypoint, + } + err := reviewConfig(stage(t, test.dockerfile), config) + testutil.CheckErrorAndDeepEqual(t, false, err, test.expectedCmd, config.Cmd) + }) + } +} + +func stage(t *testing.T, d string) config.KanikoStage { + stages, err := dockerfile.Parse([]byte(d)) + if err != nil { + t.Fatalf("error parsing dockerfile: %v", err) + } + return config.KanikoStage{ + Stage: stages[0], + } +}