diff --git a/components/cli/cli/command/container/attach.go b/components/cli/cli/command/container/attach.go index dca84d5ddb..6e4628d95d 100644 --- a/components/cli/cli/command/container/attach.go +++ b/components/cli/cli/command/container/attach.go @@ -1,14 +1,12 @@ package container import ( - "fmt" "io" "net/http/httputil" "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/container" "github.com/docker/docker/client" "github.com/docker/docker/pkg/signal" "github.com/pkg/errors" @@ -68,9 +66,6 @@ func runAttach(dockerCli command.Cli, opts *attachOptions) error { ctx := context.Background() client := dockerCli.Client() - // request channel to wait for client - resultC, errC := client.ContainerWait(ctx, opts.container, "") - c, err := inspectContainerAndCheckState(ctx, client, opts.container) if err != nil { return err @@ -145,24 +140,7 @@ func runAttach(dockerCli command.Cli, opts *attachOptions) error { if errAttach != nil { return errAttach } - - return getExitStatus(errC, resultC) -} - -func getExitStatus(errC <-chan error, resultC <-chan container.ContainerWaitOKBody) error { - select { - case result := <-resultC: - if result.Error != nil { - return fmt.Errorf(result.Error.Message) - } - if result.StatusCode != 0 { - return cli.StatusError{StatusCode: int(result.StatusCode)} - } - case err := <-errC: - return err - } - - return nil + return getExitStatus(ctx, dockerCli.Client(), opts.container) } func resizeTTY(ctx context.Context, dockerCli command.Cli, containerID string) { @@ -179,3 +157,19 @@ func resizeTTY(ctx context.Context, dockerCli command.Cli, containerID string) { logrus.Debugf("Error monitoring TTY size: %s", err) } } + +func getExitStatus(ctx context.Context, apiclient client.ContainerAPIClient, containerID string) error { + container, err := apiclient.ContainerInspect(ctx, containerID) + if err != nil { + // If we can't connect, then the daemon probably died. + if !client.IsErrConnectionFailed(err) { + return err + } + return cli.StatusError{StatusCode: -1} + } + status := container.State.ExitCode + if status != 0 { + return cli.StatusError{StatusCode: status} + } + return nil +} diff --git a/components/cli/cli/command/container/attach_test.go b/components/cli/cli/command/container/attach_test.go index 1c305aa7a1..1ca775c6d5 100644 --- a/components/cli/cli/command/container/attach_test.go +++ b/components/cli/cli/command/container/attach_test.go @@ -1,7 +1,6 @@ package container import ( - "fmt" "io/ioutil" "testing" @@ -9,9 +8,9 @@ import ( "github.com/docker/cli/internal/test" "github.com/docker/cli/internal/test/testutil" "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/container" "github.com/pkg/errors" "github.com/stretchr/testify/assert" + "golang.org/x/net/context" ) func TestNewAttachCommandErrors(t *testing.T) { @@ -79,50 +78,40 @@ func TestNewAttachCommandErrors(t *testing.T) { } func TestGetExitStatus(t *testing.T) { - var ( - expectedErr = fmt.Errorf("unexpected error") - errC = make(chan error, 1) - resultC = make(chan container.ContainerWaitOKBody, 1) - ) + containerID := "the exec id" + expecatedErr := errors.New("unexpected error") testcases := []struct { - result *container.ContainerWaitOKBody - err error + inspectError error + exitCode int expectedError error }{ { - result: &container.ContainerWaitOKBody{ - StatusCode: 0, - }, + inspectError: nil, + exitCode: 0, }, { - err: expectedErr, - expectedError: expectedErr, + inspectError: expecatedErr, + expectedError: expecatedErr, }, { - result: &container.ContainerWaitOKBody{ - Error: &container.ContainerWaitOKBodyError{ - expectedErr.Error(), - }, - }, - expectedError: expectedErr, - }, - { - result: &container.ContainerWaitOKBody{ - StatusCode: 15, - }, + exitCode: 15, expectedError: cli.StatusError{StatusCode: 15}, }, } for _, testcase := range testcases { - if testcase.err != nil { - errC <- testcase.err + client := &fakeClient{ + inspectFunc: func(id string) (types.ContainerJSON, error) { + assert.Equal(t, containerID, id) + return types.ContainerJSON{ + ContainerJSONBase: &types.ContainerJSONBase{ + State: &types.ContainerState{ExitCode: testcase.exitCode}, + }, + }, testcase.inspectError + }, } - if testcase.result != nil { - resultC <- *testcase.result - } - err := getExitStatus(errC, resultC) + err := getExitStatus(context.Background(), client, containerID) assert.Equal(t, testcase.expectedError, err) } } diff --git a/components/cli/e2e/container/attach_test.go b/components/cli/e2e/container/attach_test.go deleted file mode 100644 index 3e7d0ed244..0000000000 --- a/components/cli/e2e/container/attach_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package container - -import ( - "strings" - "testing" - - "github.com/docker/cli/e2e/internal/fixtures" - "github.com/gotestyourself/gotestyourself/icmd" -) - -func TestAttachExitCode(t *testing.T) { - containerID := runBackgroundContainsWithExitCode(t, 21) - - result := icmd.RunCmd( - icmd.Command("docker", "attach", containerID), - withStdinNewline) - - result.Assert(t, icmd.Expected{ExitCode: 21}) -} - -func runBackgroundContainsWithExitCode(t *testing.T, exitcode int) string { - result := icmd.RunCmd(shell(t, - "docker run -d -i --rm %s sh -c 'read; exit %d'", fixtures.AlpineImage, exitcode)) - result.Assert(t, icmd.Success) - return strings.TrimSpace(result.Stdout()) -} - -func withStdinNewline(cmd *icmd.Cmd) { - cmd.Stdin = strings.NewReader("\n") -}