Remove `IsPaused` from backend interface.

Move connection hijacking logic to the daemon.

Signed-off-by: David Calavera <david.calavera@gmail.com>
This commit is contained in:
David Calavera 2015-12-16 01:41:46 -05:00
parent 52fd30079a
commit af94f941df
4 changed files with 54 additions and 37 deletions

View File

@ -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.

View File

@ -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 {

View File

@ -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

View File

@ -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,
})
)