mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Add detach event
If we attach to a running container and stream is closed afterwards, we can never be sure if the container is stopped or detached. Adding a new type of `detach` event can explicitly notify client that container is detached, so client will know that there's no need to wait for its exit code and it can move forward to next step now. Signed-off-by: Zhang Wei <zhangwei555@huawei.com>
This commit is contained in:
parent
e2528712db
commit
83ad006d47
4 changed files with 42 additions and 12 deletions
|
@ -48,6 +48,21 @@ var (
|
|||
errInvalidNetwork = fmt.Errorf("invalid network settings while building port map info")
|
||||
)
|
||||
|
||||
// AttachError represents errors of attach
|
||||
type AttachError interface {
|
||||
IsDetached() bool
|
||||
}
|
||||
|
||||
type detachError struct{}
|
||||
|
||||
func (e detachError) IsDetached() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (e detachError) Error() string {
|
||||
return "detached from container"
|
||||
}
|
||||
|
||||
// CommonContainer holds the fields for a container which are
|
||||
// applicable across all platforms supported by the daemon.
|
||||
type CommonContainer struct {
|
||||
|
@ -393,7 +408,6 @@ func AttachStreams(ctx context.Context, streamConfig *runconfig.StreamConfig, op
|
|||
_, err = copyEscapable(cStdin, stdin, keys)
|
||||
} else {
|
||||
_, err = io.Copy(cStdin, stdin)
|
||||
|
||||
}
|
||||
if err == io.ErrClosedPipe {
|
||||
err = nil
|
||||
|
@ -492,10 +506,8 @@ func copyEscapable(dst io.Writer, src io.ReadCloser, keys []byte) (written int64
|
|||
break
|
||||
}
|
||||
if i == len(keys)-1 {
|
||||
if err := src.Close(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return 0, nil
|
||||
src.Close()
|
||||
return 0, detachError{}
|
||||
}
|
||||
nr, er = src.Read(buf)
|
||||
}
|
||||
|
|
|
@ -73,9 +73,9 @@ func (daemon *Daemon) ContainerAttachRaw(prefixOrName string, stdin io.ReadClose
|
|||
return daemon.containerAttach(container, stdin, stdout, stderr, false, stream, nil)
|
||||
}
|
||||
|
||||
func (daemon *Daemon) containerAttach(container *container.Container, stdin io.ReadCloser, stdout, stderr io.Writer, logs, stream bool, keys []byte) error {
|
||||
func (daemon *Daemon) containerAttach(c *container.Container, stdin io.ReadCloser, stdout, stderr io.Writer, logs, stream bool, keys []byte) error {
|
||||
if logs {
|
||||
logDriver, err := daemon.getLogger(container)
|
||||
logDriver, err := daemon.getLogger(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ func (daemon *Daemon) containerAttach(container *container.Container, stdin io.R
|
|||
}
|
||||
}
|
||||
|
||||
daemon.LogContainerEvent(container, "attach")
|
||||
daemon.LogContainerEvent(c, "attach")
|
||||
|
||||
//stream
|
||||
if stream {
|
||||
|
@ -119,11 +119,20 @@ func (daemon *Daemon) containerAttach(container *container.Container, stdin io.R
|
|||
}()
|
||||
stdinPipe = r
|
||||
}
|
||||
<-container.Attach(stdinPipe, stdout, stderr, keys)
|
||||
err := <-c.Attach(stdinPipe, stdout, stderr, keys)
|
||||
if err != nil {
|
||||
e, ok := err.(container.AttachError)
|
||||
if ok && e.IsDetached() {
|
||||
daemon.LogContainerEvent(c, "detach")
|
||||
} else {
|
||||
logrus.Errorf("attach failed with error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// If we are in stdinonce mode, wait for the process to end
|
||||
// otherwise, simply return
|
||||
if container.Config.StdinOnce && !container.Config.Tty {
|
||||
container.WaitStop(-1 * time.Second)
|
||||
if c.Config.StdinOnce && !c.Config.Tty {
|
||||
c.WaitStop(-1 * time.Second)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -222,7 +222,11 @@ func (d *Daemon) ContainerExecStart(ctx context.Context, name string, stdin io.R
|
|||
return fmt.Errorf("context cancelled")
|
||||
case err := <-attachErr:
|
||||
if err != nil {
|
||||
return fmt.Errorf("attach failed with error: %v", err)
|
||||
e, ok := err.(container.AttachError)
|
||||
if !ok || !e.IsDetached() {
|
||||
return fmt.Errorf("attach failed with error: %v", err)
|
||||
}
|
||||
d.LogContainerEvent(c, "detach")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -135,6 +135,11 @@ func (s *DockerSuite) TestRunAttachDetach(c *check.C) {
|
|||
|
||||
running := inspectField(c, name, "State.Running")
|
||||
c.Assert(running, checker.Equals, "true", check.Commentf("expected container to still be running"))
|
||||
|
||||
out, _ = dockerCmd(c, "events", "--since=0", "--until", daemonUnixTime(c), "-f", "container="+name)
|
||||
// attach and detach event should be monitored
|
||||
c.Assert(out, checker.Contains, "attach")
|
||||
c.Assert(out, checker.Contains, "detach")
|
||||
}
|
||||
|
||||
// TestRunDetach checks attaching and detaching with the escape sequence specified via flags.
|
||||
|
|
Loading…
Reference in a new issue