|
@@ -13,6 +13,7 @@ import (
|
|
|
"github.com/Sirupsen/logrus"
|
|
|
containerd "github.com/docker/containerd/api/grpc/types"
|
|
|
"github.com/docker/docker/pkg/idtools"
|
|
|
+ "github.com/docker/docker/pkg/ioutils"
|
|
|
"github.com/docker/docker/pkg/mount"
|
|
|
"github.com/golang/protobuf/ptypes"
|
|
|
"github.com/golang/protobuf/ptypes/timestamp"
|
|
@@ -30,7 +31,10 @@ type client struct {
|
|
|
liveRestore bool
|
|
|
}
|
|
|
|
|
|
-func (clnt *client) AddProcess(ctx context.Context, containerID, processFriendlyName string, specp Process) error {
|
|
|
+// AddProcess is the handler for adding a process to an already running
|
|
|
+// container. It's called through docker exec. It returns the system pid of the
|
|
|
+// exec'd process.
|
|
|
+func (clnt *client) AddProcess(ctx context.Context, containerID, processFriendlyName string, specp Process, attachStdio StdioCallback) error {
|
|
|
clnt.lock(containerID)
|
|
|
defer clnt.unlock(containerID)
|
|
|
container, err := clnt.getContainer(containerID)
|
|
@@ -96,15 +100,25 @@ func (clnt *client) AddProcess(ctx context.Context, containerID, processFriendly
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
- container.processes[processFriendlyName] = p
|
|
|
+ var stdinOnce sync.Once
|
|
|
+ stdin := iopipe.Stdin
|
|
|
+ iopipe.Stdin = ioutils.NewWriteCloserWrapper(stdin, func() error {
|
|
|
+ var err error
|
|
|
+ stdinOnce.Do(func() { // on error from attach we don't know if stdin was already closed
|
|
|
+ err = stdin.Close()
|
|
|
+ if err2 := p.sendCloseStdin(); err == nil {
|
|
|
+ err = err2
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return err
|
|
|
+ })
|
|
|
|
|
|
- clnt.unlock(containerID)
|
|
|
+ container.processes[processFriendlyName] = p
|
|
|
|
|
|
- if err := clnt.backend.AttachStreams(processFriendlyName, *iopipe); err != nil {
|
|
|
- clnt.lock(containerID)
|
|
|
+ if err := attachStdio(*iopipe); err != nil {
|
|
|
+ p.closeFifos(iopipe)
|
|
|
return err
|
|
|
}
|
|
|
- clnt.lock(containerID)
|
|
|
|
|
|
return nil
|
|
|
}
|
|
@@ -134,7 +148,7 @@ func (clnt *client) prepareBundleDir(uid, gid int) (string, error) {
|
|
|
return p, nil
|
|
|
}
|
|
|
|
|
|
-func (clnt *client) Create(containerID string, spec Spec, options ...CreateOption) (err error) {
|
|
|
+func (clnt *client) Create(containerID string, spec Spec, attachStdio StdioCallback, options ...CreateOption) (err error) {
|
|
|
clnt.lock(containerID)
|
|
|
defer clnt.unlock(containerID)
|
|
|
|
|
@@ -160,6 +174,7 @@ func (clnt *client) Create(containerID string, spec Spec, options ...CreateOptio
|
|
|
if err := container.clean(); err != nil {
|
|
|
return err
|
|
|
}
|
|
|
+ container.attachStdio = attachStdio // hack for v1.12 backport
|
|
|
|
|
|
defer func() {
|
|
|
if err != nil {
|
|
@@ -181,7 +196,7 @@ func (clnt *client) Create(containerID string, spec Spec, options ...CreateOptio
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
- return container.start()
|
|
|
+ return container.start(attachStdio)
|
|
|
}
|
|
|
|
|
|
func (clnt *client) Signal(containerID string, sig int) error {
|
|
@@ -390,7 +405,7 @@ func (clnt *client) getOrCreateExitNotifier(containerID string) *exitNotifier {
|
|
|
return w
|
|
|
}
|
|
|
|
|
|
-func (clnt *client) restore(cont *containerd.Container, lastEvent *containerd.Event, options ...CreateOption) (err error) {
|
|
|
+func (clnt *client) restore(cont *containerd.Container, lastEvent *containerd.Event, attachStdio StdioCallback, options ...CreateOption) (err error) {
|
|
|
clnt.lock(cont.Id)
|
|
|
defer clnt.unlock(cont.Id)
|
|
|
|
|
@@ -421,8 +436,18 @@ func (clnt *client) restore(cont *containerd.Container, lastEvent *containerd.Ev
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
+ var stdinOnce sync.Once
|
|
|
+ stdin := iopipe.Stdin
|
|
|
+ iopipe.Stdin = ioutils.NewWriteCloserWrapper(stdin, func() error {
|
|
|
+ var err error
|
|
|
+ stdinOnce.Do(func() { // on error from attach we don't know if stdin was already closed
|
|
|
+ err = stdin.Close()
|
|
|
+ })
|
|
|
+ return err
|
|
|
+ })
|
|
|
|
|
|
- if err := clnt.backend.AttachStreams(containerID, *iopipe); err != nil {
|
|
|
+ if err := attachStdio(*iopipe); err != nil {
|
|
|
+ container.closeFifos(iopipe)
|
|
|
return err
|
|
|
}
|
|
|
|
|
@@ -435,6 +460,7 @@ func (clnt *client) restore(cont *containerd.Container, lastEvent *containerd.Ev
|
|
|
}})
|
|
|
|
|
|
if err != nil {
|
|
|
+ container.closeFifos(iopipe)
|
|
|
return err
|
|
|
}
|
|
|
|
|
@@ -512,7 +538,7 @@ func (clnt *client) getContainerLastEvent(id string) (*containerd.Event, error)
|
|
|
return ev, err
|
|
|
}
|
|
|
|
|
|
-func (clnt *client) Restore(containerID string, options ...CreateOption) error {
|
|
|
+func (clnt *client) Restore(containerID string, attachStdio StdioCallback, options ...CreateOption) error {
|
|
|
// Synchronize with live events
|
|
|
clnt.remote.Lock()
|
|
|
defer clnt.remote.Unlock()
|
|
@@ -560,7 +586,7 @@ func (clnt *client) Restore(containerID string, options ...CreateOption) error {
|
|
|
|
|
|
// container is still alive
|
|
|
if clnt.liveRestore {
|
|
|
- if err := clnt.restore(cont, ev, options...); err != nil {
|
|
|
+ if err := clnt.restore(cont, ev, attachStdio, options...); err != nil {
|
|
|
logrus.Errorf("libcontainerd: error restoring %s: %v", containerID, err)
|
|
|
}
|
|
|
return nil
|