Skip to content

Commit

Permalink
Set OOMKilled state on any OOM event
Browse files Browse the repository at this point in the history
This restores the behavior that existed prior to moby#16235 for setting
OOMKilled, while retaining the additional benefits it introduced around
emitting the oom event.

This also adds a test for the most obvious OOM cases which would have
caught this regression.

Fixes moby#18510

Signed-off-by: Euan <[email protected]>
  • Loading branch information
euank committed Dec 15, 2015
1 parent adb1975 commit 0b51314
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 3 deletions.
3 changes: 1 addition & 2 deletions container/monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,7 @@ func (m *containerMonitor) shouldRestart(exitCode int) bool {
// received ack from the execution drivers
func (m *containerMonitor) callback(processConfig *execdriver.ProcessConfig, pid int, chOOM <-chan struct{}) error {
go func() {
_, ok := <-chOOM
if ok {
for range chOOM {
m.logEvent("oom")
}
}()
Expand Down
19 changes: 18 additions & 1 deletion daemon/execdriver/native/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,10 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execd
return execdriver.ExitStatus{ExitCode: -1}, err
}

// 'oom' is used to emit 'oom' events to the eventstream, 'oomKilled' is used
// to set the 'OOMKilled' flag in state
oom := notifyOnOOM(cont)
oomKilled := notifyOnOOM(cont)
if hooks.Start != nil {
pid, err := p.Pid()
if err != nil {
Expand All @@ -198,7 +201,21 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execd
}
cont.Destroy()
destroyed = true
_, oomKill := <-oom
// oomKilled will have an oom event if any process within the container was
// OOM killed at any time, not only if the init process OOMed.
//
// Perhaps we only want the OOMKilled flag to be set if the OOM
// resulted in a container death, but there isn't a good way to do this
// because the kernel's cgroup oom notification does not provide information
// such as the PID. This could be heuristically done by checking that the OOM
// happened within some very small time slice for the container dying (and
// optionally exit-code 137), but I don't think the cgroup oom notification
// can be used to reliably determine this
//
// Even if there were multiple OOMs, it's sufficient to read one value
// because libcontainer's oom notify will discard the channel after the
// cgroup is destroyed
_, oomKill := <-oomKilled
return execdriver.ExitStatus{ExitCode: utils.ExitStatus(ps.Sys().(syscall.WaitStatus)), OOMKilled: oomKill}, nil
}

Expand Down
32 changes: 32 additions & 0 deletions integration-cli/docker_cli_oom_killed_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// +build !windows

package main

import (
"github.com/docker/docker/pkg/integration/checker"
"github.com/go-check/check"
)

func (s *DockerSuite) TestInspectOomKilledTrue(c *check.C) {
testRequires(c, DaemonIsLinux, memoryLimitSupport)

name := "testoomkilled"
_, exitCode, _ := dockerCmdWithError("run", "--name", name, "-m", "10MB", "busybox", "sh", "-c", "x=a; while true; do x=$x$x$x$x; done")

c.Assert(exitCode, checker.Equals, 137, check.Commentf("OOM exit should be 137"))

oomKilled, err := inspectField(name, "State.OOMKilled")
c.Assert(oomKilled, checker.Equals, "true")
c.Assert(err, checker.IsNil)
}

func (s *DockerSuite) TestInspectOomKilledFalse(c *check.C) {
testRequires(c, DaemonIsLinux, memoryLimitSupport)

name := "testoomkilled"
dockerCmd(c, "run", "--name", name, "-m", "10MB", "busybox", "sh", "-c", "echo hello world")

oomKilled, err := inspectField(name, "State.OOMKilled")
c.Assert(oomKilled, checker.Equals, "false")
c.Assert(err, checker.IsNil)
}

0 comments on commit 0b51314

Please sign in to comment.