From 8582466e4f3a9af1df085ad8846f8e0538e864e1 Mon Sep 17 00:00:00 2001 From: baude Date: Sat, 10 Feb 2018 11:57:05 -0600 Subject: [PATCH] Honor ENTRYPOINT in image When an image has an ENTRYPOINT defined, we should be honoring it. The problem is described in issue #321. Also, added buildah binary to test runtimes for testing entrypoint and will also allow us to test podman build as well. Signed-off-by: baude --- Dockerfile | 9 +++ Dockerfile.CentOS | 9 +++ Dockerfile.Fedora | 9 +++ cmd/podman/common.go | 2 +- cmd/podman/create.go | 31 ++++++---- cmd/podman/inspect.go | 3 +- test/e2e/libpod_suite_test.go | 11 ++++ test/e2e/run_entrypoint_test.go | 100 ++++++++++++++++++++++++++++++++ 8 files changed, 161 insertions(+), 13 deletions(-) create mode 100644 test/e2e/run_entrypoint_test.go diff --git a/Dockerfile b/Dockerfile index 941a7e0d3b..6a29269b36 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,6 +13,7 @@ RUN apt-get update && apt-get install -y \ e2fslibs-dev \ gawk \ gettext \ + go-md2man \ iptables \ pkg-config \ libaio-dev \ @@ -96,6 +97,14 @@ RUN set -x \ && cp "$GOPATH"/bin/crictl /usr/bin/ \ && rm -rf "$GOPATH" +# Install buildah +RUN set -x \ + && export GOPATH=/go \ + && git clone https://github.com/projectatomic/buildah "$GOPATH/src/github.com/projectatomic/buildah" \ + && cd "$GOPATH/src/github.com/projectatomic/buildah" \ + && make \ + && make install + # Install ginkgo RUN set -x \ && export GOPATH=/go \ diff --git a/Dockerfile.CentOS b/Dockerfile.CentOS index 217837ce05..cecb354ba2 100644 --- a/Dockerfile.CentOS +++ b/Dockerfile.CentOS @@ -9,6 +9,7 @@ RUN yum -y install btrfs-progs-devel \ glib2-devel \ gnupg \ golang \ + golang-github-cpuguy83-go-md2man \ gpgme-devel \ libassuan-devel \ libseccomp-devel \ @@ -34,6 +35,14 @@ RUN set -x \ && cp bin/* /usr/libexec/cni \ && rm -rf "$GOPATH" +# Install buildah +RUN set -x \ + && export GOPATH=/go \ + && git clone https://github.com/projectatomic/buildah "$GOPATH/src/github.com/projectatomic/buildah" \ + && cd "$GOPATH/src/github.com/projectatomic/buildah" \ + && make \ + && make install + # Install ginkgo RUN set -x \ && export GOPATH=/go \ diff --git a/Dockerfile.Fedora b/Dockerfile.Fedora index f15734f05e..aa10a054f6 100644 --- a/Dockerfile.Fedora +++ b/Dockerfile.Fedora @@ -10,6 +10,7 @@ RUN dnf -y install btrfs-progs-devel \ glib2-devel \ gnupg \ golang \ + golang-github-cpuguy83-go-md2man \ gpgme-devel \ libassuan-devel \ libseccomp-devel \ @@ -36,6 +37,14 @@ RUN set -x \ && cp bin/* /usr/libexec/cni \ && rm -rf "$GOPATH" +# Install buildah +RUN set -x \ + && export GOPATH=/go \ + && git clone https://github.com/projectatomic/buildah "$GOPATH/src/github.com/projectatomic/buildah" \ + && cd "$GOPATH/src/github.com/projectatomic/buildah" \ + && make \ + && make install + # Install ginkgo RUN set -x \ && export GOPATH=/go \ diff --git a/cmd/podman/common.go b/cmd/podman/common.go index e0aaf52c08..657535e63e 100644 --- a/cmd/podman/common.go +++ b/cmd/podman/common.go @@ -173,7 +173,7 @@ var createFlags = []cli.Flag{ Name: "dns-search", Usage: "Set custom DNS search domains", }, - cli.StringFlag{ + cli.StringSliceFlag{ Name: "entrypoint", Usage: "Overwrite the default ENTRYPOINT of the image", }, diff --git a/cmd/podman/create.go b/cmd/podman/create.go index 340c036cc1..f847b2d227 100644 --- a/cmd/podman/create.go +++ b/cmd/podman/create.go @@ -81,7 +81,7 @@ type createConfig struct { DNSOpt []string //dns-opt DNSSearch []string //dns-search DNSServers []string //dns - Entrypoint string //entrypoint + Entrypoint []string //entrypoint Env map[string]string //env ExposedPorts map[nat.Port]struct{} GroupAdd []uint32 // group-add @@ -419,14 +419,14 @@ func imageData(c *cli.Context, runtime *libpod.Runtime, image string) (string, s // Parses CLI options related to container creation into a config which can be // parsed into an OCI runtime spec func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime, imageName string, data *inspect.ImageData) (*createConfig, error) { - var command []string + var inputCommand, command []string var memoryLimit, memoryReservation, memorySwap, memoryKernel int64 var blkioWeight uint16 imageID := data.ID if len(c.Args()) > 1 { - command = c.Args()[1:] + inputCommand = c.Args()[1:] } sysctl, err := validateSysctl(c.StringSlice("sysctl")) @@ -567,15 +567,24 @@ func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime, imageName string, workDir = data.Config.WorkingDir } - // COMMAND - if len(command) == 0 { - command = data.Config.Cmd - } - // ENTRYPOINT - entrypoint := c.String("entrypoint") - if entrypoint == "" { - entrypoint = strings.Join(data.Config.Entrypoint, " ") + // User input entrypoint takes priority over image entrypoint + entrypoint := c.StringSlice("entrypoint") + if len(entrypoint) == 0 { + entrypoint = data.Config.Entrypoint + } + + // Build the command + // If we have an entry point, it goes first + if len(entrypoint) > 0 { + command = entrypoint + } + if len(inputCommand) > 0 { + // User command overrides data CMD + command = append(command, inputCommand...) + } else if len(data.Config.Cmd) > 0 && !c.IsSet("entrypoint") { + // If not user command, add CMD + command = append(command, data.Config.Cmd...) } // EXPOSED PORTS diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go index ba7b17ed71..84107f3dba 100644 --- a/cmd/podman/inspect.go +++ b/cmd/podman/inspect.go @@ -2,6 +2,7 @@ package main import ( "encoding/json" + "strings" specs "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" @@ -223,7 +224,7 @@ func getCtrInspectInfo(ctr *libpod.Container, ctrInspectData *inspect.ContainerI OpenStdin: config.Stdin, StopSignal: config.StopSignal, Cmd: config.Spec.Process.Args, - Entrypoint: createArtifact.Entrypoint, + Entrypoint: strings.Join(createArtifact.Entrypoint, " "), }, } return data, nil diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go index b8e650e308..afe91134e1 100644 --- a/test/e2e/libpod_suite_test.go +++ b/test/e2e/libpod_suite_test.go @@ -449,3 +449,14 @@ func (p *PodmanTest) GetContainerStatus() string { session.WaitWithDefaultTimeout() return session.OutputToString() } + +// BuildImage uses podman build and buildah to build an image +// called imageName based on a string dockerfile +func (p *PodmanTest) BuildImage(dockerfile, imageName string) { + dockerfilePath := filepath.Join(p.TempDir, "Dockerfile") + err := ioutil.WriteFile(dockerfilePath, []byte(dockerfile), 0755) + Expect(err).To(BeNil()) + session := p.Podman([]string{"build", "-t", imageName, "--file", dockerfilePath, p.TempDir}) + session.Wait(120) + Expect(session.ExitCode()).To(Equal(0)) +} diff --git a/test/e2e/run_entrypoint_test.go b/test/e2e/run_entrypoint_test.go new file mode 100644 index 0000000000..2ae2829679 --- /dev/null +++ b/test/e2e/run_entrypoint_test.go @@ -0,0 +1,100 @@ +package integration + +import ( + "os" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Podman run entrypoint", func() { + var ( + tempdir string + err error + podmanTest PodmanTest + ) + + BeforeEach(func() { + tempdir, err = CreateTempDirInTempDir() + if err != nil { + os.Exit(1) + } + podmanTest = PodmanCreate(tempdir) + podmanTest.RestoreArtifact(ALPINE) + }) + + AfterEach(func() { + podmanTest.Cleanup() + + }) + + It("podman run entrypoint", func() { + dockerfile := `FROM docker.io/library/alpine:latest +ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] +` + podmanTest.BuildImage(dockerfile, "foobar.com/entrypoint:latest") + session := podmanTest.Podman([]string{"run", "foobar.com/entrypoint:latest"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(len(session.OutputToStringArray())).To(Equal(3)) + }) + + It("podman run entrypoint with cmd", func() { + dockerfile := `FROM docker.io/library/alpine:latest +CMD [ "-v"] +ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] +` + podmanTest.BuildImage(dockerfile, "foobar.com/entrypoint:latest") + session := podmanTest.Podman([]string{"run", "foobar.com/entrypoint:latest"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(len(session.OutputToStringArray())).To(Equal(5)) + }) + + It("podman run entrypoint with user cmd overrides image cmd", func() { + dockerfile := `FROM docker.io/library/alpine:latest +CMD [ "-v"] +ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] +` + podmanTest.BuildImage(dockerfile, "foobar.com/entrypoint:latest") + session := podmanTest.Podman([]string{"run", "foobar.com/entrypoint:latest", "-i"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(len(session.OutputToStringArray())).To(Equal(6)) + }) + + It("podman run entrypoint with user cmd no image cmd", func() { + dockerfile := `FROM docker.io/library/alpine:latest +ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] +` + podmanTest.BuildImage(dockerfile, "foobar.com/entrypoint:latest") + session := podmanTest.Podman([]string{"run", "foobar.com/entrypoint:latest", "-i"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(len(session.OutputToStringArray())).To(Equal(6)) + }) + + It("podman run user entrypoint overrides image entrypoint and image cmd", func() { + dockerfile := `FROM docker.io/library/alpine:latest +CMD ["-i"] +ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] +` + podmanTest.BuildImage(dockerfile, "foobar.com/entrypoint:latest") + session := podmanTest.Podman([]string{"run", "--entrypoint=uname", "foobar.com/entrypoint:latest"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.LineInOuputStartsWith("Linux")).To(BeTrue()) + }) + + It("podman run user entrypoint with command overrides image entrypoint and image cmd", func() { + dockerfile := `FROM docker.io/library/alpine:latest +CMD ["-i"] +ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] +` + podmanTest.BuildImage(dockerfile, "foobar.com/entrypoint:latest") + session := podmanTest.Podman([]string{"run", "--entrypoint=uname", "foobar.com/entrypoint:latest", "-r"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.LineInOuputStartsWith("Linux")).To(BeFalse()) + }) +})