From 5da78632a18ebd16bca2c7c37bf1e32b518bca0c Mon Sep 17 00:00:00 2001 From: Priya Wadhwa Date: Tue, 20 Mar 2018 10:40:45 -0700 Subject: [PATCH 1/4] CMD command and unit tests --- pkg/commands/cmd.go | 63 ++++++++++++++++++++++++++++++++++++++++ pkg/commands/cmd_test.go | 61 ++++++++++++++++++++++++++++++++++++++ pkg/commands/commands.go | 2 ++ 3 files changed, 126 insertions(+) create mode 100644 pkg/commands/cmd.go create mode 100644 pkg/commands/cmd_test.go diff --git a/pkg/commands/cmd.go b/pkg/commands/cmd.go new file mode 100644 index 000000000..54e18e241 --- /dev/null +++ b/pkg/commands/cmd.go @@ -0,0 +1,63 @@ +/* +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 commands + +import ( + "github.com/containers/image/manifest" + "github.com/docker/docker/builder/dockerfile/instructions" + "github.com/sirupsen/logrus" + "strings" +) + +type CmdCommand struct { + cmd *instructions.CmdCommand +} + +// ExecuteCommand executes the CMD command +// Argument handling is the same as RUN. +func (c *CmdCommand) ExecuteCommand(config *manifest.Schema2Config) error { + logrus.Info("cmd: CMD") + var newCommand []string + if c.cmd.PrependShell { + // This is the default shell on Linux + // TODO: Support shell command here + shell := []string{"/bin/sh", "-c"} + newCommand = append(shell, strings.Join(c.cmd.CmdLine, " ")) + } else { + newCommand = c.cmd.CmdLine + } + + logrus.Infof("Replacing CMD in config with %v", newCommand) + config.Cmd = newCommand + return nil +} + +// FilesToSnapshot returns an empty array since this is a metadata command +func (c *CmdCommand) FilesToSnapshot() []string { + return []string{} +} + +// CreatedBy returns some information about the command for the image config history +func (c *CmdCommand) CreatedBy() string { + cmdLine := strings.Join(c.cmd.CmdLine, " ") + if c.cmd.PrependShell { + // TODO: Support shell command here + shell := []string{"/bin/sh", "-c"} + return strings.Join(append(shell, cmdLine), " ") + } + return cmdLine +} diff --git a/pkg/commands/cmd_test.go b/pkg/commands/cmd_test.go new file mode 100644 index 000000000..3a966da11 --- /dev/null +++ b/pkg/commands/cmd_test.go @@ -0,0 +1,61 @@ +/* +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 commands + +import ( + "github.com/GoogleCloudPlatform/k8s-container-builder/testutil" + "github.com/containers/image/manifest" + "github.com/containers/image/pkg/strslice" + "github.com/docker/docker/builder/dockerfile/instructions" + "testing" +) + +var cmdTests = []struct { + prependShell bool + cmdLine []string + expectedCmd strslice.StrSlice +}{ + { + prependShell: true, + cmdLine: []string{"echo", "cmd1"}, + expectedCmd: strslice.StrSlice{"/bin/sh", "-c", "echo cmd1"}, + }, + { + prependShell: false, + cmdLine: []string{"echo", "cmd2"}, + expectedCmd: strslice.StrSlice{"echo", "cmd2"}, + }, +} + +func TestExecuteCmd(t *testing.T) { + + cfg := &manifest.Schema2Config{ + Cmd: nil, + } + + for _, test := range cmdTests { + cmd := CmdCommand{ + &instructions.CmdCommand{ + ShellDependantCmdLine: instructions.ShellDependantCmdLine{ + PrependShell: test.prependShell, + CmdLine: test.cmdLine, + }, + }, + } + err := cmd.ExecuteCommand(cfg) + testutil.CheckErrorAndDeepEqual(t, false, err, test.expectedCmd, cfg.Cmd) + } +} diff --git a/pkg/commands/commands.go b/pkg/commands/commands.go index 6fc2a8c1a..3ce6960aa 100644 --- a/pkg/commands/commands.go +++ b/pkg/commands/commands.go @@ -40,6 +40,8 @@ func GetCommand(cmd instructions.Command) (DockerCommand, error) { return &RunCommand{cmd: c}, nil case *instructions.EnvCommand: return &EnvCommand{cmd: c}, nil + case *instructions.CmdCommand: + return &CmdCommand{cmd: c}, nil } return nil, errors.Errorf("%s is not a supported command", cmd.Name()) } From 773d2b06fdc4b65b145db4757f6c7b2c2648a220 Mon Sep 17 00:00:00 2001 From: Priya Wadhwa Date: Tue, 20 Mar 2018 10:50:04 -0700 Subject: [PATCH 2/4] CMD integration test --- integration_tests/dockerfiles/Dockerfile_test_cmd | 4 ++++ integration_tests/dockerfiles/test_cmd.yaml | 3 +++ integration_tests/integration_test_yaml.go | 7 +++++++ 3 files changed, 14 insertions(+) create mode 100644 integration_tests/dockerfiles/Dockerfile_test_cmd create mode 100644 integration_tests/dockerfiles/test_cmd.yaml diff --git a/integration_tests/dockerfiles/Dockerfile_test_cmd b/integration_tests/dockerfiles/Dockerfile_test_cmd new file mode 100644 index 000000000..7b8b04999 --- /dev/null +++ b/integration_tests/dockerfiles/Dockerfile_test_cmd @@ -0,0 +1,4 @@ +FROM gcr.io/distroless/base:latest +CMD ["command", "one"] +CMD ["command", "two"] +CMD echo "hello" diff --git a/integration_tests/dockerfiles/test_cmd.yaml b/integration_tests/dockerfiles/test_cmd.yaml new file mode 100644 index 000000000..c05b14824 --- /dev/null +++ b/integration_tests/dockerfiles/test_cmd.yaml @@ -0,0 +1,3 @@ +schemaVersion: '2.0.0' +metadataTest: + cmd: ["/bin/sh", "-c", "echo \"hello\""] diff --git a/integration_tests/integration_test_yaml.go b/integration_tests/integration_test_yaml.go index 5471e207e..d610e5146 100644 --- a/integration_tests/integration_test_yaml.go +++ b/integration_tests/integration_test_yaml.go @@ -65,6 +65,13 @@ var structureTests = []struct { dockerBuildContext: "/workspace/integration_tests/dockerfiles/", structureTestYamlPath: "/workspace/integration_tests/dockerfiles/test_env.yaml", }, + { + description: "test cmd", + dockerfilePath: "/workspace/integration_tests/dockerfiles/Dockerfile_test_cmd", + repo: "test-cmd", + dockerBuildContext: "/workspace/integration_tests/dockerfiles/", + structureTestYamlPath: "/workspace/integration_tests/dockerfiles/test_cmd.yaml", + }, } type step struct { From d49c7c5ed1fb430bb4dd0986239e923448f09524 Mon Sep 17 00:00:00 2001 From: Priya Wadhwa Date: Tue, 20 Mar 2018 12:58:38 -0700 Subject: [PATCH 3/4] Entrypoint command and unit tests --- pkg/commands/commands.go | 2 ++ pkg/commands/entrypoint.go | 64 +++++++++++++++++++++++++++++++++ pkg/commands/entrypoint_test.go | 61 +++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 pkg/commands/entrypoint.go create mode 100644 pkg/commands/entrypoint_test.go diff --git a/pkg/commands/commands.go b/pkg/commands/commands.go index 3ce6960aa..04622035b 100644 --- a/pkg/commands/commands.go +++ b/pkg/commands/commands.go @@ -42,6 +42,8 @@ func GetCommand(cmd instructions.Command) (DockerCommand, error) { return &EnvCommand{cmd: c}, nil case *instructions.CmdCommand: return &CmdCommand{cmd: c}, nil + case *instructions.EntrypointCommand: + return &EntrypointCommand{cmd: c}, nil } return nil, errors.Errorf("%s is not a supported command", cmd.Name()) } diff --git a/pkg/commands/entrypoint.go b/pkg/commands/entrypoint.go new file mode 100644 index 000000000..a7fd5f3ed --- /dev/null +++ b/pkg/commands/entrypoint.go @@ -0,0 +1,64 @@ +/* +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 commands + +import ( + "github.com/containers/image/manifest" + "github.com/docker/docker/builder/dockerfile/instructions" + "github.com/sirupsen/logrus" + "strings" +) + +type EntrypointCommand struct { + cmd *instructions.EntrypointCommand +} + +// ExecuteCommand handles command processing similar to CMD and RUN, +func (e *EntrypointCommand) ExecuteCommand(config *manifest.Schema2Config) error { + logrus.Info("cmd: ENTRYPOINT") + var newCommand []string + if e.cmd.PrependShell { + // This is the default shell on Linux + // TODO: Support shell command here + shell := []string{"/bin/sh", "-c"} + newCommand = append(shell, strings.Join(e.cmd.CmdLine, " ")) + } else { + newCommand = e.cmd.CmdLine + } + + logrus.Infof("Replacing Entrypoint in config with %v", newCommand) + config.Entrypoint = newCommand + return nil +} + +// FilesToSnapshot returns an empty array since this is a metadata command +func (e *EntrypointCommand) FilesToSnapshot() []string { + return []string{} +} + +// CreatedBy returns some information about the command for the image config history +func (e *EntrypointCommand) CreatedBy() string { + entrypoint := []string{"ENTRYPOINT"} + cmdLine := strings.Join(e.cmd.CmdLine, " ") + if e.cmd.PrependShell { + // TODO: Support shell command here + shell := []string{"/bin/sh", "-c"} + appendedShell := append(entrypoint, shell...) + return strings.Join(append(appendedShell, cmdLine), " ") + } + return strings.Join(append(entrypoint, cmdLine), " ") +} diff --git a/pkg/commands/entrypoint_test.go b/pkg/commands/entrypoint_test.go new file mode 100644 index 000000000..0835de07e --- /dev/null +++ b/pkg/commands/entrypoint_test.go @@ -0,0 +1,61 @@ +/* +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 commands + +import ( + "github.com/GoogleCloudPlatform/k8s-container-builder/testutil" + "github.com/containers/image/manifest" + "github.com/containers/image/pkg/strslice" + "github.com/docker/docker/builder/dockerfile/instructions" + "testing" +) + +var entrypointTests = []struct { + prependShell bool + cmdLine []string + expectedCmd strslice.StrSlice +}{ + { + prependShell: true, + cmdLine: []string{"echo", "cmd1"}, + expectedCmd: strslice.StrSlice{"/bin/sh", "-c", "echo cmd1"}, + }, + { + prependShell: false, + cmdLine: []string{"echo", "cmd2"}, + expectedCmd: strslice.StrSlice{"echo", "cmd2"}, + }, +} + +func TestEntrypointExecuteCmd(t *testing.T) { + + cfg := &manifest.Schema2Config{ + Cmd: nil, + } + + for _, test := range entrypointTests { + cmd := EntrypointCommand{ + &instructions.EntrypointCommand{ + ShellDependantCmdLine: instructions.ShellDependantCmdLine{ + PrependShell: test.prependShell, + CmdLine: test.cmdLine, + }, + }, + } + err := cmd.ExecuteCommand(cfg) + testutil.CheckErrorAndDeepEqual(t, false, err, test.expectedCmd, cfg.Entrypoint) + } +} From bf47ea928b1b8288dac5b29b46a4b23636e62ede Mon Sep 17 00:00:00 2001 From: Priya Wadhwa Date: Tue, 20 Mar 2018 13:00:36 -0700 Subject: [PATCH 4/4] Integration tests for entrypoint --- .../{Dockerfile_test_cmd => Dockerfile_test_metadata} | 3 +++ .../dockerfiles/{test_cmd.yaml => test_metadata.yaml} | 1 + integration_tests/integration_test_yaml.go | 8 ++++---- pkg/commands/cmd.go | 6 ++++-- 4 files changed, 12 insertions(+), 6 deletions(-) rename integration_tests/dockerfiles/{Dockerfile_test_cmd => Dockerfile_test_metadata} (56%) rename integration_tests/dockerfiles/{test_cmd.yaml => test_metadata.yaml} (66%) diff --git a/integration_tests/dockerfiles/Dockerfile_test_cmd b/integration_tests/dockerfiles/Dockerfile_test_metadata similarity index 56% rename from integration_tests/dockerfiles/Dockerfile_test_cmd rename to integration_tests/dockerfiles/Dockerfile_test_metadata index 7b8b04999..261db4d5b 100644 --- a/integration_tests/dockerfiles/Dockerfile_test_cmd +++ b/integration_tests/dockerfiles/Dockerfile_test_metadata @@ -2,3 +2,6 @@ FROM gcr.io/distroless/base:latest CMD ["command", "one"] CMD ["command", "two"] CMD echo "hello" + +ENTRYPOINT ["execute", "something"] +ENTRYPOINT ["execute", "entrypoint"] diff --git a/integration_tests/dockerfiles/test_cmd.yaml b/integration_tests/dockerfiles/test_metadata.yaml similarity index 66% rename from integration_tests/dockerfiles/test_cmd.yaml rename to integration_tests/dockerfiles/test_metadata.yaml index c05b14824..cb0024311 100644 --- a/integration_tests/dockerfiles/test_cmd.yaml +++ b/integration_tests/dockerfiles/test_metadata.yaml @@ -1,3 +1,4 @@ schemaVersion: '2.0.0' metadataTest: cmd: ["/bin/sh", "-c", "echo \"hello\""] + entrypoint: ["execute", "entrypoint"] diff --git a/integration_tests/integration_test_yaml.go b/integration_tests/integration_test_yaml.go index d610e5146..19c5a8926 100644 --- a/integration_tests/integration_test_yaml.go +++ b/integration_tests/integration_test_yaml.go @@ -66,11 +66,11 @@ var structureTests = []struct { structureTestYamlPath: "/workspace/integration_tests/dockerfiles/test_env.yaml", }, { - description: "test cmd", - dockerfilePath: "/workspace/integration_tests/dockerfiles/Dockerfile_test_cmd", - repo: "test-cmd", + description: "test metadata", + dockerfilePath: "/workspace/integration_tests/dockerfiles/Dockerfile_test_metadata", + repo: "test-metadata", dockerBuildContext: "/workspace/integration_tests/dockerfiles/", - structureTestYamlPath: "/workspace/integration_tests/dockerfiles/test_cmd.yaml", + structureTestYamlPath: "/workspace/integration_tests/dockerfiles/test_metadata.yaml", }, } diff --git a/pkg/commands/cmd.go b/pkg/commands/cmd.go index 54e18e241..4d49234b2 100644 --- a/pkg/commands/cmd.go +++ b/pkg/commands/cmd.go @@ -53,11 +53,13 @@ func (c *CmdCommand) FilesToSnapshot() []string { // CreatedBy returns some information about the command for the image config history func (c *CmdCommand) CreatedBy() string { + cmd := []string{"CMD"} cmdLine := strings.Join(c.cmd.CmdLine, " ") if c.cmd.PrependShell { // TODO: Support shell command here shell := []string{"/bin/sh", "-c"} - return strings.Join(append(shell, cmdLine), " ") + appendedShell := append(cmd, shell...) + return strings.Join(append(appendedShell, cmdLine), " ") } - return cmdLine + return strings.Join(append(cmd, cmdLine), " ") }