From f9dc3337f9dd3b02cb4fb888b6237c75ebdd644b Mon Sep 17 00:00:00 2001 From: Shukui Yang Date: Thu, 18 May 2017 12:12:37 +0800 Subject: [PATCH] Recheck the container's state to avoid attach block. If use docker attach command to attach to a stop container, it will return "You cannot attach to a stopped container" error, it's ok, but when attach to a running container, it(docker attach) use inspect to check the container's state, if it pass the state check on the client side, and then the container is stopped, docker attach command still attach to the container and not exit. Signed-off-by: Shukui Yang --- cli/command/container/attach.go | 38 +++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/cli/command/container/attach.go b/cli/command/container/attach.go index f86b33a8ca..39a59e3926 100644 --- a/cli/command/container/attach.go +++ b/cli/command/container/attach.go @@ -8,6 +8,7 @@ import ( "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" "github.com/docker/docker/api/types" + "github.com/docker/docker/client" "github.com/docker/docker/pkg/signal" "github.com/pkg/errors" "github.com/spf13/cobra" @@ -22,6 +23,20 @@ type attachOptions struct { container string } +func inspectContainerAndCheckState(ctx context.Context, cli client.APIClient, args string) (*types.ContainerJSON, error) { + c, err := cli.ContainerInspect(ctx, args) + if err != nil { + return nil, err + } + if !c.State.Running { + return nil, errors.New("You cannot attach to a stopped container, start it first") + } + if c.State.Paused { + return nil, errors.New("You cannot attach to a paused container, unpause it first") + } + return &c, nil +} + // NewAttachCommand creates a new cobra.Command for `docker attach` func NewAttachCommand(dockerCli *command.DockerCli) *cobra.Command { var opts attachOptions @@ -47,19 +62,11 @@ func runAttach(dockerCli *command.DockerCli, opts *attachOptions) error { ctx := context.Background() client := dockerCli.Client() - c, err := client.ContainerInspect(ctx, opts.container) + c, err := inspectContainerAndCheckState(ctx, client, opts.container) if err != nil { return err } - if !c.State.Running { - return errors.New("You cannot attach to a stopped container, start it first") - } - - if c.State.Paused { - return errors.New("You cannot attach to a paused container, unpause it first") - } - if err := dockerCli.In().CheckTty(!opts.noStdin, c.Config.Tty); err != nil { return err } @@ -95,6 +102,19 @@ func runAttach(dockerCli *command.DockerCli, opts *attachOptions) error { } defer resp.Close() + // If use docker attach command to attach to a stop container, it will return + // "You cannot attach to a stopped container" error, it's ok, but when + // attach to a running container, it(docker attach) use inspect to check + // the container's state, if it pass the state check on the client side, + // and then the container is stopped, docker attach command still attach to + // the container and not exit. + // + // Recheck the container's state to avoid attach block. + _, err = inspectContainerAndCheckState(ctx, client, opts.container) + if err != nil { + return err + } + if c.Config.Tty && dockerCli.Out().IsTerminal() { height, width := dockerCli.Out().GetTtySize() // To handle the case where a user repeatedly attaches/detaches without resizing their