mirror of https://github.com/docker/docs.git
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)
This commit is contained in:
parent
4949e070fb
commit
c2496d97cc
|
@ -683,6 +683,11 @@ func (b *buildFile) run(c *daemon.Container) error {
|
||||||
var errCh chan error
|
var errCh chan error
|
||||||
if b.verbose {
|
if b.verbose {
|
||||||
errCh = utils.Go(func() error {
|
errCh = utils.Go(func() error {
|
||||||
|
// FIXME: call the 'attach' job so that daemon.Attach can be made private
|
||||||
|
//
|
||||||
|
// FIXME (LK4D4): Also, maybe makes sense to call "logs" job, it is like attach
|
||||||
|
// but without hijacking for stdin. Also, with attach there can be race
|
||||||
|
// condition because of some output already was printed before it.
|
||||||
return <-b.daemon.Attach(c, nil, nil, b.outStream, b.errStream)
|
return <-b.daemon.Attach(c, nil, nil, b.outStream, b.errStream)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
111
daemon/attach.go
111
daemon/attach.go
|
@ -1,11 +1,122 @@
|
||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/docker/docker/engine"
|
||||||
"github.com/docker/docker/utils"
|
"github.com/docker/docker/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (daemon *Daemon) ContainerAttach(job *engine.Job) engine.Status {
|
||||||
|
if len(job.Args) != 1 {
|
||||||
|
return job.Errorf("Usage: %s CONTAINER\n", job.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
name = job.Args[0]
|
||||||
|
logs = job.GetenvBool("logs")
|
||||||
|
stream = job.GetenvBool("stream")
|
||||||
|
stdin = job.GetenvBool("stdin")
|
||||||
|
stdout = job.GetenvBool("stdout")
|
||||||
|
stderr = job.GetenvBool("stderr")
|
||||||
|
)
|
||||||
|
|
||||||
|
container := daemon.Get(name)
|
||||||
|
if container == nil {
|
||||||
|
return job.Errorf("No such container: %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
//logs
|
||||||
|
if logs {
|
||||||
|
cLog, err := container.ReadLog("json")
|
||||||
|
if err != nil && os.IsNotExist(err) {
|
||||||
|
// Legacy logs
|
||||||
|
utils.Debugf("Old logs format")
|
||||||
|
if stdout {
|
||||||
|
cLog, err := container.ReadLog("stdout")
|
||||||
|
if err != nil {
|
||||||
|
utils.Errorf("Error reading logs (stdout): %s", err)
|
||||||
|
} else if _, err := io.Copy(job.Stdout, cLog); err != nil {
|
||||||
|
utils.Errorf("Error streaming logs (stdout): %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if stderr {
|
||||||
|
cLog, err := container.ReadLog("stderr")
|
||||||
|
if err != nil {
|
||||||
|
utils.Errorf("Error reading logs (stderr): %s", err)
|
||||||
|
} else if _, err := io.Copy(job.Stderr, cLog); err != nil {
|
||||||
|
utils.Errorf("Error streaming logs (stderr): %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if err != nil {
|
||||||
|
utils.Errorf("Error reading logs (json): %s", err)
|
||||||
|
} else {
|
||||||
|
dec := json.NewDecoder(cLog)
|
||||||
|
for {
|
||||||
|
l := &utils.JSONLog{}
|
||||||
|
|
||||||
|
if err := dec.Decode(l); err == io.EOF {
|
||||||
|
break
|
||||||
|
} else if err != nil {
|
||||||
|
utils.Errorf("Error streaming logs: %s", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if l.Stream == "stdout" && stdout {
|
||||||
|
fmt.Fprintf(job.Stdout, "%s", l.Log)
|
||||||
|
}
|
||||||
|
if l.Stream == "stderr" && stderr {
|
||||||
|
fmt.Fprintf(job.Stderr, "%s", l.Log)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//stream
|
||||||
|
if stream {
|
||||||
|
var (
|
||||||
|
cStdin io.ReadCloser
|
||||||
|
cStdout, cStderr io.Writer
|
||||||
|
cStdinCloser io.Closer
|
||||||
|
)
|
||||||
|
|
||||||
|
if stdin {
|
||||||
|
r, w := io.Pipe()
|
||||||
|
go func() {
|
||||||
|
defer w.Close()
|
||||||
|
defer utils.Debugf("Closing buffered stdin pipe")
|
||||||
|
io.Copy(w, job.Stdin)
|
||||||
|
}()
|
||||||
|
cStdin = r
|
||||||
|
cStdinCloser = job.Stdin
|
||||||
|
}
|
||||||
|
if stdout {
|
||||||
|
cStdout = job.Stdout
|
||||||
|
}
|
||||||
|
if stderr {
|
||||||
|
cStderr = job.Stderr
|
||||||
|
}
|
||||||
|
|
||||||
|
<-daemon.Attach(container, cStdin, cStdinCloser, cStdout, cStderr)
|
||||||
|
|
||||||
|
// If we are in stdinonce mode, wait for the process to end
|
||||||
|
// otherwise, simply return
|
||||||
|
if container.Config.StdinOnce && !container.Config.Tty {
|
||||||
|
container.State.WaitStop(-1 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return engine.StatusOK
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: this should be private, and every outside subsystem
|
||||||
|
// should go through the "container_attach" job. But that would require
|
||||||
|
// that job to be properly documented, as well as the relationship betweem
|
||||||
|
// Attach and ContainerAttach.
|
||||||
|
//
|
||||||
|
// This method is in use by builder/builder.go.
|
||||||
func (daemon *Daemon) Attach(container *Container, stdin io.ReadCloser, stdinCloser io.Closer, stdout io.Writer, stderr io.Writer) chan error {
|
func (daemon *Daemon) Attach(container *Container, stdin io.ReadCloser, stdinCloser io.Closer, stdout io.Writer, stderr io.Writer) chan error {
|
||||||
var (
|
var (
|
||||||
cStdout, cStderr io.ReadCloser
|
cStdout, cStderr io.ReadCloser
|
||||||
|
|
|
@ -105,7 +105,13 @@ type Daemon struct {
|
||||||
|
|
||||||
// Install installs daemon capabilities to eng.
|
// Install installs daemon capabilities to eng.
|
||||||
func (daemon *Daemon) Install(eng *engine.Engine) error {
|
func (daemon *Daemon) Install(eng *engine.Engine) error {
|
||||||
return eng.Register("container_inspect", daemon.ContainerInspect)
|
if err := eng.Register("container_inspect", daemon.ContainerInspect); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := eng.Register("attach", daemon.ContainerAttach); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// List returns an array of all containers registered in the daemon.
|
// List returns an array of all containers registered in the daemon.
|
||||||
|
|
|
@ -798,105 +798,6 @@ func (srv *Server) ContainerLogs(job *engine.Job) engine.Status {
|
||||||
return engine.StatusOK
|
return engine.StatusOK
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) ContainerAttach(job *engine.Job) engine.Status {
|
|
||||||
if len(job.Args) != 1 {
|
|
||||||
return job.Errorf("Usage: %s CONTAINER\n", job.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
name = job.Args[0]
|
|
||||||
logs = job.GetenvBool("logs")
|
|
||||||
stream = job.GetenvBool("stream")
|
|
||||||
stdin = job.GetenvBool("stdin")
|
|
||||||
stdout = job.GetenvBool("stdout")
|
|
||||||
stderr = job.GetenvBool("stderr")
|
|
||||||
)
|
|
||||||
|
|
||||||
container := srv.daemon.Get(name)
|
|
||||||
if container == nil {
|
|
||||||
return job.Errorf("No such container: %s", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
//logs
|
|
||||||
if logs {
|
|
||||||
cLog, err := container.ReadLog("json")
|
|
||||||
if err != nil && os.IsNotExist(err) {
|
|
||||||
// Legacy logs
|
|
||||||
utils.Debugf("Old logs format")
|
|
||||||
if stdout {
|
|
||||||
cLog, err := container.ReadLog("stdout")
|
|
||||||
if err != nil {
|
|
||||||
utils.Errorf("Error reading logs (stdout): %s", err)
|
|
||||||
} else if _, err := io.Copy(job.Stdout, cLog); err != nil {
|
|
||||||
utils.Errorf("Error streaming logs (stdout): %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if stderr {
|
|
||||||
cLog, err := container.ReadLog("stderr")
|
|
||||||
if err != nil {
|
|
||||||
utils.Errorf("Error reading logs (stderr): %s", err)
|
|
||||||
} else if _, err := io.Copy(job.Stderr, cLog); err != nil {
|
|
||||||
utils.Errorf("Error streaming logs (stderr): %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if err != nil {
|
|
||||||
utils.Errorf("Error reading logs (json): %s", err)
|
|
||||||
} else {
|
|
||||||
dec := json.NewDecoder(cLog)
|
|
||||||
for {
|
|
||||||
l := &utils.JSONLog{}
|
|
||||||
|
|
||||||
if err := dec.Decode(l); err == io.EOF {
|
|
||||||
break
|
|
||||||
} else if err != nil {
|
|
||||||
utils.Errorf("Error streaming logs: %s", err)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if l.Stream == "stdout" && stdout {
|
|
||||||
fmt.Fprintf(job.Stdout, "%s", l.Log)
|
|
||||||
}
|
|
||||||
if l.Stream == "stderr" && stderr {
|
|
||||||
fmt.Fprintf(job.Stderr, "%s", l.Log)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//stream
|
|
||||||
if stream {
|
|
||||||
var (
|
|
||||||
cStdin io.ReadCloser
|
|
||||||
cStdout, cStderr io.Writer
|
|
||||||
cStdinCloser io.Closer
|
|
||||||
)
|
|
||||||
|
|
||||||
if stdin {
|
|
||||||
r, w := io.Pipe()
|
|
||||||
go func() {
|
|
||||||
defer w.Close()
|
|
||||||
defer utils.Debugf("Closing buffered stdin pipe")
|
|
||||||
io.Copy(w, job.Stdin)
|
|
||||||
}()
|
|
||||||
cStdin = r
|
|
||||||
cStdinCloser = job.Stdin
|
|
||||||
}
|
|
||||||
if stdout {
|
|
||||||
cStdout = job.Stdout
|
|
||||||
}
|
|
||||||
if stderr {
|
|
||||||
cStderr = job.Stderr
|
|
||||||
}
|
|
||||||
|
|
||||||
<-srv.daemon.Attach(container, cStdin, cStdinCloser, cStdout, cStderr)
|
|
||||||
|
|
||||||
// If we are in stdinonce mode, wait for the process to end
|
|
||||||
// otherwise, simply return
|
|
||||||
if container.Config.StdinOnce && !container.Config.Tty {
|
|
||||||
container.State.WaitStop(-1 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return engine.StatusOK
|
|
||||||
}
|
|
||||||
|
|
||||||
func (srv *Server) ContainerCopy(job *engine.Job) engine.Status {
|
func (srv *Server) ContainerCopy(job *engine.Job) engine.Status {
|
||||||
if len(job.Args) != 2 {
|
if len(job.Args) != 2 {
|
||||||
|
|
|
@ -105,7 +105,6 @@ func InitServer(job *engine.Job) engine.Status {
|
||||||
"history": srv.ImageHistory,
|
"history": srv.ImageHistory,
|
||||||
"viz": srv.ImagesViz,
|
"viz": srv.ImagesViz,
|
||||||
"container_copy": srv.ContainerCopy,
|
"container_copy": srv.ContainerCopy,
|
||||||
"attach": srv.ContainerAttach,
|
|
||||||
"logs": srv.ContainerLogs,
|
"logs": srv.ContainerLogs,
|
||||||
"changes": srv.ContainerChanges,
|
"changes": srv.ContainerChanges,
|
||||||
"top": srv.ContainerTop,
|
"top": srv.ContainerTop,
|
||||||
|
|
Loading…
Reference in New Issue