Add create/start to exec processes in shim
This splits up the create and start of an exec process in the shim to have two separate steps like the initial process. This will allow better state reporting for individual process along with a more robust wait for execs. Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
@@ -36,6 +36,8 @@ type execProcess struct {
|
||||
closers []io.Closer
|
||||
stdin io.Closer
|
||||
stdio stdio
|
||||
path string
|
||||
spec specs.Process
|
||||
|
||||
parent *initProcess
|
||||
}
|
||||
@@ -44,43 +46,6 @@ func newExecProcess(context context.Context, path string, r *shimapi.ExecProcess
|
||||
if err := identifiers.Validate(id); err != nil {
|
||||
return nil, errors.Wrapf(err, "invalid exec id")
|
||||
}
|
||||
|
||||
e := &execProcess{
|
||||
id: id,
|
||||
parent: parent,
|
||||
stdio: stdio{
|
||||
stdin: r.Stdin,
|
||||
stdout: r.Stdout,
|
||||
stderr: r.Stderr,
|
||||
terminal: r.Terminal,
|
||||
},
|
||||
}
|
||||
var (
|
||||
err error
|
||||
socket *runc.Socket
|
||||
io runc.IO
|
||||
pidfile = filepath.Join(path, fmt.Sprintf("%s.pid", id))
|
||||
)
|
||||
if r.Terminal {
|
||||
if socket, err = runc.NewConsoleSocket(filepath.Join(path, "pty.sock")); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create runc console socket")
|
||||
}
|
||||
defer os.Remove(socket.Path())
|
||||
} else {
|
||||
// TODO: get uid/gid
|
||||
if io, err = runc.NewPipeIO(0, 0); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create runc io pipes")
|
||||
}
|
||||
e.io = io
|
||||
}
|
||||
opts := &runc.ExecOpts{
|
||||
PidFile: pidfile,
|
||||
IO: io,
|
||||
Detach: true,
|
||||
}
|
||||
if socket != nil {
|
||||
opts.ConsoleSocket = socket
|
||||
}
|
||||
// process exec request
|
||||
var spec specs.Process
|
||||
if err := json.Unmarshal(r.Spec.Value, &spec); err != nil {
|
||||
@@ -88,39 +53,18 @@ func newExecProcess(context context.Context, path string, r *shimapi.ExecProcess
|
||||
}
|
||||
spec.Terminal = r.Terminal
|
||||
|
||||
if err := parent.runtime.Exec(context, parent.id, spec, opts); err != nil {
|
||||
return nil, parent.runtimeError(err, "OCI runtime exec failed")
|
||||
e := &execProcess{
|
||||
id: id,
|
||||
path: path,
|
||||
parent: parent,
|
||||
spec: spec,
|
||||
stdio: stdio{
|
||||
stdin: r.Stdin,
|
||||
stdout: r.Stdout,
|
||||
stderr: r.Stderr,
|
||||
terminal: r.Terminal,
|
||||
},
|
||||
}
|
||||
if r.Stdin != "" {
|
||||
sc, err := fifo.OpenFifo(context, r.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to open stdin fifo %s", r.Stdin)
|
||||
}
|
||||
e.closers = append(e.closers, sc)
|
||||
e.stdin = sc
|
||||
}
|
||||
var copyWaitGroup sync.WaitGroup
|
||||
if socket != nil {
|
||||
console, err := socket.ReceiveMaster()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to retrieve console master")
|
||||
}
|
||||
console, err = e.parent.platform.copyConsole(context, console, r.Stdin, r.Stdout, r.Stderr, &e.WaitGroup, ©WaitGroup)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to start console copy")
|
||||
}
|
||||
e.console = console
|
||||
} else {
|
||||
if err := copyPipes(context, io, r.Stdin, r.Stdout, r.Stderr, &e.WaitGroup, ©WaitGroup); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to start io pipe copy")
|
||||
}
|
||||
}
|
||||
copyWaitGroup.Wait()
|
||||
pid, err := runc.ReadPidFile(opts.PidFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to retrieve OCI runtime exec pid")
|
||||
}
|
||||
e.pid = pid
|
||||
return e, nil
|
||||
}
|
||||
|
||||
@@ -178,3 +122,63 @@ func (e *execProcess) Stdin() io.Closer {
|
||||
func (e *execProcess) Stdio() stdio {
|
||||
return e.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 {
|
||||
if socket, err = runc.NewConsoleSocket(filepath.Join(e.path, "pty.sock")); err != nil {
|
||||
return errors.Wrap(err, "failed to create runc console socket")
|
||||
}
|
||||
defer os.Remove(socket.Path())
|
||||
} else {
|
||||
if io, err = runc.NewPipeIO(0, 0); err != nil {
|
||||
return errors.Wrap(err, "failed to create runc io pipes")
|
||||
}
|
||||
e.io = io
|
||||
}
|
||||
opts := &runc.ExecOpts{
|
||||
PidFile: pidfile,
|
||||
IO: io,
|
||||
Detach: true,
|
||||
}
|
||||
if socket != nil {
|
||||
opts.ConsoleSocket = socket
|
||||
}
|
||||
if err := e.parent.runtime.Exec(ctx, e.parent.id, e.spec, opts); err != nil {
|
||||
return e.parent.runtimeError(err, "OCI runtime exec failed")
|
||||
}
|
||||
if e.stdio.stdin != "" {
|
||||
sc, err := fifo.OpenFifo(ctx, e.stdio.stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to open stdin fifo %s", e.stdio.stdin)
|
||||
}
|
||||
e.closers = append(e.closers, sc)
|
||||
e.stdin = sc
|
||||
}
|
||||
var copyWaitGroup sync.WaitGroup
|
||||
if socket != nil {
|
||||
console, err := socket.ReceiveMaster()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to retrieve console master")
|
||||
}
|
||||
e.console = console
|
||||
if 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 {
|
||||
return errors.Wrap(err, "failed to start io pipe copy")
|
||||
}
|
||||
}
|
||||
copyWaitGroup.Wait()
|
||||
pid, err := runc.ReadPidFile(opts.PidFile)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to retrieve OCI runtime exec pid")
|
||||
}
|
||||
e.pid = pid
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user