Skip to content
This repository was archived by the owner on Feb 8, 2021. It is now read-only.

Commit c2496d9

Browse files
author
Solomon Hykes
committed
Move Server.ContainerAttach to Daemon.ContainerAttach
This is part of an effort to break apart the legacy server package. Help wanted! Docker-DCO-1.1-Signed-off-by: Solomon Hykes <solomon@docker.com> (github: shykes)
1 parent 4949e07 commit c2496d9

File tree

5 files changed

+123
-101
lines changed

5 files changed

+123
-101
lines changed

builder/builder.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,11 @@ func (b *buildFile) run(c *daemon.Container) error {
683683
var errCh chan error
684684
if b.verbose {
685685
errCh = utils.Go(func() error {
686+
// FIXME: call the 'attach' job so that daemon.Attach can be made private
687+
//
688+
// FIXME (LK4D4): Also, maybe makes sense to call "logs" job, it is like attach
689+
// but without hijacking for stdin. Also, with attach there can be race
690+
// condition because of some output already was printed before it.
686691
return <-b.daemon.Attach(c, nil, nil, b.outStream, b.errStream)
687692
})
688693
}

daemon/attach.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,122 @@
11
package daemon
22

33
import (
4+
"encoding/json"
5+
"fmt"
46
"io"
7+
"os"
8+
"time"
59

10+
"github.com/docker/docker/engine"
611
"github.com/docker/docker/utils"
712
)
813

14+
func (daemon *Daemon) ContainerAttach(job *engine.Job) engine.Status {
15+
if len(job.Args) != 1 {
16+
return job.Errorf("Usage: %s CONTAINER\n", job.Name)
17+
}
18+
19+
var (
20+
name = job.Args[0]
21+
logs = job.GetenvBool("logs")
22+
stream = job.GetenvBool("stream")
23+
stdin = job.GetenvBool("stdin")
24+
stdout = job.GetenvBool("stdout")
25+
stderr = job.GetenvBool("stderr")
26+
)
27+
28+
container := daemon.Get(name)
29+
if container == nil {
30+
return job.Errorf("No such container: %s", name)
31+
}
32+
33+
//logs
34+
if logs {
35+
cLog, err := container.ReadLog("json")
36+
if err != nil && os.IsNotExist(err) {
37+
// Legacy logs
38+
utils.Debugf("Old logs format")
39+
if stdout {
40+
cLog, err := container.ReadLog("stdout")
41+
if err != nil {
42+
utils.Errorf("Error reading logs (stdout): %s", err)
43+
} else if _, err := io.Copy(job.Stdout, cLog); err != nil {
44+
utils.Errorf("Error streaming logs (stdout): %s", err)
45+
}
46+
}
47+
if stderr {
48+
cLog, err := container.ReadLog("stderr")
49+
if err != nil {
50+
utils.Errorf("Error reading logs (stderr): %s", err)
51+
} else if _, err := io.Copy(job.Stderr, cLog); err != nil {
52+
utils.Errorf("Error streaming logs (stderr): %s", err)
53+
}
54+
}
55+
} else if err != nil {
56+
utils.Errorf("Error reading logs (json): %s", err)
57+
} else {
58+
dec := json.NewDecoder(cLog)
59+
for {
60+
l := &utils.JSONLog{}
61+
62+
if err := dec.Decode(l); err == io.EOF {
63+
break
64+
} else if err != nil {
65+
utils.Errorf("Error streaming logs: %s", err)
66+
break
67+
}
68+
if l.Stream == "stdout" && stdout {
69+
fmt.Fprintf(job.Stdout, "%s", l.Log)
70+
}
71+
if l.Stream == "stderr" && stderr {
72+
fmt.Fprintf(job.Stderr, "%s", l.Log)
73+
}
74+
}
75+
}
76+
}
77+
78+
//stream
79+
if stream {
80+
var (
81+
cStdin io.ReadCloser
82+
cStdout, cStderr io.Writer
83+
cStdinCloser io.Closer
84+
)
85+
86+
if stdin {
87+
r, w := io.Pipe()
88+
go func() {
89+
defer w.Close()
90+
defer utils.Debugf("Closing buffered stdin pipe")
91+
io.Copy(w, job.Stdin)
92+
}()
93+
cStdin = r
94+
cStdinCloser = job.Stdin
95+
}
96+
if stdout {
97+
cStdout = job.Stdout
98+
}
99+
if stderr {
100+
cStderr = job.Stderr
101+
}
102+
103+
<-daemon.Attach(container, cStdin, cStdinCloser, cStdout, cStderr)
104+
105+
// If we are in stdinonce mode, wait for the process to end
106+
// otherwise, simply return
107+
if container.Config.StdinOnce && !container.Config.Tty {
108+
container.State.WaitStop(-1 * time.Second)
109+
}
110+
}
111+
return engine.StatusOK
112+
}
113+
114+
// FIXME: this should be private, and every outside subsystem
115+
// should go through the "container_attach" job. But that would require
116+
// that job to be properly documented, as well as the relationship betweem
117+
// Attach and ContainerAttach.
118+
//
119+
// This method is in use by builder/builder.go.
9120
func (daemon *Daemon) Attach(container *Container, stdin io.ReadCloser, stdinCloser io.Closer, stdout io.Writer, stderr io.Writer) chan error {
10121
var (
11122
cStdout, cStderr io.ReadCloser

daemon/daemon.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,13 @@ type Daemon struct {
105105

106106
// Install installs daemon capabilities to eng.
107107
func (daemon *Daemon) Install(eng *engine.Engine) error {
108-
return eng.Register("container_inspect", daemon.ContainerInspect)
108+
if err := eng.Register("container_inspect", daemon.ContainerInspect); err != nil {
109+
return err
110+
}
111+
if err := eng.Register("attach", daemon.ContainerAttach); err != nil {
112+
return err
113+
}
114+
return nil
109115
}
110116

111117
// List returns an array of all containers registered in the daemon.

server/container.go

Lines changed: 0 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -798,105 +798,6 @@ func (srv *Server) ContainerLogs(job *engine.Job) engine.Status {
798798
return engine.StatusOK
799799
}
800800

801-
func (srv *Server) ContainerAttach(job *engine.Job) engine.Status {
802-
if len(job.Args) != 1 {
803-
return job.Errorf("Usage: %s CONTAINER\n", job.Name)
804-
}
805-
806-
var (
807-
name = job.Args[0]
808-
logs = job.GetenvBool("logs")
809-
stream = job.GetenvBool("stream")
810-
stdin = job.GetenvBool("stdin")
811-
stdout = job.GetenvBool("stdout")
812-
stderr = job.GetenvBool("stderr")
813-
)
814-
815-
container := srv.daemon.Get(name)
816-
if container == nil {
817-
return job.Errorf("No such container: %s", name)
818-
}
819-
820-
//logs
821-
if logs {
822-
cLog, err := container.ReadLog("json")
823-
if err != nil && os.IsNotExist(err) {
824-
// Legacy logs
825-
utils.Debugf("Old logs format")
826-
if stdout {
827-
cLog, err := container.ReadLog("stdout")
828-
if err != nil {
829-
utils.Errorf("Error reading logs (stdout): %s", err)
830-
} else if _, err := io.Copy(job.Stdout, cLog); err != nil {
831-
utils.Errorf("Error streaming logs (stdout): %s", err)
832-
}
833-
}
834-
if stderr {
835-
cLog, err := container.ReadLog("stderr")
836-
if err != nil {
837-
utils.Errorf("Error reading logs (stderr): %s", err)
838-
} else if _, err := io.Copy(job.Stderr, cLog); err != nil {
839-
utils.Errorf("Error streaming logs (stderr): %s", err)
840-
}
841-
}
842-
} else if err != nil {
843-
utils.Errorf("Error reading logs (json): %s", err)
844-
} else {
845-
dec := json.NewDecoder(cLog)
846-
for {
847-
l := &utils.JSONLog{}
848-
849-
if err := dec.Decode(l); err == io.EOF {
850-
break
851-
} else if err != nil {
852-
utils.Errorf("Error streaming logs: %s", err)
853-
break
854-
}
855-
if l.Stream == "stdout" && stdout {
856-
fmt.Fprintf(job.Stdout, "%s", l.Log)
857-
}
858-
if l.Stream == "stderr" && stderr {
859-
fmt.Fprintf(job.Stderr, "%s", l.Log)
860-
}
861-
}
862-
}
863-
}
864-
865-
//stream
866-
if stream {
867-
var (
868-
cStdin io.ReadCloser
869-
cStdout, cStderr io.Writer
870-
cStdinCloser io.Closer
871-
)
872-
873-
if stdin {
874-
r, w := io.Pipe()
875-
go func() {
876-
defer w.Close()
877-
defer utils.Debugf("Closing buffered stdin pipe")
878-
io.Copy(w, job.Stdin)
879-
}()
880-
cStdin = r
881-
cStdinCloser = job.Stdin
882-
}
883-
if stdout {
884-
cStdout = job.Stdout
885-
}
886-
if stderr {
887-
cStderr = job.Stderr
888-
}
889-
890-
<-srv.daemon.Attach(container, cStdin, cStdinCloser, cStdout, cStderr)
891-
892-
// If we are in stdinonce mode, wait for the process to end
893-
// otherwise, simply return
894-
if container.Config.StdinOnce && !container.Config.Tty {
895-
container.State.WaitStop(-1 * time.Second)
896-
}
897-
}
898-
return engine.StatusOK
899-
}
900801

901802
func (srv *Server) ContainerCopy(job *engine.Job) engine.Status {
902803
if len(job.Args) != 2 {

server/init.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,6 @@ func InitServer(job *engine.Job) engine.Status {
105105
"history": srv.ImageHistory,
106106
"viz": srv.ImagesViz,
107107
"container_copy": srv.ContainerCopy,
108-
"attach": srv.ContainerAttach,
109108
"logs": srv.ContainerLogs,
110109
"changes": srv.ContainerChanges,
111110
"top": srv.ContainerTop,

0 commit comments

Comments
 (0)