Cleanup binary IO resources on error

Signed-off-by: Maksym Pavlenko <makpav@amazon.com>
This commit is contained in:
Maksym Pavlenko 2020-04-17 15:56:21 -07:00
parent 0dc7c85956
commit 9175401b28

View File

@ -246,11 +246,12 @@ func (c *countingWriteCloser) Close() error {
} }
// NewBinaryIO runs a custom binary process for pluggable shim logging // NewBinaryIO runs a custom binary process for pluggable shim logging
func NewBinaryIO(ctx context.Context, id string, uri *url.URL) (runc.IO, error) { func NewBinaryIO(ctx context.Context, id string, uri *url.URL) (_ runc.IO, err error) {
ns, err := namespaces.NamespaceRequired(ctx) ns, err := namespaces.NamespaceRequired(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var args []string var args []string
for k, vs := range uri.Query() { for k, vs := range uri.Query() {
args = append(args, k) args = append(args, k)
@ -259,20 +260,35 @@ func NewBinaryIO(ctx context.Context, id string, uri *url.URL) (runc.IO, error)
} }
} }
var closers []func() error
defer func() {
if err == nil {
return
}
result := multierror.Append(err)
for _, fn := range closers {
result = multierror.Append(result, fn())
}
err = multierror.Flatten(result)
}()
out, err := newPipe() out, err := newPipe()
if err != nil { if err != nil {
return nil, err return nil, errors.Wrap(err, "failed to create stdout pipes")
} }
closers = append(closers, out.Close)
serr, err := newPipe() serr, err := newPipe()
if err != nil { if err != nil {
return nil, err return nil, errors.Wrap(err, "failed to create stderr pipes")
} }
closers = append(closers, serr.Close)
r, w, err := os.Pipe() r, w, err := os.Pipe()
if err != nil { if err != nil {
return nil, err return nil, err
} }
closers = append(closers, r.Close, w.Close)
cmd := exec.Command(uri.Path, args...) cmd := exec.Command(uri.Path, args...)
cmd.Env = append(cmd.Env, cmd.Env = append(cmd.Env,
@ -284,17 +300,21 @@ func NewBinaryIO(ctx context.Context, id string, uri *url.URL) (runc.IO, error)
// don't need to register this with the reaper or wait when // don't need to register this with the reaper or wait when
// running inside a shim // running inside a shim
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
return nil, err return nil, errors.Wrap(err, "failed to start binary process")
} }
closers = append(closers, func() error { return cmd.Process.Kill() })
// close our side of the pipe after start // close our side of the pipe after start
if err := w.Close(); err != nil { if err := w.Close(); err != nil {
return nil, err return nil, errors.Wrap(err, "failed to close write pipe after start")
} }
// wait for the logging binary to be ready // wait for the logging binary to be ready
b := make([]byte, 1) b := make([]byte, 1)
if _, err := r.Read(b); err != nil && err != io.EOF { if _, err := r.Read(b); err != nil && err != io.EOF {
return nil, err return nil, errors.Wrap(err, "failed to read from logging binary")
} }
return &binaryIO{ return &binaryIO{
cmd: cmd, cmd: cmd,
out: out, out: out,
@ -423,9 +443,15 @@ type pipe struct {
} }
func (p *pipe) Close() error { func (p *pipe) Close() error {
err := p.w.Close() var result *multierror.Error
if rerr := p.r.Close(); err == nil {
err = rerr if err := p.w.Close(); err != nil {
result = multierror.Append(result, errors.Wrap(err, "failed to close write pipe"))
} }
return err
if err := p.r.Close(); err != nil {
result = multierror.Append(result, errors.Wrap(err, "failed to close read pipe"))
}
return multierror.Prefix(result.ErrorOrNil(), "pipe:")
} }