Merge pull request #135 from docker/deps-errors

Return errors from shim and missing shim/runc
This commit is contained in:
Michael Crosby 2016-03-17 14:53:20 -07:00
commit 5617360b3a
3 changed files with 66 additions and 38 deletions

View file

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"os" "os"
"os/signal" "os/signal"
"path/filepath"
"syscall" "syscall"
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
@ -12,14 +13,6 @@ import (
"github.com/docker/docker/pkg/term" "github.com/docker/docker/pkg/term"
) )
func setupLogger() {
f, err := os.OpenFile("/tmp/shim.log", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0755)
if err != nil {
panic(err)
}
logrus.SetOutput(f)
}
// containerd-shim is a small shim that sits in front of a runtime implementation // containerd-shim is a small shim that sits in front of a runtime implementation
// that allows it to be repartented to init and handle reattach from the caller. // that allows it to be repartented to init and handle reattach from the caller.
// //
@ -27,50 +20,65 @@ func setupLogger() {
// to the state directory where the shim can locate fifos and other information. // to the state directory where the shim can locate fifos and other information.
func main() { func main() {
flag.Parse() flag.Parse()
cwd, err := os.Getwd()
if err != nil {
panic(err)
}
f, err := os.OpenFile(filepath.Join(cwd, "shim-log.json"), os.O_CREATE|os.O_WRONLY|os.O_APPEND|os.O_SYNC, 0666)
if err != nil {
panic(err)
}
logrus.SetOutput(f)
logrus.SetFormatter(&logrus.JSONFormatter{})
if err := start(); err != nil {
// log the error instead of writing to stderr because the shim will have
// /dev/null as it's stdio because it is supposed to be reparented to system
// init and will not have anyone to read from it
logrus.Error(err)
f.Close()
os.Exit(1)
}
}
func start() error {
// start handling signals as soon as possible so that things are properly reaped // start handling signals as soon as possible so that things are properly reaped
// or if runtime exits before we hit the handler // or if runtime exits before we hit the handler
signals := make(chan os.Signal, 2048) signals := make(chan os.Signal, 2048)
signal.Notify(signals) signal.Notify(signals)
// set the shim as the subreaper for all orphaned processes created by the container // set the shim as the subreaper for all orphaned processes created by the container
if err := osutils.SetSubreaper(1); err != nil { if err := osutils.SetSubreaper(1); err != nil {
logrus.WithField("error", err).Error("shim: set as subreaper") return err
return
} }
// open the exit pipe // open the exit pipe
f, err := os.OpenFile("exit", syscall.O_WRONLY, 0) f, err := os.OpenFile("exit", syscall.O_WRONLY, 0)
if err != nil { if err != nil {
logrus.WithField("error", err).Error("shim: open exit pipe") return err
return
} }
defer f.Close() defer f.Close()
control, err := os.OpenFile("control", syscall.O_RDWR, 0) control, err := os.OpenFile("control", syscall.O_RDWR, 0)
if err != nil { if err != nil {
logrus.WithField("error", err).Error("shim: open control pipe") return err
return
} }
defer control.Close() defer control.Close()
p, err := newProcess(flag.Arg(0), flag.Arg(1), flag.Arg(2)) p, err := newProcess(flag.Arg(0), flag.Arg(1), flag.Arg(2))
if err != nil { if err != nil {
logrus.WithField("error", err).Error("shim: create new process") return err
return
} }
defer func() { defer func() {
if err := p.Close(); err != nil { if err := p.Close(); err != nil {
logrus.WithField("error", err).Error("shim: close stdio") logrus.Warn(err)
} }
}() }()
if err := p.start(); err != nil { if err := p.start(); err != nil {
p.delete() p.delete()
logrus.WithField("error", err).Error("shim: start process") return err
return
} }
go func() { go func() {
for { for {
var msg, w, h int var msg, w, h int
if _, err := fmt.Fscanf(control, "%d %d %d\n", &msg, &w, &h); err != nil { if _, err := fmt.Fscanf(control, "%d %d %d\n", &msg, &w, &h); err != nil {
logrus.WithField("error", err).Error("shim: reading from control") logrus.Warn(err)
} }
logrus.Info("got control message")
switch msg { switch msg {
case 0: case 0:
// close stdin // close stdin
@ -89,12 +97,11 @@ func main() {
}() }()
var exitShim bool var exitShim bool
for s := range signals { for s := range signals {
logrus.WithField("signal", s).Debug("shim: received signal")
switch s { switch s {
case syscall.SIGCHLD: case syscall.SIGCHLD:
exits, err := osutils.Reap() exits, err := osutils.Reap()
if err != nil { if err != nil {
logrus.WithField("error", err).Error("shim: reaping child processes") logrus.Warn(err)
} }
for _, e := range exits { for _, e := range exits {
// check to see if runtime is one of the processes that has exited // check to see if runtime is one of the processes that has exited
@ -105,10 +112,7 @@ func main() {
"status": e.Status, "status": e.Status,
}).Info("shim: runtime exited") }).Info("shim: runtime exited")
if err := writeInt("exitStatus", e.Status); err != nil { if err := writeInt("exitStatus", e.Status); err != nil {
logrus.WithFields(logrus.Fields{ logrus.WithFields(logrus.Fields{"status": e.Status}).Warn(err)
"error": err,
"status": e.Status,
}).Error("shim: write exit status")
} }
} }
} }
@ -117,9 +121,10 @@ func main() {
if exitShim { if exitShim {
p.delete() p.delete()
p.Wait() p.Wait()
return return nil
} }
} }
return nil
} }
func writeInt(path string, i int) error { func writeInt(path string, i int) error {

View file

@ -134,6 +134,11 @@ func (p *process) start() error {
Pdeathsig: syscall.SIGKILL, Pdeathsig: syscall.SIGKILL,
} }
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
if exErr, ok := err.(*exec.Error); ok {
if exErr.Err == exec.ErrNotFound || exErr.Err == os.ErrNotExist {
return fmt.Errorf("runc not installed on system")
}
}
return err return err
} }
p.stdio.stdout.Close() p.stdio.stdout.Close()

View file

@ -154,13 +154,9 @@ func (c *container) Start(checkpoint string, s Stdio) (Process, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := cmd.Start(); err != nil { if err := c.startCmd(InitProcessID, cmd, p); err != nil {
return nil, err return nil, err
} }
if err := waitForStart(p, cmd); err != nil {
return nil, err
}
c.processes[InitProcessID] = p
return p, nil return p, nil
} }
@ -198,14 +194,26 @@ func (c *container) Exec(pid string, pspec specs.ProcessSpec, s Stdio) (pp Proce
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := cmd.Start(); err != nil { if err := c.startCmd(pid, cmd, p); err != nil {
return nil, err return nil, err
} }
return p, nil
}
func (c *container) startCmd(pid string, cmd *exec.Cmd, p *process) error {
if err := cmd.Start(); err != nil {
if exErr, ok := err.(*exec.Error); ok {
if exErr.Err == exec.ErrNotFound || exErr.Err == os.ErrNotExist {
return fmt.Errorf("containerd-shim not installed on system")
}
}
return err
}
if err := waitForStart(p, cmd); err != nil { if err := waitForStart(p, cmd); err != nil {
return nil, err return err
} }
c.processes[pid] = p c.processes[pid] = p
return p, nil return nil
} }
func (c *container) getLibctContainer() (libcontainer.Container, error) { func (c *container) getLibctContainer() (libcontainer.Container, error) {
@ -312,8 +320,18 @@ func waitForStart(p *process, cmd *exec.Cmd) error {
} }
if !alive { if !alive {
// runc could have failed to run the container so lets get the error // runc could have failed to run the container so lets get the error
// out of the logs // out of the logs or the shim could have encountered an error
messages, err := readLogMessages(filepath.Join(p.root, "log.json")) messages, err := readLogMessages(filepath.Join(p.root, "shim-log.json"))
if err != nil {
return err
}
for _, m := range messages {
if m.Level == "error" {
return errors.New(m.Msg)
}
}
// no errors reported back from shim, check for runc/runtime errors
messages, err = readLogMessages(filepath.Join(p.root, "log.json"))
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return ErrContainerNotStarted return ErrContainerNotStarted