Merge pull request #27766 from Banana-Cultist/podman-events-oom

Improve OOMKilled Visibility
This commit is contained in:
Paul Holzinger
2026-03-12 19:23:02 +01:00
committed by GitHub
8 changed files with 64 additions and 3 deletions

View File

@@ -54,6 +54,8 @@ type Event struct {
// containerExitCode is for storing the exit code of a container which can // containerExitCode is for storing the exit code of a container which can
// be used for "internal" event notification // be used for "internal" event notification
ContainerExitCode *int `json:",omitempty"` ContainerExitCode *int `json:",omitempty"`
// OOMKilled indicates whether the container was killed by an OOM condition
OOMKilled *bool `json:",omitempty"`
// ID can be for the container, image, volume, etc // ID can be for the container, image, volume, etc
ID string `json:",omitempty"` ID string `json:",omitempty"`
// Image used where applicable // Image used where applicable
@@ -81,6 +83,7 @@ type Event struct {
func newEventFromLibpodEvent(e *events.Event) Event { func newEventFromLibpodEvent(e *events.Event) Event {
return Event{ return Event{
ContainerExitCode: e.ContainerExitCode, ContainerExitCode: e.ContainerExitCode,
OOMKilled: e.OOMKilled,
ID: e.ID, ID: e.ID,
Image: e.Image, Image: e.Image,
Name: e.Name, Name: e.Name,

View File

@@ -127,6 +127,7 @@ Format the output to JSON Lines or using the given Go template.
| .Image | Name of image being run (string) | | .Image | Name of image being run (string) |
| .Name | Container name (string) | | .Name | Container name (string) |
| .Network | Name of network being used (string) | | .Network | Name of network being used (string) |
| .OOMKilled | Whether container was killed due to OOM (bool) |
| .PodID | ID of pod associated with container, if any | | .PodID | ID of pod associated with container, if any |
| .Status | Event status (e.g., create, start, died, ...) | | .Status | Event status (e.g., create, start, died, ...) |
| .Time | Event timestamp (string) | | .Time | Event timestamp (string) |

View File

@@ -147,6 +147,12 @@ podman container inspect --latest --format {{.EffectiveCaps}}
[CAP_CHOWN CAP_DAC_OVERRIDE CAP_FSETID CAP_FOWNER CAP_SETGID CAP_SETUID CAP_SETFCAP CAP_SETPCAP CAP_NET_BIND_SERVICE CAP_KILL] [CAP_CHOWN CAP_DAC_OVERRIDE CAP_FSETID CAP_FOWNER CAP_SETGID CAP_SETUID CAP_SETFCAP CAP_SETPCAP CAP_NET_BIND_SERVICE CAP_KILL]
``` ```
Inspect the specified container for the `OOMKilled` format specifier
```
podman container inspect myContainer --format {{.State.OOMKilled}}
false
```
Inspect the specified pod for the `Name` format specifier: Inspect the specified pod for the `Name` format specifier:
``` ```
# podman inspect myPod --type pod --format "{{.Name}}" # podman inspect myPod --type pod --format "{{.Name}}"

View File

@@ -105,9 +105,11 @@ func (c *Container) newContainerExitedEvent(exitCode int32) {
intExitCode := int(exitCode) intExitCode := int(exitCode)
e.ContainerExitCode = &intExitCode e.ContainerExitCode = &intExitCode
e.Details = events.Details{ attrs := c.Labels()
Attributes: c.Labels(), if c.state.OOMKilled {
e.OOMKilled = &c.state.OOMKilled
} }
e.Details = events.Details{Attributes: attrs}
if err := c.runtime.eventer.Write(e); err != nil { if err := c.runtime.eventer.Write(e); err != nil {
logrus.Errorf("Unable to write container exited event: %q", err) logrus.Errorf("Unable to write container exited event: %q", err)

View File

@@ -24,6 +24,8 @@ type Event struct {
// ContainerExitCode is for storing the exit code of a container which can // ContainerExitCode is for storing the exit code of a container which can
// be used for "internal" event notification // be used for "internal" event notification
ContainerExitCode *int `json:",omitempty"` ContainerExitCode *int `json:",omitempty"`
// OOMKilled indicates whether the container was killed by an OOM condition
OOMKilled *bool `json:",omitempty"`
// ID can be for the container, image, volume, etc // ID can be for the container, image, volume, etc
ID string `json:",omitempty"` ID string `json:",omitempty"`
// Image used where applicable // Image used where applicable

View File

@@ -50,6 +50,9 @@ func (e EventJournalD) Write(ee Event) error {
if ee.ContainerExitCode != nil { if ee.ContainerExitCode != nil {
m["PODMAN_EXIT_CODE"] = strconv.Itoa(*ee.ContainerExitCode) m["PODMAN_EXIT_CODE"] = strconv.Itoa(*ee.ContainerExitCode)
} }
if ee.OOMKilled != nil {
m["PODMAN_OOM_KILLED"] = strconv.FormatBool(*ee.OOMKilled)
}
if ee.PodID != "" { if ee.PodID != "" {
m["PODMAN_POD_ID"] = ee.PodID m["PODMAN_POD_ID"] = ee.PodID
} }
@@ -250,6 +253,14 @@ func newEventFromJournalEntry(entry *sdjournal.JournalEntry) (*Event, error) {
newEvent.ContainerExitCode = &intCode newEvent.ContainerExitCode = &intCode
} }
} }
if val, ok := entry.Fields["PODMAN_OOM_KILLED"]; ok {
oomKilled, err := strconv.ParseBool(val)
if err != nil {
logrus.Errorf("Parsing event oom killed value %s", val)
} else {
newEvent.OOMKilled = &oomKilled
}
}
if err := getLabelsFromJournal(entry, &newEvent); err != nil { if err := getLabelsFromJournal(entry, &newEvent); err != nil {
return nil, err return nil, err
} }

View File

@@ -29,6 +29,16 @@ func ConvertToLibpodEvent(e Event) *libpodEvents.Event {
if err != nil { if err != nil {
return nil return nil
} }
var (
oomKilled bool
hasOOM bool
)
if raw, ok := e.Actor.Attributes["oomKilled"]; ok {
if parsed, err := strconv.ParseBool(raw); err == nil {
oomKilled = parsed
hasOOM = true
}
}
image := e.Actor.Attributes["image"] image := e.Actor.Attributes["image"]
name := e.Actor.Attributes["name"] name := e.Actor.Attributes["name"]
network := e.Actor.Attributes["network"] network := e.Actor.Attributes["network"]
@@ -41,7 +51,8 @@ func ConvertToLibpodEvent(e Event) *libpodEvents.Event {
delete(details, "podId") delete(details, "podId")
delete(details, "error") delete(details, "error")
delete(details, "containerExitCode") delete(details, "containerExitCode")
return &libpodEvents.Event{ delete(details, "oomKilled")
newEvent := &libpodEvents.Event{
ContainerExitCode: &exitCode, ContainerExitCode: &exitCode,
ID: e.Actor.ID, ID: e.Actor.ID,
Image: image, Image: image,
@@ -57,6 +68,10 @@ func ConvertToLibpodEvent(e Event) *libpodEvents.Event {
Attributes: details, Attributes: details,
}, },
} }
if hasOOM {
newEvent.OOMKilled = &oomKilled
}
return newEvent
} }
// ConvertToEntitiesEvent converts a libpod event to an entities one. // ConvertToEntitiesEvent converts a libpod event to an entities one.
@@ -70,6 +85,9 @@ func ConvertToEntitiesEvent(e libpodEvents.Event) *types.Event {
if e.ContainerExitCode != nil { if e.ContainerExitCode != nil {
attributes["containerExitCode"] = strconv.Itoa(*e.ContainerExitCode) attributes["containerExitCode"] = strconv.Itoa(*e.ContainerExitCode)
} }
if e.OOMKilled != nil {
attributes["oomKilled"] = strconv.FormatBool(*e.OOMKilled)
}
attributes["podId"] = e.PodID attributes["podId"] = e.PodID
if e.Network != "" { if e.Network != "" {
attributes["network"] = e.Network attributes["network"] = e.Network

View File

@@ -338,6 +338,24 @@ EOF
assert "$output" = "$lvalue" "podman-events output includes container label" assert "$output" = "$lvalue" "podman-events output includes container label"
} }
@test "events - died event contains OOMKilled attribute" {
local cname=c-$(safename)
run_podman run -d --rm \
--name $cname \
--memory 20m \
--cgroup-conf=memory.oom.group=1 \
$IMAGE sh -c "x=a; while :; do x=\$x\$x\$x\$x; done"
run_podman wait $cname
run_podman events \
--filter container=$cname \
--filter event=died \
--stream=false \
--format "{{.OOMKilled}}"
assert "$output" = "true" "OOMKilled attribute should be present and set to true"
}
# bats test_tags=ci:parallel # bats test_tags=ci:parallel
@test "events - backend none should error" { @test "events - backend none should error" {
skip_if_remote "remote does not support --events-backend" skip_if_remote "remote does not support --events-backend"