func daemon(context *cli.Context) error { // setup a standard reaper so that we don't leave any zombies if we are still alive // this is just good practice because we are spawning new processes s := make(chan os.Signal, 2048) signal.Notify(s, syscall.SIGCHLD, syscall.SIGTERM, syscall.SIGINT) if err := osutils.SetSubreaper(1); err != nil { logrus.WithField("error", err).Error("containerd: set subpreaper") } sv, err := supervisor.New( context.String("state-dir"), context.String("runtime"), context.String("shim"), context.StringSlice("runtime-args"), context.Duration("start-timeout"), context.Int("retain-count")) if err != nil { return err } wg := &sync.WaitGroup{} for i := 0; i < 10; i++ { wg.Add(1) w := supervisor.NewWorker(sv, wg) go w.Start() } if err := sv.Start(); err != nil { return err } // Split the listen string of the form proto://addr listenSpec := context.String("listen") listenParts := strings.SplitN(listenSpec, "://", 2) if len(listenParts) != 2 { return fmt.Errorf("bad listen address format %s, expected proto://address", listenSpec) } server, err := startServer(listenParts[0], listenParts[1], sv) if err != nil { return err } for ss := range s { switch ss { case syscall.SIGCHLD: if _, err := osutils.Reap(); err != nil { logrus.WithField("error", err).Warn("containerd: reap child processes") } default: logrus.Infof("stopping containerd after receiving %s", ss) server.Stop() os.Exit(0) } } return nil }
func daemon(context *cli.Context) error { s := make(chan os.Signal, 2048) signal.Notify(s, syscall.SIGTERM, syscall.SIGINT) osutils.SetSubreaper(1) sv, err := supervisor.New( context.String("state-dir"), context.String("runtime"), context.String("shim"), context.StringSlice("runtime-args"), context.Duration("start-timeout"), context.Int("retain-count")) if err != nil { return err } wg := &sync.WaitGroup{} for i := 0; i < 10; i++ { wg.Add(1) w := supervisor.NewWorker(sv, wg) go w.Start() } if err := sv.Start(); err != nil { return err } // Split the listen string of the form proto://addr listenSpec := context.String("listen") listenParts := strings.SplitN(listenSpec, "://", 2) if len(listenParts) != 2 { return fmt.Errorf("bad listen address format %s, expected proto://address", listenSpec) } server, err := startServer(listenParts[0], listenParts[1], sv) if err != nil { return err } for ss := range s { switch ss { default: logrus.Infof("stopping containerd after receiving %s", ss) server.Stop() os.Exit(0) } } return nil }
func daemon(address, stateDir string, concurrency int, runtimeName string, runtimeArgs []string, shimName string, timeout time.Duration) error { // setup a standard reaper so that we don't leave any zombies if we are still alive // this is just good practice because we are spawning new processes s := make(chan os.Signal, 2048) signal.Notify(s, syscall.SIGCHLD, syscall.SIGTERM, syscall.SIGINT) if err := osutils.SetSubreaper(1); err != nil { logrus.WithField("error", err).Error("containerd: set subpreaper") } sv, err := supervisor.New(stateDir, runtimeName, shimName, runtimeArgs, timeout) if err != nil { return err } wg := &sync.WaitGroup{} for i := 0; i < concurrency; i++ { wg.Add(1) w := supervisor.NewWorker(sv, wg) go w.Start() } if err := sv.Start(); err != nil { return err } server, err := startServer(address, sv) if err != nil { return err } for ss := range s { switch ss { case syscall.SIGCHLD: if _, err := osutils.Reap(); err != nil { logrus.WithField("error", err).Warn("containerd: reap child processes") } default: logrus.Infof("stopping containerd after receiving %s", ss) server.Stop() os.Exit(0) } } return nil }
func start(log *os.File) error { // start handling signals as soon as possible so that things are properly reaped // or if runtime exits before we hit the handler signals := make(chan os.Signal, 2048) signal.Notify(signals) // set the shim as the subreaper for all orphaned processes created by the container if err := osutils.SetSubreaper(1); err != nil { return err } // open the exit pipe f, err := os.OpenFile("exit", syscall.O_WRONLY, 0) if err != nil { return err } defer f.Close() control, err := os.OpenFile("control", syscall.O_RDWR, 0) if err != nil { return err } defer control.Close() p, err := newProcess(flag.Arg(0), flag.Arg(1), flag.Arg(2)) if err != nil { return err } defer func() { if err := p.Close(); err != nil { writeMessage(log, "warn", err) } }() if err := p.create(); err != nil { p.delete() return err } msgC := make(chan controlMessage, 32) go func() { for { var m controlMessage if _, err := fmt.Fscanf(control, "%d %d %d\n", &m.Type, &m.Width, &m.Height); err != nil { continue } msgC <- m } }() var exitShim bool for { select { case s := <-signals: switch s { case syscall.SIGCHLD: exits, _ := osutils.Reap() for _, e := range exits { // check to see if runtime is one of the processes that has exited if e.Pid == p.pid() { exitShim = true writeInt("exitStatus", e.Status) } } } // runtime has exited so the shim can also exit if exitShim { // Let containerd take care of calling the runtime delete f.Close() p.Wait() return nil } case msg := <-msgC: switch msg.Type { case 0: // close stdin if p.stdinCloser != nil { p.stdinCloser.Close() } case 1: if p.console == nil { continue } ws := term.Winsize{ Width: uint16(msg.Width), Height: uint16(msg.Height), } term.SetWinsize(p.console.Fd(), &ws) } } } return nil }