Skip to content

Commit 5f3e8cb

Browse files
Merge pull request openshift-kni#1268 from shajmakh/mem-cmp
internal: ensure total memory resources are equal on node level
2 parents 94d8d40 + 8409832 commit 5f3e8cb

File tree

2 files changed

+201
-1
lines changed

2 files changed

+201
-1
lines changed

internal/noderesourcetopology/equality.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,18 @@ func EqualZones(zonesA, zonesB nrtv1alpha2.ZoneList, isRebootTest bool) (bool, e
3838
zA := SortedZoneList(zonesA)
3939
zB := SortedZoneList(zonesB)
4040

41+
klog.Infof("ensure memory resources on node level are maintained with same amounts")
42+
/*
43+
the need for this came mainly because of tests requiring reboot. The reason is that in such tests it was observed that there is a slight difference
44+
in the memory resources set by the kernel on NUMA zones but the total memory resources on node level is kept the same. This verification ensures that
45+
is achieved on every test which is true and not only for tests that involve reboot. For now the check is for memory resources only as there were no
46+
similar observations for other types of resources.
47+
*/
48+
_, err := equalMemoryNodeLevel(zonesA, zonesB)
49+
if err != nil {
50+
return false, err
51+
}
52+
4153
for idx := range zA {
4254
zoneA := &zA[idx]
4355
zoneB := &zB[idx]
@@ -55,6 +67,38 @@ func EqualZones(zonesA, zonesB nrtv1alpha2.ZoneList, isRebootTest bool) (bool, e
5567
return true, nil
5668
}
5769

70+
func equalMemoryNodeLevel(zonesA, zonesB nrtv1alpha2.ZoneList) (bool, error) {
71+
totalCapacityA, totalAvailableA, totalAllocatableA := getTotalMemory(zonesA)
72+
totalCapacityB, totalAvailableB, totalAllocatableB := getTotalMemory(zonesB)
73+
74+
if totalCapacityA.Cmp(totalCapacityB) != 0 {
75+
return false, fmt.Errorf("mismatched total capacity memory initial=%v vs updated=%v", totalCapacityA, totalCapacityB)
76+
}
77+
if totalAvailableA.Cmp(totalAvailableB) != 0 {
78+
return false, fmt.Errorf("mismatched total available memory initial=%v vs updated=%v", totalAvailableA, totalAvailableB)
79+
}
80+
if totalAllocatableA.Cmp(totalAllocatableB) != 0 {
81+
return false, fmt.Errorf("mismatched total allocatable memory initial=%v vs updated=%v", totalAllocatableA, totalAllocatableB)
82+
}
83+
return true, nil
84+
}
85+
86+
func getTotalMemory(zoneList nrtv1alpha2.ZoneList) (resource.Quantity, resource.Quantity, resource.Quantity) {
87+
var totalCapacity, totalAvailable, totalAllocatable resource.Quantity
88+
for _, zone := range zoneList {
89+
res := zone.Resources
90+
for _, resource := range res {
91+
if resource.Name != string(corev1.ResourceMemory) {
92+
continue
93+
}
94+
totalCapacity.Add(resource.Capacity)
95+
totalAvailable.Add(resource.Available)
96+
totalAllocatable.Add(resource.Allocatable)
97+
}
98+
}
99+
return totalCapacity, totalAvailable, totalAllocatable
100+
}
101+
58102
func EqualResourceInfos(resInfosA, resInfosB nrtv1alpha2.ResourceInfoList, isRebootTest bool) (bool, error) {
59103
if len(resInfosA) != len(resInfosB) {
60104
return false, fmt.Errorf("unequal resourceinfo count")

internal/noderesourcetopology/equality_test.go

Lines changed: 157 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"fmt"
2222
"testing"
2323

24+
corev1 "k8s.io/api/core/v1"
2425
"k8s.io/apimachinery/pkg/api/resource"
2526

2627
nrtv1alpha2 "github.com/k8stopologyawareschedwg/noderesourcetopology-api/pkg/apis/topology/v1alpha2"
@@ -31,6 +32,7 @@ func TestEqualZones(t *testing.T) {
3132
name string
3233
data1 nrtv1alpha2.ZoneList
3334
data2 nrtv1alpha2.ZoneList
35+
isReboot bool
3436
expected bool
3537
}{
3638
{
@@ -185,10 +187,164 @@ func TestEqualZones(t *testing.T) {
185187
},
186188
expected: false,
187189
},
190+
{
191+
name: "with memory deviation but total is equal on node level - reboot test",
192+
isReboot: true, // because we don't want the NUMA level check to fail
193+
data1: nrtv1alpha2.ZoneList{
194+
{
195+
Name: "Zone-000",
196+
Resources: nrtv1alpha2.ResourceInfoList{
197+
{
198+
Name: "foo",
199+
Capacity: resource.MustParse("2"),
200+
Allocatable: resource.MustParse("2"),
201+
Available: resource.MustParse("2"),
202+
},
203+
{
204+
Name: string(corev1.ResourceMemory),
205+
Capacity: resource.MustParse("154525950"),
206+
Allocatable: resource.MustParse("154525950"),
207+
Available: resource.MustParse("154000000"),
208+
},
209+
},
210+
},
211+
{
212+
Name: "Zone-001",
213+
Resources: nrtv1alpha2.ResourceInfoList{
214+
{
215+
Name: string(corev1.ResourceMemory),
216+
Capacity: resource.MustParse("100000000"),
217+
Allocatable: resource.MustParse("100000000"),
218+
Available: resource.MustParse("100000000"),
219+
},
220+
{
221+
Name: "foo",
222+
Capacity: resource.MustParse("2"),
223+
Allocatable: resource.MustParse("2"),
224+
Available: resource.MustParse("2"),
225+
},
226+
},
227+
},
228+
},
229+
data2: nrtv1alpha2.ZoneList{
230+
{
231+
Name: "Zone-001",
232+
Resources: nrtv1alpha2.ResourceInfoList{
233+
{
234+
Name: "foo",
235+
Capacity: resource.MustParse("2"),
236+
Allocatable: resource.MustParse("2"),
237+
Available: resource.MustParse("2"),
238+
},
239+
{
240+
Name: string(corev1.ResourceMemory),
241+
Capacity: resource.MustParse("154525950"),
242+
Allocatable: resource.MustParse("154525950"),
243+
Available: resource.MustParse("154000000"),
244+
},
245+
},
246+
},
247+
{
248+
Name: "Zone-000",
249+
Resources: nrtv1alpha2.ResourceInfoList{
250+
{
251+
Name: "foo",
252+
Capacity: resource.MustParse("2"),
253+
Allocatable: resource.MustParse("2"),
254+
Available: resource.MustParse("2"),
255+
},
256+
{
257+
Name: string(corev1.ResourceMemory),
258+
Capacity: resource.MustParse("100000000"),
259+
Allocatable: resource.MustParse("100000000"),
260+
Available: resource.MustParse("100000000"),
261+
},
262+
},
263+
},
264+
},
265+
expected: true,
266+
},
267+
{
268+
name: "with memory deviation but total is NOT equal on node level - reboot test",
269+
isReboot: true,
270+
data1: nrtv1alpha2.ZoneList{
271+
{
272+
Name: "Zone-000",
273+
Resources: nrtv1alpha2.ResourceInfoList{
274+
{
275+
Name: "foo",
276+
Capacity: resource.MustParse("2"),
277+
Allocatable: resource.MustParse("2"),
278+
Available: resource.MustParse("2"),
279+
},
280+
{
281+
Name: string(corev1.ResourceMemory),
282+
Capacity: resource.MustParse("154525950"),
283+
Allocatable: resource.MustParse("154525950"),
284+
Available: resource.MustParse("154000000"),
285+
},
286+
},
287+
},
288+
{
289+
Name: "Zone-001",
290+
Resources: nrtv1alpha2.ResourceInfoList{
291+
{
292+
Name: string(corev1.ResourceMemory),
293+
Capacity: resource.MustParse("100000000"),
294+
Allocatable: resource.MustParse("100000000"),
295+
Available: resource.MustParse("100000000"),
296+
},
297+
{
298+
Name: "foo",
299+
Capacity: resource.MustParse("2"),
300+
Allocatable: resource.MustParse("2"),
301+
Available: resource.MustParse("2"),
302+
},
303+
},
304+
},
305+
},
306+
data2: nrtv1alpha2.ZoneList{
307+
{
308+
Name: "Zone-001",
309+
Resources: nrtv1alpha2.ResourceInfoList{
310+
{
311+
Name: "foo",
312+
Capacity: resource.MustParse("2"),
313+
Allocatable: resource.MustParse("2"),
314+
Available: resource.MustParse("2"),
315+
},
316+
{
317+
Name: string(corev1.ResourceMemory),
318+
Capacity: resource.MustParse("154525950"),
319+
Allocatable: resource.MustParse("154525950"),
320+
Available: resource.MustParse("154000000"),
321+
},
322+
},
323+
},
324+
{
325+
Name: "Zone-000",
326+
Resources: nrtv1alpha2.ResourceInfoList{
327+
{
328+
Name: "foo",
329+
Capacity: resource.MustParse("2"),
330+
Allocatable: resource.MustParse("2"),
331+
Available: resource.MustParse("2"),
332+
},
333+
{
334+
Name: string(corev1.ResourceMemory),
335+
Capacity: resource.MustParse("154525950"),
336+
Allocatable: resource.MustParse("154525950"),
337+
Available: resource.MustParse("154000000"),
338+
},
339+
},
340+
},
341+
},
342+
expected: false,
343+
},
188344
}
189345
for _, tt := range testCases {
190346
t.Run(tt.name, func(t *testing.T) {
191-
got, _ := EqualZones(tt.data1, tt.data2, false)
347+
got, _ := EqualZones(tt.data1, tt.data2, tt.isReboot)
192348
if got != tt.expected {
193349
t.Errorf("got=%v expected=%v\ndata1=%s\ndata2=%s", got, tt.expected, toJSON(tt.data1), toJSON(tt.data2))
194350
}

0 commit comments

Comments
 (0)