Merge pull request #27467 from tonistiigi/attach-cb
Move stdio attach from libcontainerd backend to callback Upstream-commit: 8ed31089c03c36954e95c2066b1f3724e2d5c849 Component: engine
This commit is contained in:
@ -193,7 +193,7 @@ func (daemon *Daemon) restore() error {
|
||||
|
||||
if c.IsRunning() || c.IsPaused() {
|
||||
c.RestartManager().Cancel() // manually start containers because some need to wait for swarm networking
|
||||
if err := daemon.containerd.Restore(c.ID); err != nil {
|
||||
if err := daemon.containerd.Restore(c.ID, c.InitializeStdio); err != nil {
|
||||
logrus.Errorf("Failed to restore %s with containerd: %s", c.ID, err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -212,7 +212,7 @@ func (d *Daemon) ContainerExecStart(ctx context.Context, name string, stdin io.R
|
||||
|
||||
attachErr := container.AttachStreams(ctx, ec.StreamConfig, ec.OpenStdin, true, ec.Tty, cStdin, cStdout, cStderr, ec.DetachKeys)
|
||||
|
||||
systemPid, err := d.containerd.AddProcess(ctx, c.ID, name, p)
|
||||
systemPid, err := d.containerd.AddProcess(ctx, c.ID, name, p, ec.InitializeStdio)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
package exec
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/libcontainerd"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/runconfig"
|
||||
)
|
||||
@ -39,6 +42,21 @@ func NewConfig() *Config {
|
||||
}
|
||||
}
|
||||
|
||||
// InitializeStdio is called by libcontainerd to connect the stdio.
|
||||
func (c *Config) InitializeStdio(iop libcontainerd.IOPipe) error {
|
||||
c.StreamConfig.CopyToPipe(iop)
|
||||
|
||||
if c.Stdin() == nil && !c.Tty && runtime.GOOS == "windows" {
|
||||
if iop.Stdin != nil {
|
||||
if err := iop.Stdin.Close(); err != nil {
|
||||
logrus.Error("error closing exec stdin: %+v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Store keeps track of the exec configurations.
|
||||
type Store struct {
|
||||
commands map[string]*Config
|
||||
|
||||
@ -14,7 +14,6 @@ import (
|
||||
timetypes "github.com/docker/docker/api/types/time"
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/daemon/logger"
|
||||
"github.com/docker/docker/daemon/logger/jsonfilelog"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
)
|
||||
@ -121,30 +120,6 @@ func (daemon *Daemon) getLogger(container *container.Container) (logger.Logger,
|
||||
return container.StartLogger(container.HostConfig.LogConfig)
|
||||
}
|
||||
|
||||
// StartLogging initializes and starts the container logging stream.
|
||||
func (daemon *Daemon) StartLogging(container *container.Container) error {
|
||||
if container.HostConfig.LogConfig.Type == "none" {
|
||||
return nil // do not start logging routines
|
||||
}
|
||||
|
||||
l, err := container.StartLogger(container.HostConfig.LogConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to initialize logging driver: %v", err)
|
||||
}
|
||||
|
||||
copier := logger.NewCopier(map[string]io.Reader{"stdout": container.StdoutPipe(), "stderr": container.StderrPipe()}, l)
|
||||
container.LogCopier = copier
|
||||
copier.Run()
|
||||
container.LogDriver = l
|
||||
|
||||
// set LogPath field only for json-file logdriver
|
||||
if jl, ok := l.(*jsonfilelog.JSONFileLogger); ok {
|
||||
container.LogPath = jl.LogPath()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// mergeLogConfig merges the daemon log config to the container's log config if the container's log driver is not specified.
|
||||
func (daemon *Daemon) mergeAndVerifyLogConfig(cfg *containertypes.LogConfig) error {
|
||||
if cfg.Type == "" {
|
||||
|
||||
@ -3,17 +3,14 @@ package daemon
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/daemon/exec"
|
||||
"github.com/docker/docker/libcontainerd"
|
||||
"github.com/docker/docker/restartmanager"
|
||||
"github.com/docker/docker/runconfig"
|
||||
)
|
||||
|
||||
// StateChanged updates daemon state changes from containerd
|
||||
@ -133,69 +130,3 @@ func (daemon *Daemon) StateChanged(id string, e libcontainerd.StateInfo) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AttachStreams is called by libcontainerd to connect the stdio.
|
||||
func (daemon *Daemon) AttachStreams(id string, iop libcontainerd.IOPipe) error {
|
||||
var (
|
||||
s *runconfig.StreamConfig
|
||||
ec *exec.Config
|
||||
)
|
||||
|
||||
c := daemon.containers.Get(id)
|
||||
if c == nil {
|
||||
var err error
|
||||
ec, err = daemon.getExecConfig(id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("no such exec/container: %s", id)
|
||||
}
|
||||
s = ec.StreamConfig
|
||||
} else {
|
||||
s = c.StreamConfig
|
||||
if err := daemon.StartLogging(c); err != nil {
|
||||
c.Reset(false)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
copyFunc := func(w io.Writer, r io.Reader) {
|
||||
s.Add(1)
|
||||
go func() {
|
||||
if _, err := io.Copy(w, r); err != nil {
|
||||
logrus.Errorf("%v stream copy error: %v", id, err)
|
||||
}
|
||||
s.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
if iop.Stdout != nil {
|
||||
copyFunc(s.Stdout(), iop.Stdout)
|
||||
}
|
||||
if iop.Stderr != nil {
|
||||
copyFunc(s.Stderr(), iop.Stderr)
|
||||
}
|
||||
|
||||
if stdin := s.Stdin(); stdin != nil {
|
||||
if iop.Stdin != nil {
|
||||
go func() {
|
||||
io.Copy(iop.Stdin, stdin)
|
||||
if err := iop.Stdin.Close(); err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
} else {
|
||||
//TODO(swernli): On Windows, not closing stdin when no tty is requested by the exec Config
|
||||
// results in a hang. We should re-evaluate generalizing this fix for all OSes if
|
||||
// we can determine that is the right thing to do more generally.
|
||||
if (c != nil && !c.Config.Tty) || (ec != nil && !ec.Tty && runtime.GOOS == "windows") {
|
||||
// tty is enabled, so dont close containerd's iopipe stdin.
|
||||
if iop.Stdin != nil {
|
||||
if err := iop.Stdin.Close(); err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ func (daemon *Daemon) postRunProcessing(container *container.Container, e libcon
|
||||
|
||||
// Create a new servicing container, which will start, complete the update, and merge back the
|
||||
// results if it succeeded, all as part of the below function call.
|
||||
if err := daemon.containerd.Create((container.ID + "_servicing"), "", "", *spec, newOpts...); err != nil {
|
||||
if err := daemon.containerd.Create((container.ID + "_servicing"), "", "", *spec, container.InitializeStdio, newOpts...); err != nil {
|
||||
container.SetExitCode(-1)
|
||||
return fmt.Errorf("Post-run update servicing failed: %s", err)
|
||||
}
|
||||
|
||||
@ -149,7 +149,7 @@ func (daemon *Daemon) containerStart(container *container.Container, checkpoint
|
||||
container.ResetRestartManager(true)
|
||||
}
|
||||
|
||||
if err := daemon.containerd.Create(container.ID, checkpoint, container.CheckpointDir(), *spec, createOptions...); err != nil {
|
||||
if err := daemon.containerd.Create(container.ID, checkpoint, container.CheckpointDir(), *spec, container.InitializeStdio, createOptions...); err != nil {
|
||||
errDesc := grpc.ErrorDesc(err)
|
||||
logrus.Errorf("Create container failed with error: %s", errDesc)
|
||||
// if we receive an internal error from the initial start of a container then lets
|
||||
|
||||
Reference in New Issue
Block a user