Преглед на файлове

Remove `IsPaused` from backend interface.

Move connection hijacking logic to the daemon.

Signed-off-by: David Calavera <david.calavera@gmail.com>
David Calavera преди 9 години
родител
ревизия
af94f941df
променени са 4 файла, в които са добавени 54 реда и са изтрити 37 реда
  1. 0 1
      api/server/router/container/backend.go
  2. 4 26
      api/server/router/container/container_routes.go
  3. 41 10
      daemon/attach.go
  4. 9 0
      errors/server.go

+ 0 - 1
api/server/router/container/backend.go

@@ -44,7 +44,6 @@ type stateBackend interface {
 	ContainerUnpause(name string) error
 	ContainerWait(name string, timeout time.Duration) (int, error)
 	Exists(id string) bool
-	IsPaused(id string) bool
 }
 
 // monitorBackend includes functions to implement to provide containers monitoring functionality.

+ 4 - 26
api/server/router/container/container_routes.go

@@ -400,29 +400,11 @@ func (s *containerRouter) postContainersAttach(ctx context.Context, w http.Respo
 	}
 	containerName := vars["name"]
 
-	if !s.backend.Exists(containerName) {
-		return derr.ErrorCodeNoSuchContainer.WithArgs(containerName)
-	}
-
-	if s.backend.IsPaused(containerName) {
-		return derr.ErrorCodePausedContainer.WithArgs(containerName)
-	}
-
-	inStream, outStream, err := httputils.HijackConnection(w)
-	if err != nil {
-		return err
-	}
-	defer httputils.CloseStreams(inStream, outStream)
-
-	if _, ok := r.Header["Upgrade"]; ok {
-		fmt.Fprintf(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n")
-	} else {
-		fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
-	}
+	_, upgrade := r.Header["Upgrade"]
 
 	attachWithLogsConfig := &daemon.ContainerAttachWithLogsConfig{
-		InStream:  inStream,
-		OutStream: outStream,
+		Hijacker:  w.(http.Hijacker),
+		Upgrade:   upgrade,
 		UseStdin:  httputils.BoolValue(r, "stdin"),
 		UseStdout: httputils.BoolValue(r, "stdout"),
 		UseStderr: httputils.BoolValue(r, "stderr"),
@@ -430,11 +412,7 @@ func (s *containerRouter) postContainersAttach(ctx context.Context, w http.Respo
 		Stream:    httputils.BoolValue(r, "stream"),
 	}
 
-	if err := s.backend.ContainerAttachWithLogs(containerName, attachWithLogsConfig); err != nil {
-		fmt.Fprintf(outStream, "Error attaching: %s\n", err)
-	}
-
-	return nil
+	return s.backend.ContainerAttachWithLogs(containerName, attachWithLogsConfig)
 }
 
 func (s *containerRouter) wsContainersAttach(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {

+ 41 - 10
daemon/attach.go

@@ -1,53 +1,84 @@
 package daemon
 
 import (
+	"fmt"
 	"io"
+	"net/http"
 	"time"
 
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon/logger"
+	derr "github.com/docker/docker/errors"
 	"github.com/docker/docker/pkg/stdcopy"
 )
 
 // ContainerAttachWithLogsConfig holds the streams to use when connecting to a container to view logs.
 type ContainerAttachWithLogsConfig struct {
-	InStream                       io.ReadCloser
-	OutStream                      io.Writer
-	UseStdin, UseStdout, UseStderr bool
-	Logs, Stream                   bool
+	Hijacker  http.Hijacker
+	Upgrade   bool
+	UseStdin  bool
+	UseStdout bool
+	UseStderr bool
+	Logs      bool
+	Stream    bool
 }
 
 // ContainerAttachWithLogs attaches to logs according to the config passed in. See ContainerAttachWithLogsConfig.
 func (daemon *Daemon) ContainerAttachWithLogs(prefixOrName string, c *ContainerAttachWithLogsConfig) error {
+	if c.Hijacker == nil {
+		return derr.ErrorCodeNoHijackConnection.WithArgs(prefixOrName)
+	}
 	container, err := daemon.GetContainer(prefixOrName)
+	if err != nil {
+		return derr.ErrorCodeNoSuchContainer.WithArgs(prefixOrName)
+	}
+	if container.IsPaused() {
+		return derr.ErrorCodePausedContainer.WithArgs(prefixOrName)
+	}
+
+	conn, _, err := c.Hijacker.Hijack()
 	if err != nil {
 		return err
 	}
+	defer conn.Close()
+	// Flush the options to make sure the client sets the raw mode
+	conn.Write([]byte{})
+	inStream := conn.(io.ReadCloser)
+	outStream := conn.(io.Writer)
+
+	if c.Upgrade {
+		fmt.Fprintf(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n")
+	} else {
+		fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
+	}
 
 	var errStream io.Writer
 
 	if !container.Config.Tty {
-		errStream = stdcopy.NewStdWriter(c.OutStream, stdcopy.Stderr)
-		c.OutStream = stdcopy.NewStdWriter(c.OutStream, stdcopy.Stdout)
+		errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
+		outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
 	} else {
-		errStream = c.OutStream
+		errStream = outStream
 	}
 
 	var stdin io.ReadCloser
 	var stdout, stderr io.Writer
 
 	if c.UseStdin {
-		stdin = c.InStream
+		stdin = inStream
 	}
 	if c.UseStdout {
-		stdout = c.OutStream
+		stdout = outStream
 	}
 	if c.UseStderr {
 		stderr = errStream
 	}
 
-	return daemon.attachWithLogs(container, stdin, stdout, stderr, c.Logs, c.Stream)
+	if err := daemon.attachWithLogs(container, stdin, stdout, stderr, c.Logs, c.Stream); err != nil {
+		fmt.Fprintf(outStream, "Error attaching: %s\n", err)
+	}
+	return nil
 }
 
 // ContainerWsAttachWithLogsConfig attach with websockets, since all

+ 9 - 0
errors/server.go

@@ -33,4 +33,13 @@ var (
 		Description:    "Docker's networking stack is disabled for this platform",
 		HTTPStatusCode: http.StatusNotFound,
 	})
+
+	// ErrorCodeNoHijackConnection is generated when a request tries to attach to a container
+	// but the connection to hijack is not provided.
+	ErrorCodeNoHijackConnection = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "HIJACK_CONNECTION_MISSING",
+		Message:        "error attaching to container %s, hijack connection missing",
+		Description:    "The caller didn't provide a connection to hijack",
+		HTTPStatusCode: http.StatusBadRequest,
+	})
 )