Skip to content

Commit e2acca6

Browse files
author
Antonio Murdaca
committed
Move container.WaitStop, AttachWithLogs and WsAttachWithLogs to daemon service in api server
Signed-off-by: Antonio Murdaca <me@runcom.ninja>
1 parent 3697ddd commit e2acca6

File tree

4 files changed

+290
-246
lines changed

4 files changed

+290
-246
lines changed

api/server/server.go

Lines changed: 21 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,14 +1058,11 @@ func (s *Server) postContainersWait(version version.Version, w http.ResponseWrit
10581058
return fmt.Errorf("Missing parameter")
10591059
}
10601060

1061-
name := vars["name"]
1062-
cont, err := s.daemon.Get(name)
1061+
status, err := s.daemon.ContainerWait(vars["name"], -1*time.Second)
10631062
if err != nil {
10641063
return err
10651064
}
10661065

1067-
status, _ := cont.WaitStop(-1 * time.Second)
1068-
10691066
return writeJSON(w, http.StatusOK, &types.ContainerWaitResponse{
10701067
StatusCode: status,
10711068
})
@@ -1099,50 +1096,33 @@ func (s *Server) postContainersAttach(version version.Version, w http.ResponseWr
10991096
return fmt.Errorf("Missing parameter")
11001097
}
11011098

1102-
cont, err := s.daemon.Get(vars["name"])
1103-
if err != nil {
1104-
return err
1105-
}
1106-
11071099
inStream, outStream, err := hijackServer(w)
11081100
if err != nil {
11091101
return err
11101102
}
11111103
defer closeStreams(inStream, outStream)
11121104

1113-
var errStream io.Writer
1114-
11151105
if _, ok := r.Header["Upgrade"]; ok {
11161106
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")
11171107
} else {
11181108
fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
11191109
}
11201110

