linux: Bubble up runc error message

Signed-off-by: Kenfe-Mickael Laventure <mickael.laventure@gmail.com>
This commit is contained in:
Kenfe-Mickael Laventure 2017-06-14 08:51:44 -07:00
parent 33598cc5d3
commit 5922cfaba8
No known key found for this signature in database
GPG Key ID: 40CF16616B361216
2 changed files with 65 additions and 10 deletions

View File

@ -86,7 +86,7 @@ func newExecProcess(context context.Context, path string, r *shimapi.ExecRequest
spec.Terminal = r.Terminal spec.Terminal = r.Terminal
if err := parent.runc.Exec(context, parent.id, spec, opts); err != nil { if err := parent.runc.Exec(context, parent.id, spec, opts); err != nil {
return nil, err return nil, parent.runcError(err, "runc exec failed")
} }
if r.Stdin != "" { if r.Stdin != "" {
sc, err := fifo.OpenFifo(context, r.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0) sc, err := fifo.OpenFifo(context, r.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)

View File

@ -4,6 +4,7 @@ package shim
import ( import (
"context" "context"
"encoding/json"
"fmt" "fmt"
"io" "io"
"os" "os"
@ -109,7 +110,7 @@ func newInitProcess(context context.Context, path, namespace string, r *shimapi.
NoSubreaper: true, NoSubreaper: true,
} }
if _, err := p.runc.Restore(context, r.ID, r.Bundle, opts); err != nil { if _, err := p.runc.Restore(context, r.ID, r.Bundle, opts); err != nil {
return nil, err return nil, p.runcError(err, "runc restore failed")
} }
} else { } else {
opts := &runc.CreateOpts{ opts := &runc.CreateOpts{
@ -121,7 +122,7 @@ func newInitProcess(context context.Context, path, namespace string, r *shimapi.
opts.ConsoleSocket = socket opts.ConsoleSocket = socket
} }
if err := p.runc.Create(context, r.ID, r.Bundle, opts); err != nil { if err := p.runc.Create(context, r.ID, r.Bundle, opts); err != nil {
return nil, err return nil, p.runcError(err, "runc create failed")
} }
} }
if r.Stdin != "" { if r.Stdin != "" {
@ -173,7 +174,7 @@ func (p *initProcess) ExitedAt() time.Time {
func (p *initProcess) ContainerStatus(ctx context.Context) (string, error) { func (p *initProcess) ContainerStatus(ctx context.Context) (string, error) {
c, err := p.runc.State(ctx, p.id) c, err := p.runc.State(ctx, p.id)
if err != nil { if err != nil {
return "", err return "", p.runcError(err, "runc state failed")
} }
return c.Status, nil return c.Status, nil
} }
@ -181,7 +182,8 @@ func (p *initProcess) ContainerStatus(ctx context.Context) (string, error) {
func (p *initProcess) Start(context context.Context) error { func (p *initProcess) Start(context context.Context) error {
p.mu.Lock() p.mu.Lock()
defer p.mu.Unlock() defer p.mu.Unlock()
return p.runc.Start(context, p.id) err := p.runc.Start(context, p.id)
return p.runcError(err, "runc start failed")
} }
func (p *initProcess) Exited(status int) { func (p *initProcess) Exited(status int) {
@ -208,7 +210,7 @@ func (p *initProcess) Delete(context context.Context) error {
} }
p.io.Close() p.io.Close()
} }
return err return p.runcError(err, "runc delete failed")
} }
func (p *initProcess) Resize(ws console.WinSize) error { func (p *initProcess) Resize(ws console.WinSize) error {
@ -219,23 +221,27 @@ func (p *initProcess) Resize(ws console.WinSize) error {
} }
func (p *initProcess) Pause(context context.Context) error { func (p *initProcess) Pause(context context.Context) error {
return p.runc.Pause(context, p.id) err := p.runc.Pause(context, p.id)
return p.runcError(err, "runc pause failed")
} }
func (p *initProcess) Resume(context context.Context) error { func (p *initProcess) Resume(context context.Context) error {
return p.runc.Resume(context, p.id) err := p.runc.Resume(context, p.id)
return p.runcError(err, "runc resume failed")
} }
func (p *initProcess) Kill(context context.Context, signal uint32, all bool) error { func (p *initProcess) Kill(context context.Context, signal uint32, all bool) error {
return p.runc.Kill(context, p.id, int(signal), &runc.KillOpts{ err := p.runc.Kill(context, p.id, int(signal), &runc.KillOpts{
All: all, All: all,
}) })
return p.runcError(err, "runc kill failed")
} }
func (p *initProcess) killAll(context context.Context) error { func (p *initProcess) killAll(context context.Context) error {
return p.runc.Kill(context, p.id, int(syscall.SIGKILL), &runc.KillOpts{ err := p.runc.Kill(context, p.id, int(syscall.SIGKILL), &runc.KillOpts{
All: true, All: true,
}) })
return p.runcError(err, "runc killall failed")
} }
func (p *initProcess) Signal(sig int) error { func (p *initProcess) Signal(sig int) error {
@ -271,6 +277,55 @@ func (p *initProcess) Checkpoint(context context.Context, r *shimapi.CheckpointR
return nil return nil
} }
// TODO(mlaventure): move to runc package?
func getLastRuncError(r *runc.Runc) (string, error) {
if r.Log == "" {
return "", nil
}
f, err := os.OpenFile(r.Log, os.O_RDONLY, 0400)
if err != nil {
return "", err
}
var (
errMsg string
log struct {
Level string
Msg string
Time time.Time
}
)
dec := json.NewDecoder(f)
for err = nil; err == nil; {
if err = dec.Decode(&log); err != nil && err != io.EOF {
return "", err
}
if log.Level == "error" {
errMsg = strings.TrimSpace(log.Msg)
}
}
return errMsg, nil
}
func (p *initProcess) runcError(rErr error, msg string) error {
if rErr == nil {
return nil
}
rMsg, err := getLastRuncError(p.runc)
switch {
case err != nil:
return errors.Wrapf(err, "%s: %s (%s)", msg, "unable to retrieve runc error", err.Error())
case rMsg == "":
return errors.Wrap(err, msg)
default:
return errors.Errorf("%s: %s", msg, rMsg)
}
}
// criuError returns only the first line of the error message from criu // criuError returns only the first line of the error message from criu
// it tries to add an invalid dump log location when returning the message // it tries to add an invalid dump log location when returning the message
func criuError(err error) string { func criuError(err error) string {