Skip to content

Commit e00be14

Browse files
committed
cgroupv2: add integration test
1 parent efd562a commit e00be14

File tree

18 files changed

+637
-31
lines changed

18 files changed

+637
-31
lines changed

cmd/metrics-node-sampler/integration/integration_test.go

+160-31
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,13 @@ func setupTests(t *testing.T, f func([]int) string) {
9999
func(tc *testutil.TestCase) error {
100100
t := tc.T
101101
// create a new container client
102-
var samples samples
102+
var v1samples samplesV1
103+
var v2samples samplesV2
103104
var cfg testConfig
104105
tc.UnmarshalInputsStrict(map[string]interface{}{
105-
"input_samples.yaml": &samples,
106-
"input_test.yaml": &cfg,
106+
"input_samples.yaml": &v1samples,
107+
"input_samples_v2.yaml": &v2samples,
108+
"input_test.yaml": &cfg,
107109
})
108110

109111
// setup the testdata by copying it to a tmp directory
@@ -129,18 +131,36 @@ func setupTests(t *testing.T, f func([]int) string) {
129131
require.NoError(t, os.WriteFile(filepath.Join(testdataCopy, rel), b, 0600))
130132
return nil
131133
})
134+
132135
fs := &fakeFS{
133-
FS: os.DirFS(testdataCopy),
134-
root: testdataCopy,
135-
samples: samples,
136-
index: make(map[string]int),
137-
time: make(map[string]time.Time),
136+
FS: os.DirFS(testdataCopy),
137+
root: testdataCopy,
138+
samplesV1: v1samples,
139+
samplesV2: v2samples,
140+
index: make(map[string]int),
141+
time: make(map[string]time.Time),
138142
}
139143

140144
// get 2 free ports
141145
ports, err := testutil.GetFreePorts(2)
142146
require.NoError(t, err)
143147

148+
var cpuPaths []samplerserverv1alpha1.MetricsFilepath
149+
var memoryPaths []samplerserverv1alpha1.MetricsFilepath
150+
if cfg.Config.Reader.CGroupVersion == samplerserverv1alpha1.CGroupV2 {
151+
cpuPaths = []samplerserverv1alpha1.MetricsFilepath{
152+
samplerserverv1alpha1.MetricsFilepath(filepath.Join("sys", "fs", "cgroup"))}
153+
memoryPaths = []samplerserverv1alpha1.MetricsFilepath{
154+
samplerserverv1alpha1.MetricsFilepath(filepath.Join("sys", "fs", "cgroup"))}
155+
} else {
156+
cpuPaths = []samplerserverv1alpha1.MetricsFilepath{
157+
samplerserverv1alpha1.MetricsFilepath(filepath.Join("sys", "fs", "cgroup", "cpu")),
158+
samplerserverv1alpha1.MetricsFilepath(filepath.Join("sys", "fs", "cgroup", "cpuacct")),
159+
}
160+
memoryPaths = []samplerserverv1alpha1.MetricsFilepath{
161+
samplerserverv1alpha1.MetricsFilepath(filepath.Join("sys", "fs", "cgroup", "memory"))}
162+
}
163+
144164
server := sampler.Server{
145165
SortResults: true, // so the test results are consistent
146166
MetricsNodeSampler: samplerserverv1alpha1.MetricsNodeSampler{
@@ -149,12 +169,9 @@ func setupTests(t *testing.T, f func([]int) string) {
149169
Size: cfg.SampleSize,
150170
},
151171
Reader: samplerserverv1alpha1.Reader{
152-
CPUPaths: []samplerserverv1alpha1.MetricsFilepath{
153-
samplerserverv1alpha1.MetricsFilepath(filepath.Join("sys", "fs", "cgroup", "cpu")),
154-
samplerserverv1alpha1.MetricsFilepath(filepath.Join("sys", "fs", "cgroup", "cpuacct")),
155-
},
156-
MemoryPaths: []samplerserverv1alpha1.MetricsFilepath{
157-
samplerserverv1alpha1.MetricsFilepath(filepath.Join("sys", "fs", "cgroup", "memory"))},
172+
CGroupVersion: cfg.Config.Reader.CGroupVersion,
173+
CPUPaths: cpuPaths,
174+
MemoryPaths: memoryPaths,
158175
NodeAggregationLevelGlobs: append(samplerserverv1alpha1.DefaultNodeAggregationLevels,
159176
samplerserverv1alpha1.NodeAggregationLevel("system.slice/*"),
160177
samplerserverv1alpha1.NodeAggregationLevel("*"),
@@ -184,6 +201,9 @@ func setupTests(t *testing.T, f func([]int) string) {
184201
var missMatchCount int
185202
require.Eventually(t, func() bool {
186203
tc.Actual = f(ports)
204+
println("Actual: ", tc.Actual)
205+
println("Expected: ", tc.Expected)
206+
println("Actual == Expected ? ", tc.Expected == tc.Actual)
187207
// use protojson because regular json library isn't compatible with proto serialization of int64
188208
require.NoError(t, protojson.Unmarshal([]byte(tc.Actual), &result))
189209
if len(result.Containers) == 0 {
@@ -221,43 +241,66 @@ func setupTests(t *testing.T, f func([]int) string) {
221241
})
222242
}
223243

224-
type samples struct {
225-
MemorySamples map[string][]MemorySample `yaml:"memorySamples" json:"memorySamples"`
226-
MemoryOOMKillSamples map[string][]MemoryOOMKillSample `yaml:"oomSamples" json:"oomSamples"`
227-
MemoryOOMSamples map[string][]MemoryOOMSample `yaml:"oomKillSamples" json:"oomKillSamples"`
228-
CPUUsageSamples map[string][]CPUUsageSample `yaml:"cpuUsageSamples" json:"cpuUsageSamples"`
229-
CPUThrottlingSamples map[string][]CPUThrottlingSample `yaml:"cpuThrottlingSamples" json:"cpuThrottlingSamples"`
244+
type samplesV1 struct {
245+
MemorySamplesV1 map[string][]MemorySampleV1 `yaml:"memorySamples" json:"memorySamples"`
246+
MemoryOOMKillSamplesV1 map[string][]MemoryOOMKillSampleV1 `yaml:"oomSamples" json:"oomSamples"`
247+
MemoryOOMSamplesV1 map[string][]MemoryOOMSampleV1 `yaml:"oomKillSamples" json:"oomKillSamples"`
248+
CPUUsageSamplesV1 map[string][]CPUUsageSampleV1 `yaml:"cpuUsageSamples" json:"cpuUsageSamples"`
249+
CPUThrottlingSamplesV1 map[string][]CPUThrottlingSampleV1 `yaml:"cpuThrottlingSamples" json:"cpuThrottlingSamples"`
250+
}
251+
252+
type samplesV2 struct {
253+
MemorySamplesV2 map[string][]MemorySampleV2 `yaml:"memorySamples" json:"memorySamples"`
254+
MemoryOOMSamplesV2 map[string][]MemoryOOMSampleV2 `yaml:"memorySamples" json:"oomSamples"`
255+
CPUSamplesV2 map[string][]CPUSampleV2 `yaml:"memorySamples" json:"cpuSamples"`
230256
}
231257

232258
type fakeFS struct {
233-
samples
259+
samplesV1
260+
samplesV2
234261
index map[string]int
235262
time map[string]time.Time
236263
root string
237264
fs.FS
238265
}
239266

240-
type MemorySample struct {
267+
type MemorySampleV1 struct {
241268
RSS int `yaml:"total_rss" json:"total_rss"`
242269
Cache int `yaml:"total_cache" json:"total_cache"`
243270
}
244271

245-
type MemoryOOMKillSample struct {
272+
type MemoryOOMKillSampleV1 struct {
246273
OOMKill int `yaml:"oom_kill" json:"oom_kill"`
247274
}
248275

249-
type MemoryOOMSample int
276+
type MemoryOOMSampleV1 int
250277

251-
type CPUUsageSample struct {
278+
type CPUUsageSampleV1 struct {
252279
Usage int `yaml:"usage" json:"usage"`
253280
}
254281

255-
type CPUThrottlingSample struct {
282+
type CPUThrottlingSampleV1 struct {
256283
ThrottledTime int `yaml:"throttled_time" json:"throttled_time"`
257284
Periods int `yaml:"nr_periods" json:"nr_periods"`
258285
ThrottledPeriods int `yaml:"nr_throttled" json:"nr_throttled"`
259286
}
260287

288+
type MemorySampleV2 struct {
289+
Current int `yaml:"total_rss" json:"usage"`
290+
}
291+
292+
type MemoryOOMSampleV2 struct {
293+
OOMKill int `yaml:"oom_kill" json:"oom_kill"`
294+
OOM int `yaml:"oom_kill" json:"oom"`
295+
}
296+
297+
type CPUSampleV2 struct {
298+
Usage int `yaml:"usage" json:"usage_usec"`
299+
ThrottledTime int `yaml:"throttled_time" json:"throttled_usec"`
300+
Periods int `yaml:"nr_periods" json:"nr_periods"`
301+
ThrottledPeriods int `yaml:"nr_throttled" json:"nr_throttled"`
302+
}
303+
261304
func (fakeFS *fakeFS) Time(name string) time.Time {
262305
t, ok := fakeFS.time[name]
263306
if !ok {
@@ -270,7 +313,7 @@ func (fakeFS *fakeFS) Time(name string) time.Time {
270313
}
271314

272315
func (fakeFS *fakeFS) Open(name string) (fs.File, error) {
273-
if val, ok := fakeFS.MemorySamples[name]; ok {
316+
if val, ok := fakeFS.MemorySamplesV1[name]; ok {
274317
// update the file value by setting its value
275318
index := fakeFS.index[name] % len(val)
276319
fakeFS.index[name] = (index + 1)
@@ -280,7 +323,7 @@ func (fakeFS *fakeFS) Open(name string) (fs.File, error) {
280323
if err != nil {
281324
return nil, err
282325
}
283-
} else if val, ok := fakeFS.CPUUsageSamples[name]; ok {
326+
} else if val, ok := fakeFS.CPUUsageSamplesV1[name]; ok {
284327
var i int
285328
// update the file value by incrementing it
286329
index := fakeFS.index[name] % len(val)
@@ -300,7 +343,7 @@ func (fakeFS *fakeFS) Open(name string) (fs.File, error) {
300343
if err != nil {
301344
return nil, err
302345
}
303-
} else if val, ok := fakeFS.CPUThrottlingSamples[name]; ok {
346+
} else if val, ok := fakeFS.CPUThrottlingSamplesV1[name]; ok {
304347
var throttledTime, periods, periodsThrottled int
305348
// update the file value by incrementing it
306349
index := fakeFS.index[name] % len(val)
@@ -339,7 +382,7 @@ func (fakeFS *fakeFS) Open(name string) (fs.File, error) {
339382
if err != nil {
340383
return nil, err
341384
}
342-
} else if val, ok := fakeFS.MemoryOOMKillSamples[name]; ok {
385+
} else if val, ok := fakeFS.MemoryOOMKillSamplesV1[name]; ok {
343386
// update the file value by setting its value
344387
index := fakeFS.index[name] % len(val)
345388
fakeFS.index[name] = (index + 1)
@@ -359,7 +402,7 @@ func (fakeFS *fakeFS) Open(name string) (fs.File, error) {
359402
if err != nil {
360403
return nil, err
361404
}
362-
} else if val, ok := fakeFS.MemoryOOMSamples[name]; ok {
405+
} else if val, ok := fakeFS.MemoryOOMSamplesV1[name]; ok {
363406
// update the file value by setting its value
364407
index := fakeFS.index[name] % len(val)
365408
fakeFS.index[name] = (index + 1)
@@ -377,6 +420,92 @@ func (fakeFS *fakeFS) Open(name string) (fs.File, error) {
377420
if err != nil {
378421
return nil, err
379422
}
423+
} else if val, ok := fakeFS.MemorySamplesV2[name]; ok {
424+
// update the file value by setting its value
425+
index := fakeFS.index[name] % len(val)
426+
fakeFS.index[name] = (index + 1)
427+
newVal := val[index]
428+
b := fmt.Sprintf("%d\n", newVal.Current)
429+
err := os.WriteFile(filepath.Join(fakeFS.root, name), []byte(b), 0600)
430+
if err != nil {
431+
return nil, err
432+
}
433+
} else if val, ok := fakeFS.CPUSamplesV2[name]; ok {
434+
var usage, throttledTime, periods, periodsThrottled int
435+
// update the file value by incrementing it
436+
index := fakeFS.index[name] % len(val)
437+
fakeFS.index[name] = (index + 1)
438+
inc := val[index]
439+
440+
b, err := os.ReadFile(filepath.Join(fakeFS.root, name))
441+
if err != nil {
442+
return nil, err
443+
}
444+
// parse the value out
445+
for _, line := range strings.Split(string(b), "\n") {
446+
fields := strings.Fields(line)
447+
value, err := strconv.ParseUint(fields[1], 10, 64)
448+
if err != nil {
449+
return nil, err
450+
}
451+
452+
switch fields[0] {
453+
case "usage_usec":
454+
usage = int(value)
455+
case "throttled_usec":
456+
throttledTime = int(value)
457+
case "nr_periods":
458+
periods = int(value)
459+
case "nr_throttled":
460+
periodsThrottled = int(value)
461+
}
462+
}
463+
464+
usage += inc.Usage
465+
throttledTime += inc.ThrottledTime
466+
periods += inc.Periods
467+
periodsThrottled += inc.ThrottledPeriods
468+
469+
err = os.WriteFile(filepath.Join(fakeFS.root, name), []byte(fmt.Sprintf(
470+
"usage_usec %d\nthrottled_usec %d\nnr_periods %d\nnr_throttled %d", usage, throttledTime, periods, periodsThrottled)), 0600)
471+
if err != nil {
472+
return nil, err
473+
}
474+
} else if val, ok := fakeFS.MemoryOOMSamplesV2[name]; ok {
475+
var oom, oomKill int
476+
// update the file value by setting its value
477+
index := fakeFS.index[name] % len(val)
478+
fakeFS.index[name] = (index + 1)
479+
newVal := val[index]
480+
481+
b, err := os.ReadFile(filepath.Join(fakeFS.root, name))
482+
if err != nil {
483+
return nil, err
484+
}
485+
// parse the value out
486+
for _, line := range strings.Split(string(b), "\n") {
487+
fields := strings.Fields(line)
488+
value, err := strconv.ParseUint(fields[1], 10, 64)
489+
if err != nil {
490+
return nil, err
491+
}
492+
493+
switch fields[0] {
494+
case "oom":
495+
oom = int(value)
496+
case "oom_kill":
497+
oomKill = int(value)
498+
}
499+
}
500+
501+
oom += newVal.OOM
502+
oomKill += newVal.OOMKill
503+
504+
err = os.WriteFile(filepath.Join(fakeFS.root, name), []byte(fmt.Sprintf("oom %d\noom_kill %d", oom, oomKill)), 0600)
505+
if err != nil {
506+
return nil, err
507+
}
380508
}
509+
381510
return fakeFS.FS.Open(name)
382511
}

0 commit comments

Comments
 (0)