Ensure that exec errors write exit codes to the DB

In local Podman, the frontend interprets the error and exit code
given by the Exec API to determine the appropriate exit code to
set for Podman itself; special cases like a missing executable
receive special exit codes.

Exec for the remote API, however, has to do this inside Libpod
itself, as Libpod will be directly queried (via the Inspect API
for exec sessions) to get the exit code. This was done correctly
when the exec session started properly, but we did not properly
handle cases where the OCI runtime fails before the exec session
can properly start. Making two error returns that would otherwise
not set exit code actually do so should resolve the issue.

Fixes #6893

Signed-off-by: Matthew Heon <matthew.heon@pm.me>
This commit is contained in:
Matthew Heon 2020-08-05 13:48:01 -04:00
parent 7a15be546a
commit 7a64ce35db
3 changed files with 23 additions and 3 deletions

View File

@ -415,6 +415,13 @@ func (c *Container) ExecHTTPStartAndAttach(sessionID string, httpCon net.Conn, h
execOpts, err := prepareForExec(c, session) execOpts, err := prepareForExec(c, session)
if err != nil { if err != nil {
session.State = define.ExecStateStopped
session.ExitCode = define.ExecErrorCodeGeneric
if err := c.save(); err != nil {
logrus.Errorf("Error saving container %s exec session %s after failure to prepare: %v", err, c.ID(), session.ID())
}
return err return err
} }
@ -427,6 +434,13 @@ func (c *Container) ExecHTTPStartAndAttach(sessionID string, httpCon net.Conn, h
pid, attachChan, err := c.ociRuntime.ExecContainerHTTP(c, session.ID(), execOpts, httpCon, httpBuf, streams, cancel) pid, attachChan, err := c.ociRuntime.ExecContainerHTTP(c, session.ID(), execOpts, httpCon, httpBuf, streams, cancel)
if err != nil { if err != nil {
session.State = define.ExecStateStopped
session.ExitCode = define.TranslateExecErrorToExitCode(define.ExecErrorCodeGeneric, err)
if err := c.save(); err != nil {
logrus.Errorf("Error saving container %s exec session %s after failure to start: %v", err, c.ID(), session.ID())
}
return err return err
} }

View File

@ -210,7 +210,6 @@ var _ = Describe("Podman exec", func() {
}) })
It("podman exec missing working directory test", func() { It("podman exec missing working directory test", func() {
Skip(v2remotefail)
setup := podmanTest.RunTopContainer("test1") setup := podmanTest.RunTopContainer("test1")
setup.WaitWithDefaultTimeout() setup.WaitWithDefaultTimeout()
Expect(setup.ExitCode()).To(Equal(0)) Expect(setup.ExitCode()).To(Equal(0))
@ -225,7 +224,6 @@ var _ = Describe("Podman exec", func() {
}) })
It("podman exec cannot be invoked", func() { It("podman exec cannot be invoked", func() {
Skip(v2remotefail)
setup := podmanTest.RunTopContainer("test1") setup := podmanTest.RunTopContainer("test1")
setup.WaitWithDefaultTimeout() setup.WaitWithDefaultTimeout()
Expect(setup.ExitCode()).To(Equal(0)) Expect(setup.ExitCode()).To(Equal(0))
@ -236,7 +234,6 @@ var _ = Describe("Podman exec", func() {
}) })
It("podman exec command not found", func() { It("podman exec command not found", func() {
Skip(v2remotefail)
setup := podmanTest.RunTopContainer("test1") setup := podmanTest.RunTopContainer("test1")
setup.WaitWithDefaultTimeout() setup.WaitWithDefaultTimeout()
Expect(setup.ExitCode()).To(Equal(0)) Expect(setup.ExitCode()).To(Equal(0))

View File

@ -19,6 +19,15 @@ load helpers
run_podman exec $cid sh -c "cat /$rand_filename" run_podman exec $cid sh -c "cat /$rand_filename"
is "$output" "$rand_content" "Can exec and see file in running container" is "$output" "$rand_content" "Can exec and see file in running container"
# Specially defined situations: exec a dir, or no such command.
# We don't check the full error message because runc & crun differ.
run_podman 126 exec $cid /etc
is "$output" ".*permission denied" "podman exec /etc"
run_podman 127 exec $cid /no/such/command
is "$output" ".*such file or dir" "podman exec /no/such/command"
# Done
run_podman exec $cid rm -f /$rand_filename run_podman exec $cid rm -f /$rand_filename
run_podman wait $cid run_podman wait $cid