1121-
if !cont.Config.Tty && version.GreaterThanOrEqualTo("1.6") {
1122-
errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
1123-
outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
1124-
} else {
1125-
errStream = outStream
1126-
}
1127-
logs := boolValue(r, "logs")
1128-
stream := boolValue(r, "stream")
1129-
1130-
var stdin io.ReadCloser
1131-
var stdout, stderr io.Writer
1132-
1133-
if boolValue(r, "stdin") {
1134-
stdin = inStream
1135-
}
1136-
if boolValue(r, "stdout") {
1137-
stdout = outStream
1138-
}
1139-
if boolValue(r, "stderr") {
1140-
stderr = errStream
1111+
attachWithLogsConfig := &daemon.ContainerAttachWithLogsConfig{
1112+
InStream: inStream,
1113+
OutStream: outStream,
1114+
UseStdin: boolValue(r, "stdin"),
1115+
UseStdout: boolValue(r, "stdout"),
1116+
UseStderr: boolValue(r, "stderr"),
1117+
Logs: boolValue(r, "logs"),
1118+
Stream: boolValue(r, "stream"),
1119+
Multiplex: version.GreaterThanOrEqualTo("1.6"),
11411120
}
11421121

1143-
if err := cont.AttachWithLogs(stdin, stdout, stderr, logs, stream); err != nil {
1122+
if err := s.daemon.ContainerAttachWithLogs(vars["name"], attachWithLogsConfig); err != nil {
11441123
fmt.Fprintf(outStream, "Error attaching: %s\n", err)
11451124
}
1125+
11461126
return nil
11471127
}
11481128

@@ -1153,17 +1133,19 @@ func (s *Server) wsContainersAttach(version version.Version, w http.ResponseWrit
11531133
if vars == nil {
11541134
return fmt.Errorf("Missing parameter")
11551135
}
1156-
cont, err := s.daemon.Get(vars["name"])
1157-
if err != nil {
1158-
return err
1159-
}
11601136

11611137
h := websocket.Handler(func(ws *websocket.Conn) {
11621138
defer ws.Close()
1163-
logs := r.Form.Get("logs") != ""
1164-
stream := r.Form.Get("stream") != ""
11651139

1166-
if err := cont.AttachWithLogs(ws, ws, ws, logs, stream); err != nil {
1140+
wsAttachWithLogsConfig := &daemon.ContainerWsAttachWithLogsConfig{
1141+
InStream: ws,
1142+
OutStream: ws,
1143+
ErrStream: ws,
1144+
Logs: boolValue(r, "logs"),
1145+
Stream: boolValue(r, "stream"),
1146+
}
1147+
1148+
if err := s.daemon.ContainerWsAttachWithLogs(vars["name"], wsAttachWithLogsConfig); err != nil {
11671149
logrus.Errorf("Error attaching websocket: %s", err)
11681150
}
11691151
})

daemon/attach.go

Lines changed: 39 additions & 207 deletions
Original file line numberDiff line numberDiff line change
@@ -1,229 +1,61 @@
11
package daemon
22

33
import (
4-
"encoding/json"
54
"io"
6-
"os"
7-
"sync"
8-
"time"
95

10-
"github.com/Sirupsen/logrus"
11-
"github.com/docker/docker/pkg/jsonlog"
12-
"github.com/docker/docker/pkg/promise"
6+
"github.com/docker/docker/pkg/stdcopy"
137
)
148

15-
func (c *Container) AttachWithLogs(stdin io.ReadCloser, stdout, stderr io.Writer, logs, stream bool) error {
16-
if logs {
17-
cLog, err := c.ReadLog("json")
18-
if err != nil && os.IsNotExist(err) {
19-
// Legacy logs
20-
logrus.Debugf("Old logs format")
21-
if stdout != nil {
22-
cLog, err := c.ReadLog("stdout")
23-
if err != nil {
24-
logrus.Errorf("Error reading logs (stdout): %s", err)
25-
} else if _, err := io.Copy(stdout, cLog); err != nil {
26-
logrus.Errorf("Error streaming logs (stdout): %s", err)
27-
}
28-
}
29-
if stderr != nil {
30-
cLog, err := c.ReadLog("stderr")
31-
if err != nil {
32-
logrus.Errorf("Error reading logs (stderr): %s", err)
33-
} else if _, err := io.Copy(stderr, cLog); err != nil {
34-
logrus.Errorf("Error streaming logs (stderr): %s", err)
35-
}
36-
}
37-
} else if err != nil {
38-
logrus.Errorf("Error reading logs (json): %s", err)
39-
} else {
40-
dec := json.NewDecoder(cLog)
41-
for {
42-
l := &jsonlog.JSONLog{}
43-
44-
if err := dec.Decode(l); err == io.EOF {
45-
break
46-
} else if err != nil {
47-
logrus.Errorf("Error streaming logs: %s", err)
48-
break
49-
}
50-
if l.Stream == "stdout" && stdout != nil {
51-
io.WriteString(stdout, l.Log)
52-
}
53-
if l.Stream == "stderr" && stderr != nil {
54-
io.WriteString(stderr, l.Log)
55-
}
56-
}
57-
}
58-
}
59-
60-
//stream
61-
if stream {
62-
var stdinPipe io.ReadCloser
63-
if stdin != nil {
64-
r, w := io.Pipe()
65-
go func() {
66-
defer w.Close()
67-
defer logrus.Debugf("Closing buffered stdin pipe")
68-
io.Copy(w, stdin)
69-
}()
70-
stdinPipe = r
71-
}
72-
<-c.Attach(stdinPipe, stdout, stderr)
73-
// If we are in stdinonce mode, wait for the process to end
74-
// otherwise, simply return
75-
if c.Config.StdinOnce && !c.Config.Tty {
76-
c.WaitStop(-1 * time.Second)
77-
}
78-
}
79-
return nil
9+
type ContainerAttachWithLogsConfig struct {
10+
InStream io.ReadCloser
11+
OutStream io.Writer
12+
UseStdin, UseStdout, UseStderr bool
13+
Logs, Stream bool
14+
Multiplex bool
8015
}
8116

82-
func (c *Container) Attach(stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) chan error {
83-
return attach(&c.StreamConfig, c.Config.OpenStdin, c.Config.StdinOnce, c.Config.Tty, stdin, stdout, stderr)
84-
}
85-
86-
func attach(streamConfig *StreamConfig, openStdin, stdinOnce, tty bool, stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) chan error {
87-
var (
88-
cStdout, cStderr io.ReadCloser
89-
cStdin io.WriteCloser
90-
wg sync.WaitGroup
91-
errors = make(chan error, 3)
92-
)
93-
94-
if stdin != nil && openStdin {
95-
cStdin = streamConfig.StdinPipe()
96-
wg.Add(1)
17+
func (daemon *Daemon) ContainerAttachWithLogs(name string, c *ContainerAttachWithLogsConfig) error {
18+
container, err := daemon.Get(name)
19+
if err != nil {
20+
return err
9721
}
9822

99-
if stdout != nil {
100-
cStdout = streamConfig.StdoutPipe()
101-
wg.Add(1)
102-
}
23+
var errStream io.Writer
10324

104-
if stderr != nil {
105-
cStderr = streamConfig.StderrPipe()
106-
wg.Add(1)
25+
if !container.Config.Tty && c.Multiplex {
26+
errStream = stdcopy.NewStdWriter(c.OutStream, stdcopy.Stderr)
27+
c.OutStream = stdcopy.NewStdWriter(c.OutStream, stdcopy.Stdout)
28+
} else {
29+
errStream = c.OutStream
10730
}
10831

109-
// Connect stdin of container to the http conn.
110-
go func() {
111-
if stdin == nil || !openStdin {
112-
return
113-
}
114-
logrus.Debugf("attach: stdin: begin")
115-
defer func() {
116-
if stdinOnce && !tty {
117-
cStdin.Close()
118-
} else {
119-
// No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
120-
if cStdout != nil {
121-
cStdout.Close()
122-
}
123-
if cStderr != nil {
124-
cStderr.Close()
125-
}
126-
}
127-
wg.Done()
128-
logrus.Debugf("attach: stdin: end")
129-
}()
32+
var stdin io.ReadCloser
33+
var stdout, stderr io.Writer
13034

131-
var err error
132-
if tty {
133-
_, err = copyEscapable(cStdin, stdin)
134-
} else {
135-
_, err = io.Copy(cStdin, stdin)
136-
137-
}
138-
if err == io.ErrClosedPipe {
139-
err = nil
140-
}
141-
if err != nil {
142-
logrus.Errorf("attach: stdin: %s", err)
143-
errors <- err
144-
return
145-
}
146-
}()
147-
148-
attachStream := func(name string, stream io.Writer, streamPipe io.ReadCloser) {
149-
if stream == nil {
150-
return
151-
}
152-
defer func() {
153-
// Make sure stdin gets closed
154-
if stdin != nil {
155-
stdin.Close()
156-
}
157-
streamPipe.Close()
158-
wg.Done()
159-
logrus.Debugf("attach: %s: end", name)
160-
}()
161-
162-
logrus.Debugf("attach: %s: begin", name)
163-
_, err := io.Copy(stream, streamPipe)
164-
if err == io.ErrClosedPipe {
165-
err = nil
166-
}
167-
if err != nil {
168-
logrus.Errorf("attach: %s: %v", name, err)
169-
errors <- err
170-
}
35+
if c.UseStdin {
36+
stdin = c.InStream
37+
}
38+
if c.UseStdout {
39+
stdout = c.OutStream
40+
}
41+
if c.UseStderr {
42+
stderr = errStream
17143
}
17244

173-
go attachStream("stdout", stdout, cStdout)
174-
go attachStream("stderr", stderr, cStderr)
45+
return container.AttachWithLogs(stdin, stdout, stderr, c.Logs, c.Stream)
46+
}
17547

176-
return promise.Go(func() error {
177-
wg.Wait()
178-
close(errors)
179-
for err := range errors {
180-
if err != nil {
181-
return err
182-
}
183-
}
184-
return nil
185-
})
48+
type ContainerWsAttachWithLogsConfig struct {
49+
InStream io.ReadCloser
50+
OutStream, ErrStream io.Writer
51+
Logs, Stream bool
18652
}
18753

188-
// Code c/c from io.Copy() modified to handle escape sequence
189-
func copyEscapable(dst io.Writer, src io.ReadCloser) (written int64, err error) {
190-
buf := make([]byte, 32*1024)
191-
for {
192-
nr, er := src.Read(buf)
193-
if nr > 0 {
194-
// ---- Docker addition
195-
// char 16 is C-p
196-
if nr == 1 && buf[0] == 16 {
197-
nr, er = src.Read(buf)
198-
// char 17 is C-q
199-
if nr == 1 && buf[0] == 17 {
200-
if err := src.Close(); err != nil {
201-
return 0, err
202-
}
203-
return 0, nil
204-
}
205-
}
206-
// ---- End of docker
207-
nw, ew := dst.Write(buf[0:nr])
208-
if nw > 0 {
209-
written += int64(nw)
210-
}
211-
if ew != nil {
212-
err = ew
213-
break
214-
}
215-
if nr != nw {
216-
err = io.ErrShortWrite
217-
break
218-
}
219-
}
220-
if er == io.EOF {
221-
break
222-
}
223-
if er != nil {
224-
err = er
225-
break
226-
}
54+
func (daemon *Daemon) ContainerWsAttachWithLogs(name string, c *ContainerWsAttachWithLogsConfig) error {
55+
container, err := daemon.Get(name)
56+
if err != nil {
57+
return err
22758
}
228-
return written, err
59+
60+
return container.AttachWithLogs(c.InStream, c.OutStream, c.ErrStream, c.Logs, c.Stream)
22961
}

0 commit comments

Comments
 (0)