containerd/io.go
Michael Crosby 00734ab04a Return fifo paths from Shim
This allows attach of existing fifos to be done without any information
stored on the client side.

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
2017-06-01 14:12:02 -07:00

149 lines
2.6 KiB
Go

package containerd
import (
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"sync"
)
type IO struct {
Terminal bool
Stdin string
Stdout string
Stderr string
closer io.Closer
}
func (i *IO) Close() error {
if i.closer == nil {
return nil
}
return i.closer.Close()
}
type IOCreation func() (*IO, error)
type IOAttach func(*FifoSet) (*IO, error)
func NewIO(stdin io.Reader, stdout, stderr io.Writer) IOCreation {
return func() (*IO, error) {
paths, err := NewFifos()
if err != nil {
return nil, err
}
i := &IO{
Terminal: false,
Stdout: paths.Out,
Stderr: paths.Err,
Stdin: paths.In,
}
set := &ioSet{
in: stdin,
out: stdout,
err: stderr,
}
closer, err := copyIO(paths, set, false)
if err != nil {
return nil, err
}
i.closer = closer
return i, nil
}
}
func WithAttach(stdin io.Reader, stdout, stderr io.Writer) IOAttach {
return func(paths *FifoSet) (*IO, error) {
if paths == nil {
return nil, fmt.Errorf("cannot attach to existing fifos")
}
i := &IO{
Terminal: false,
Stdout: paths.Out,
Stderr: paths.Err,
Stdin: paths.In,
}
set := &ioSet{
in: stdin,
out: stdout,
err: stderr,
}
closer, err := copyIO(paths, set, false)
if err != nil {
return nil, err
}
i.closer = closer
return i, nil
}
}
// Stdio returns an IO implementation to be used for a task
// that outputs the container's IO as the current processes Stdio
func Stdio() (*IO, error) {
paths, err := NewFifos()
if err != nil {
return nil, err
}
set := &ioSet{
in: os.Stdin,
out: os.Stdout,
err: os.Stderr,
}
closer, err := copyIO(paths, set, false)
if err != nil {
return nil, err
}
return &IO{
Terminal: false,
Stdin: paths.In,
Stdout: paths.Out,
Stderr: paths.Err,
closer: closer,
}, nil
}
// NewFifos returns a new set of fifos for the task
func NewFifos() (*FifoSet, error) {
root := filepath.Join(os.TempDir(), "containerd")
if err := os.MkdirAll(root, 0700); err != nil {
return nil, err
}
dir, err := ioutil.TempDir(root, "")
if err != nil {
return nil, err
}
return &FifoSet{
Dir: dir,
In: filepath.Join(dir, "stdin"),
Out: filepath.Join(dir, "stdout"),
Err: filepath.Join(dir, "stderr"),
}, nil
}
type FifoSet struct {
// Dir is the directory holding the task fifos
Dir string
In, Out, Err string
}
type ioSet struct {
in io.Reader
out, err io.Writer
}
type wgCloser struct {
wg *sync.WaitGroup
dir string
}
func (g *wgCloser) Close() error {
g.wg.Wait()
if g.dir != "" {
return os.RemoveAll(g.dir)
}
return nil
}