Skip to content

Commit

Permalink
attach: wait for exit code from ContainerWait
Browse files Browse the repository at this point in the history
Such as with `docker run`, if a user CTRL-Cs while attached to a
container, we should forward the signal and wait for the exit from
`ContainerWait`, instead of just returning.

Signed-off-by: Laura Brehm <[email protected]>
  • Loading branch information
laurazard committed Jul 25, 2024
1 parent 788e996 commit f4bb939
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 5 deletions.
6 changes: 2 additions & 4 deletions cli/command/container/attach.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ func RunAttach(ctx context.Context, dockerCLI command.Cli, containerID string, o
apiClient := dockerCLI.Client()

// request channel to wait for client
resultC, errC := apiClient.ContainerWait(ctx, containerID, "")
waitCtx := context.WithoutCancel(ctx)
resultC, errC := apiClient.ContainerWait(waitCtx, containerID, "")

c, err := inspectContainerAndCheckState(ctx, apiClient, containerID)
if err != nil {
Expand Down Expand Up @@ -163,9 +164,6 @@ func getExitStatus(errC <-chan error, resultC <-chan container.WaitResponse) err
return cli.StatusError{StatusCode: int(result.StatusCode)}
}
case err := <-errC:
if errors.Is(err, context.Canceled) {
return nil
}
return err
}

Expand Down
5 changes: 4 additions & 1 deletion cli/command/container/attach_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,11 @@ func TestGetExitStatus(t *testing.T) {
expectedError: cli.StatusError{StatusCode: 15},
},
{
result: &container.WaitResponse{
StatusCode: 130,
},
err: context.Canceled,
expectedError: nil,
expectedError: cli.StatusError{StatusCode: 130},
},
}

Expand Down
22 changes: 22 additions & 0 deletions e2e/container/attach_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,28 @@ func TestAttachInterrupt(t *testing.T) {
time.Sleep(500 * time.Millisecond)
c.Process.Signal(os.Interrupt)

_ = c.Wait()
assert.Equal(t, c.ProcessState.ExitCode(), 130)
assert.Equal(t, d.String(), "")
}

func TestAttachInterruptWithoutStdin(t *testing.T) {
result := icmd.RunCommand("docker", "run", "-dit", fixtures.AlpineImage, "sh", "-c", "sleep 5")
result.Assert(t, icmd.Success)
containerID := strings.TrimSpace(result.Stdout())

// run it as such so we can signal it later
c := exec.Command("docker", "attach", containerID)
d := bytes.Buffer{}
c.Stdout = &d
c.Stderr = &d
_, err := pty.Start(c)
assert.NilError(t, err)

// have to wait a bit to give time for the command to execute/print
time.Sleep(500 * time.Millisecond)
c.Process.Signal(os.Interrupt)

_ = c.Wait()
assert.Equal(t, c.ProcessState.ExitCode(), 0)
assert.Equal(t, d.String(), "")
Expand Down

0 comments on commit f4bb939

Please sign in to comment.