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 <yangshukui@huawei.com>
This commit is contained in:
Shukui Yang 2017-05-18 12:12:37 +08:00
parent dee8e6ab2d
commit f9dc3337f9
1 changed files with 29 additions and 9 deletions

View File

@ -8,6 +8,7 @@ import (
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/docker/docker/pkg/signal" "github.com/docker/docker/pkg/signal"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -22,6 +23,20 @@ type attachOptions struct {
container string 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` // NewAttachCommand creates a new cobra.Command for `docker attach`
func NewAttachCommand(dockerCli *command.DockerCli) *cobra.Command { func NewAttachCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts attachOptions var opts attachOptions
@ -47,19 +62,11 @@ func runAttach(dockerCli *command.DockerCli, opts *attachOptions) error {
ctx := context.Background() ctx := context.Background()
client := dockerCli.Client() client := dockerCli.Client()
c, err := client.ContainerInspect(ctx, opts.container) c, err := inspectContainerAndCheckState(ctx, client, opts.container)
if err != nil { if err != nil {
return err 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 { if err := dockerCli.In().CheckTty(!opts.noStdin, c.Config.Tty); err != nil {
return err return err
} }
@ -95,6 +102,19 @@ func runAttach(dockerCli *command.DockerCli, opts *attachOptions) error {
} }
defer resp.Close() 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() { if c.Config.Tty && dockerCli.Out().IsTerminal() {
height, width := dockerCli.Out().GetTtySize() height, width := dockerCli.Out().GetTtySize()
// To handle the case where a user repeatedly attaches/detaches without resizing their // To handle the case where a user repeatedly attaches/detaches without resizing their