// notifyOnOOM returns a channel that signals if the container received an OOM notification // for any process. If it is unable to subscribe to OOM notifications then a closed // channel is returned as it will be non-blocking and return the correct result when read. func notifyOnOOM(container libcontainer.Container) <-chan struct{} { oom, err := container.NotifyOOM() if err != nil { logrus.Warnf("Your kernel does not support OOM notifications: %s", err) c := make(chan struct{}) close(c) return c } return oom }
func destroy(container libcontainer.Container) { status, err := container.Status() if err != nil { logrus.Error(err) } if status != libcontainer.Checkpointed { if err := container.Destroy(); err != nil { logrus.Error(err) } } }
func killContainer(container libcontainer.Container) error { container.Signal(syscall.SIGKILL) for i := 0; i < 100; i++ { time.Sleep(100 * time.Millisecond) if err := container.Signal(syscall.Signal(0)); err != nil { destroy(container) return nil } } return fmt.Errorf("container init still running") }
func killCgroupProcs(c libcontainer.Container) { var procs []*os.Process if err := c.Pause(); err != nil { logrus.Warn(err) } pids, err := c.Processes() if err != nil { // don't care about childs if we can't get them, this is mostly because cgroup already deleted logrus.Warnf("Failed to get processes from container %s: %v", c.ID(), err) } for _, pid := range pids { if p, err := os.FindProcess(pid); err == nil { procs = append(procs, p) if err := p.Kill(); err != nil { logrus.Warn(err) } } } if err := c.Resume(); err != nil { logrus.Warn(err) } for _, p := range procs { if _, err := p.Wait(); err != nil { logrus.Warn(err) } } }
// runProcess will create a new process in the specified container // by executing the process specified in the 'config'. func runProcess(container libcontainer.Container, config *specs.Process, listenFDs []*os.File, console string, pidFile string, detach bool) (int, error) { process := newProcess(*config) // Add extra file descriptors if needed if len(listenFDs) > 0 { process.Env = append(process.Env, fmt.Sprintf("LISTEN_FDS=%d", len(listenFDs)), "LISTEN_PID=1") process.ExtraFiles = append(process.ExtraFiles, listenFDs...) } rootuid, err := container.Config().HostUID() if err != nil { return -1, err } tty, err := setupIO(process, rootuid, console, config.Terminal, detach) if err != nil { return -1, err } handler := newSignalHandler(tty) defer handler.Close() if err := container.Start(process); err != nil { if tty != nil { tty.Close() } return -1, err } if pidFile != "" { if err := createPidFile(pidFile, process); err != nil { process.Signal(syscall.SIGKILL) process.Wait() if tty != nil { tty.Close() } return -1, err } } if detach { return 0, nil } return handler.forward(process) }
func destroy(container libcontainer.Container) { if err := container.Destroy(); err != nil { logrus.Error(err) } }
// runCmdInDir runs the given command inside a container under dir func runCmdInDir(im *schema.ImageManifest, cmd, dir string, jail bool, mounts []*configs.Mount) error { exePath, err := osext.Executable() if err != nil { return fmt.Errorf("error getting path to the current executable: %v", err) } factory, err := libcontainer.New(dir, libcontainer.InitArgs(exePath, "init")) if err != nil { return fmt.Errorf("error creating a container factory: %v", err) } // The containter ID doesn't really matter here... using a UUID containerID := uuid.NewV4().String() var container libcontainer.Container if jail { config := &configs.Config{} if err := json.Unmarshal([]byte(LibcontainerDefaultConfig), config); err != nil { return fmt.Errorf("error unmarshalling default config: %v", err) } config.Rootfs = dir config.Readonlyfs = false container, err = factory.Create(containerID, config) if err != nil { return fmt.Errorf("error creating a container: %v", err) } } else { container, err = factory.Create(containerID, &configs.Config{ Rootfs: dir, Mounts: mounts, Cgroups: &configs.Cgroup{ Name: containerID, Parent: "system", AllowAllDevices: false, AllowedDevices: configs.DefaultAllowedDevices, }, }) if err != nil { return fmt.Errorf("error creating a container: %v", err) } } process := &libcontainer.Process{ Args: strings.Fields(cmd), User: "******", Stdin: os.Stdin, Stdout: os.Stdout, Stderr: os.Stderr, } if im.App != nil { process.Env = util.ACIEnvironmentToList(im.App.Environment) } process.Env = []string{"PATH=/usr/bin:/sbin/:/bin"} if err := container.Start(process); err != nil { return fmt.Errorf("error starting the process inside the container: %v", err) } _, err = process.Wait() if err != nil { return fmt.Errorf("error running the process: %v", err) } if err := container.Destroy(); err != nil { return fmt.Errorf("error destroying the container: %v", err) } return nil }