|
@@ -1,14 +1,16 @@
|
|
package libcontainerd
|
|
package libcontainerd
|
|
|
|
|
|
import (
|
|
import (
|
|
- "fmt"
|
|
|
|
"io"
|
|
"io"
|
|
|
|
+ "io/ioutil"
|
|
"os"
|
|
"os"
|
|
"path/filepath"
|
|
"path/filepath"
|
|
"syscall"
|
|
"syscall"
|
|
|
|
+ "time"
|
|
|
|
|
|
containerd "github.com/docker/containerd/api/grpc/types"
|
|
containerd "github.com/docker/containerd/api/grpc/types"
|
|
"github.com/docker/docker/pkg/ioutils"
|
|
"github.com/docker/docker/pkg/ioutils"
|
|
|
|
+ "github.com/tonistiigi/fifo"
|
|
"golang.org/x/net/context"
|
|
"golang.org/x/net/context"
|
|
)
|
|
)
|
|
|
|
|
|
@@ -26,34 +28,53 @@ type process struct {
|
|
dir string
|
|
dir string
|
|
}
|
|
}
|
|
|
|
|
|
-func (p *process) openFifos(terminal bool) (*IOPipe, error) {
|
|
|
|
- bundleDir := p.dir
|
|
|
|
- if err := os.MkdirAll(bundleDir, 0700); err != nil {
|
|
|
|
|
|
+func (p *process) openFifos(terminal bool) (pipe *IOPipe, err error) {
|
|
|
|
+ if err := os.MkdirAll(p.dir, 0700); err != nil {
|
|
return nil, err
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
|
|
- for i := 0; i < 3; i++ {
|
|
|
|
- f := p.fifo(i)
|
|
|
|
- if err := syscall.Mkfifo(f, 0700); err != nil && !os.IsExist(err) {
|
|
|
|
- return nil, fmt.Errorf("mkfifo: %s %v", f, err)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ ctx, _ := context.WithTimeout(context.Background(), 15*time.Second)
|
|
|
|
|
|
io := &IOPipe{}
|
|
io := &IOPipe{}
|
|
- stdinf, err := os.OpenFile(p.fifo(syscall.Stdin), syscall.O_RDWR, 0)
|
|
|
|
|
|
+
|
|
|
|
+ stdin, err := fifo.OpenFifo(ctx, p.fifo(syscall.Stdin), syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ defer func() {
|
|
|
|
+ if err != nil {
|
|
|
|
+ stdin.Close()
|
|
|
|
+ }
|
|
|
|
+ }()
|
|
|
|
+
|
|
|
|
+ io.Stdout, err = fifo.OpenFifo(ctx, p.fifo(syscall.Stdout), syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700)
|
|
if err != nil {
|
|
if err != nil {
|
|
return nil, err
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
|
|
- io.Stdout = openReaderFromFifo(p.fifo(syscall.Stdout))
|
|
|
|
|
|
+ defer func() {
|
|
|
|
+ if err != nil {
|
|
|
|
+ io.Stdout.Close()
|
|
|
|
+ }
|
|
|
|
+ }()
|
|
|
|
+
|
|
if !terminal {
|
|
if !terminal {
|
|
- io.Stderr = openReaderFromFifo(p.fifo(syscall.Stderr))
|
|
|
|
|
|
+ io.Stderr, err = fifo.OpenFifo(ctx, p.fifo(syscall.Stderr), syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+ defer func() {
|
|
|
|
+ if err != nil {
|
|
|
|
+ io.Stderr.Close()
|
|
|
|
+ }
|
|
|
|
+ }()
|
|
} else {
|
|
} else {
|
|
- io.Stderr = emptyReader{}
|
|
|
|
|
|
+ io.Stderr = ioutil.NopCloser(emptyReader{})
|
|
}
|
|
}
|
|
|
|
|
|
- io.Stdin = ioutils.NewWriteCloserWrapper(stdinf, func() error {
|
|
|
|
- stdinf.Close()
|
|
|
|
|
|
+ io.Stdin = ioutils.NewWriteCloserWrapper(stdin, func() error {
|
|
|
|
+ stdin.Close()
|
|
_, err := p.client.remote.apiClient.UpdateProcess(context.Background(), &containerd.UpdateProcessRequest{
|
|
_, err := p.client.remote.apiClient.UpdateProcess(context.Background(), &containerd.UpdateProcessRequest{
|
|
Id: p.containerID,
|
|
Id: p.containerID,
|
|
Pid: p.friendlyName,
|
|
Pid: p.friendlyName,
|
|
@@ -67,8 +88,8 @@ func (p *process) openFifos(terminal bool) (*IOPipe, error) {
|
|
|
|
|
|
func (p *process) closeFifos(io *IOPipe) {
|
|
func (p *process) closeFifos(io *IOPipe) {
|
|
io.Stdin.Close()
|
|
io.Stdin.Close()
|
|
- closeReaderFifo(p.fifo(syscall.Stdout))
|
|
|
|
- closeReaderFifo(p.fifo(syscall.Stderr))
|
|
|
|
|
|
+ io.Stdout.Close()
|
|
|
|
+ io.Stderr.Close()
|
|
}
|
|
}
|
|
|
|
|
|
type emptyReader struct{}
|
|
type emptyReader struct{}
|
|
@@ -77,34 +98,6 @@ func (r emptyReader) Read(b []byte) (int, error) {
|
|
return 0, io.EOF
|
|
return 0, io.EOF
|
|
}
|
|
}
|
|
|
|
|
|
-func openReaderFromFifo(fn string) io.Reader {
|
|
|
|
- r, w := io.Pipe()
|
|
|
|
- c := make(chan struct{})
|
|
|
|
- go func() {
|
|
|
|
- close(c)
|
|
|
|
- stdoutf, err := os.OpenFile(fn, syscall.O_RDONLY, 0)
|
|
|
|
- if err != nil {
|
|
|
|
- r.CloseWithError(err)
|
|
|
|
- }
|
|
|
|
- if _, err := io.Copy(w, stdoutf); err != nil {
|
|
|
|
- r.CloseWithError(err)
|
|
|
|
- }
|
|
|
|
- w.Close()
|
|
|
|
- stdoutf.Close()
|
|
|
|
- }()
|
|
|
|
- <-c // wait for the goroutine to get scheduled and syscall to block
|
|
|
|
- return r
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-// closeReaderFifo closes fifo that may be blocked on open by opening the write side.
|
|
|
|
-func closeReaderFifo(fn string) {
|
|
|
|
- f, err := os.OpenFile(fn, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
|
|
|
|
- if err != nil {
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
- f.Close()
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
func (p *process) fifo(index int) string {
|
|
func (p *process) fifo(index int) string {
|
|
return filepath.Join(p.dir, p.friendlyName+"-"+fdNames[index])
|
|
return filepath.Join(p.dir, p.friendlyName+"-"+fdNames[index])
|
|
}
|
|
}
|