generated from opencontainers/project-template
-
Notifications
You must be signed in to change notification settings - Fork 12
Open
Description
In cgroup v2, memory.failcnt is unavailable; memory.events provides the max failures count.
This patch updates getMemoryDataV2 to read the 'max' field from memory.events and populate MemoryData.Failcnt.
Includes TestStatMemoryPodCgroupFailcnt to cover both presence and absence of memory.events.
diff --git a/fs2/memory.go b/fs2/memory.go
index 7613307..47891ef 100644
--- a/fs2/memory.go
+++ b/fs2/memory.go
@@ -170,6 +170,13 @@ func getMemoryDataV2(path, name string) (cgroups.MemoryData, error) {
}
memoryData.MaxUsage = value
+ // Read failcnt (max events) from memory.events for cgroup v2
+ if failcnt, err := fscommon.GetValueByKey(path, "memory.events", "max"); err == nil {
+ memoryData.Failcnt = failcnt
+ } else if !os.IsNotExist(err) {
+ return cgroups.MemoryData{}, err
+ }
+
return memoryData, nil
}
diff --git a/fs2/memory_test.go b/fs2/memory_test.go
index e46dbe6..1a7c6c9 100644
--- a/fs2/memory_test.go
+++ b/fs2/memory_test.go
@@ -125,6 +125,62 @@ func TestStatMemoryPodCgroup(t *testing.T) {
}
}
+// Test that memory.events max field is parsed into Failcnt for cgroup v2
+func TestStatMemoryPodCgroupFailcnt(t *testing.T) {
+ // Use a fake cgroupfs.
+ cgroups.TestMode = true
+ fakeCgroupDir := t.TempDir()
+
+ // Prepare minimal cgroup v2 files.
+ if err := os.WriteFile(filepath.Join(fakeCgroupDir, "memory.stat"), []byte(exampleMemoryStatData), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.WriteFile(filepath.Join(fakeCgroupDir, "memory.current"), []byte("1"), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.WriteFile(filepath.Join(fakeCgroupDir, "memory.max"), []byte("2"), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.WriteFile(filepath.Join(fakeCgroupDir, "memory.peak"), []byte("3"), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ // Write memory.events with max field
+ events := "other_event 5\nmax 42\nsome_event 7\n"
+ if err := os.WriteFile(filepath.Join(fakeCgroupDir, "memory.events"), []byte(events), 0o644); err != nil {
+ t.Fatal(err)
+ }
+
+ gotStats := cgroups.NewStats()
+ if err := statMemory(fakeCgroupDir, gotStats); err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if got := gotStats.MemoryStats.Usage.Failcnt; got != 42 {
+ t.Errorf("expected Failcnt 42, got %d", got)
+ }
+
+ // Missing memory.events should not error and Failcnt remains zero
+ fakeCgroupDir = t.TempDir()
+ if err := os.WriteFile(filepath.Join(fakeCgroupDir, "memory.stat"), []byte(exampleMemoryStatData), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.WriteFile(filepath.Join(fakeCgroupDir, "memory.current"), []byte("10"), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.WriteFile(filepath.Join(fakeCgroupDir, "memory.max"), []byte("20"), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.WriteFile(filepath.Join(fakeCgroupDir, "memory.peak"), []byte("30"), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ gotStats = cgroups.NewStats()
+ if err := statMemory(fakeCgroupDir, gotStats); err != nil {
+ t.Fatalf("unexpected error when memory.events missing: %v", err)
+ }
+ if got := gotStats.MemoryStats.Usage.Failcnt; got != 0 {
+ t.Errorf("expected Failcnt 0 when memory.events missing, got %d", got)
+ }
+}
+
func TestRootStatsFromMeminfo(t *testing.T) {
stats := &cgroups.Stats{
MemoryStats: cgroups.MemoryStats{
Metadata
Metadata
Assignees
Labels
No labels