Add null io option
This adds null IO option for efficient handling of IO. It provides a container directly with `/dev/null` and does not require any io.Copy within the shim whenever a user does not want the IO of the container. Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
parent
77035a6e65
commit
eb58ecab7c
@ -1,10 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
@ -205,7 +203,7 @@ func (w *worker) runContainer(ctx context.Context, id string) error {
|
||||
}
|
||||
defer c.Delete(ctx, containerd.WithSnapshotCleanup)
|
||||
|
||||
task, err := c.NewTask(ctx, containerd.NewIO(bytes.NewBuffer(nil), ioutil.Discard, ioutil.Discard))
|
||||
task, err := c.NewTask(ctx, containerd.NullIO)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -19,8 +19,7 @@ import (
|
||||
)
|
||||
|
||||
func empty() IOCreation {
|
||||
null := ioutil.Discard
|
||||
return NewIO(bytes.NewBuffer(nil), null, null)
|
||||
return NullIO
|
||||
}
|
||||
|
||||
func TestContainerList(t *testing.T) {
|
||||
|
5
io.go
5
io.go
@ -126,6 +126,11 @@ func StdioTerminal(id string) (*IO, error) {
|
||||
return NewIOWithTerminal(os.Stdin, os.Stdout, os.Stderr, true)(id)
|
||||
}
|
||||
|
||||
// NullIO redirects the container's IO into /dev/null
|
||||
func NullIO(id string) (*IO, error) {
|
||||
return &IO{}, nil
|
||||
}
|
||||
|
||||
// FIFOSet is a set of fifos for use with tasks
|
||||
type FIFOSet struct {
|
||||
// Dir is the directory holding the task fifos
|
||||
|
@ -133,7 +133,6 @@ func (e *execProcess) Stdio() stdio {
|
||||
func (e *execProcess) Start(ctx context.Context) (err error) {
|
||||
var (
|
||||
socket *runc.Socket
|
||||
io runc.IO
|
||||
pidfile = filepath.Join(e.path, fmt.Sprintf("%s.pid", e.id))
|
||||
)
|
||||
if e.stdio.terminal {
|
||||
@ -141,15 +140,18 @@ func (e *execProcess) Start(ctx context.Context) (err error) {
|
||||
return errors.Wrap(err, "failed to create runc console socket")
|
||||
}
|
||||
defer socket.Close()
|
||||
} else if e.stdio.isNull() {
|
||||
if e.io, err = runc.NewNullIO(); err != nil {
|
||||
return errors.Wrap(err, "creating new NULL IO")
|
||||
}
|
||||
} else {
|
||||
if io, err = runc.NewPipeIO(); err != nil {
|
||||
if e.io, err = runc.NewPipeIO(); err != nil {
|
||||
return errors.Wrap(err, "failed to create runc io pipes")
|
||||
}
|
||||
e.io = io
|
||||
}
|
||||
opts := &runc.ExecOpts{
|
||||
PidFile: pidfile,
|
||||
IO: io,
|
||||
IO: e.io,
|
||||
Detach: true,
|
||||
}
|
||||
if socket != nil {
|
||||
@ -175,8 +177,8 @@ func (e *execProcess) Start(ctx context.Context) (err error) {
|
||||
if e.console, err = e.parent.platform.copyConsole(ctx, console, e.stdio.stdin, e.stdio.stdout, e.stdio.stderr, &e.WaitGroup, ©WaitGroup); err != nil {
|
||||
return errors.Wrap(err, "failed to start console copy")
|
||||
}
|
||||
} else {
|
||||
if err := copyPipes(ctx, io, e.stdio.stdin, e.stdio.stdout, e.stdio.stderr, &e.WaitGroup, ©WaitGroup); err != nil {
|
||||
} else if !e.stdio.isNull() {
|
||||
if err := copyPipes(ctx, e.io, e.stdio.stdin, e.stdio.stdout, e.stdio.stderr, &e.WaitGroup, ©WaitGroup); err != nil {
|
||||
return errors.Wrap(err, "failed to start io pipe copy")
|
||||
}
|
||||
}
|
||||
|
@ -117,18 +117,20 @@ func newInitProcess(context context.Context, plat platform, path, namespace, wor
|
||||
var (
|
||||
err error
|
||||
socket *runc.Socket
|
||||
io runc.IO
|
||||
)
|
||||
if r.Terminal {
|
||||
if socket, err = runc.NewTempConsoleSocket(); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create OCI runtime console socket")
|
||||
}
|
||||
defer socket.Close()
|
||||
} else if hasNoIO(r) {
|
||||
if p.io, err = runc.NewNullIO(); err != nil {
|
||||
return nil, errors.Wrap(err, "creating new NULL IO")
|
||||
}
|
||||
} else {
|
||||
if io, err = runc.NewPipeIO(); err != nil {
|
||||
if p.io, err = runc.NewPipeIO(); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create OCI runtime io pipes")
|
||||
}
|
||||
p.io = io
|
||||
}
|
||||
pidFile := filepath.Join(path, "init.pid")
|
||||
if r.Checkpoint != "" {
|
||||
@ -139,7 +141,7 @@ func newInitProcess(context context.Context, plat platform, path, namespace, wor
|
||||
ParentPath: r.ParentCheckpoint,
|
||||
},
|
||||
PidFile: pidFile,
|
||||
IO: io,
|
||||
IO: p.io,
|
||||
NoPivot: options.NoPivotRoot,
|
||||
Detach: true,
|
||||
NoSubreaper: true,
|
||||
@ -150,7 +152,7 @@ func newInitProcess(context context.Context, plat platform, path, namespace, wor
|
||||
} else {
|
||||
opts := &runc.CreateOpts{
|
||||
PidFile: pidFile,
|
||||
IO: io,
|
||||
IO: p.io,
|
||||
NoPivot: options.NoPivotRoot,
|
||||
NoNewKeyring: options.NoNewKeyring,
|
||||
}
|
||||
@ -180,8 +182,8 @@ func newInitProcess(context context.Context, plat platform, path, namespace, wor
|
||||
return nil, errors.Wrap(err, "failed to start console copy")
|
||||
}
|
||||
p.console = console
|
||||
} else {
|
||||
if err := copyPipes(context, io, r.Stdin, r.Stdout, r.Stderr, &p.WaitGroup, ©WaitGroup); err != nil {
|
||||
} else if !hasNoIO(r) {
|
||||
if err := copyPipes(context, p.io, r.Stdin, r.Stdout, r.Stderr, &p.WaitGroup, ©WaitGroup); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to start io pipe copy")
|
||||
}
|
||||
}
|
||||
@ -427,3 +429,7 @@ func checkKillError(err error) error {
|
||||
}
|
||||
return errors.Wrapf(err, "unknown error after kill")
|
||||
}
|
||||
|
||||
func hasNoIO(r *shimapi.CreateTaskRequest) bool {
|
||||
return r.Stdin == "" && r.Stdout == "" && r.Stderr == ""
|
||||
}
|
||||
|
@ -17,6 +17,10 @@ type stdio struct {
|
||||
terminal bool
|
||||
}
|
||||
|
||||
func (s stdio) isNull() bool {
|
||||
return s.stdin == "" && s.stdout == "" && s.stderr == ""
|
||||
}
|
||||
|
||||
type process interface {
|
||||
// ID returns the id for the process
|
||||
ID() string
|
||||
|
Loading…
Reference in New Issue
Block a user