1
2
3
4
19
20 package cm
21
22 import (
23 "testing"
24
25 "github.com/stretchr/testify/assert"
26 "k8s.io/api/core/v1"
27 "k8s.io/apimachinery/pkg/api/resource"
28 evictionapi "k8s.io/kubernetes/pkg/kubelet/eviction/api"
29 )
30
31 func TestNodeAllocatableReservationForScheduling(t *testing.T) {
32 memoryEvictionThreshold := resource.MustParse("100Mi")
33 cpuMemCases := []struct {
34 kubeReserved v1.ResourceList
35 systemReserved v1.ResourceList
36 expected v1.ResourceList
37 capacity v1.ResourceList
38 hardThreshold evictionapi.ThresholdValue
39 }{
40 {
41 kubeReserved: getResourceList("100m", "100Mi"),
42 systemReserved: getResourceList("50m", "50Mi"),
43 capacity: getResourceList("10", "10Gi"),
44 expected: getResourceList("150m", "150Mi"),
45 },
46 {
47 kubeReserved: getResourceList("100m", "100Mi"),
48 systemReserved: getResourceList("50m", "50Mi"),
49 hardThreshold: evictionapi.ThresholdValue{
50 Quantity: &memoryEvictionThreshold,
51 },
52 capacity: getResourceList("10", "10Gi"),
53 expected: getResourceList("150m", "250Mi"),
54 },
55 {
56 kubeReserved: getResourceList("100m", "100Mi"),
57 systemReserved: getResourceList("50m", "50Mi"),
58 capacity: getResourceList("10", "10Gi"),
59 hardThreshold: evictionapi.ThresholdValue{
60 Percentage: 0.05,
61 },
62 expected: getResourceList("150m", "694157320"),
63 },
64
65 {
66 kubeReserved: v1.ResourceList{},
67 systemReserved: v1.ResourceList{},
68 capacity: getResourceList("10", "10Gi"),
69 expected: getResourceList("", ""),
70 },
71 {
72 kubeReserved: getResourceList("", "100Mi"),
73 systemReserved: getResourceList("50m", "50Mi"),
74 capacity: getResourceList("10", "10Gi"),
75 expected: getResourceList("50m", "150Mi"),
76 },
77
78 {
79 kubeReserved: getResourceList("50m", "100Mi"),
80 systemReserved: getResourceList("", "50Mi"),
81 capacity: getResourceList("10", "10Gi"),
82 expected: getResourceList("50m", "150Mi"),
83 },
84 {
85 kubeReserved: getResourceList("", "100Mi"),
86 systemReserved: getResourceList("", "50Mi"),
87 capacity: getResourceList("10", ""),
88 expected: getResourceList("", "150Mi"),
89 },
90 }
91 for idx, tc := range cpuMemCases {
92 nc := NodeConfig{
93 NodeAllocatableConfig: NodeAllocatableConfig{
94 KubeReserved: tc.kubeReserved,
95 SystemReserved: tc.systemReserved,
96 HardEvictionThresholds: []evictionapi.Threshold{
97 {
98 Signal: evictionapi.SignalMemoryAvailable,
99 Operator: evictionapi.OpLessThan,
100 Value: tc.hardThreshold,
101 },
102 },
103 },
104 }
105 cm := &containerManagerImpl{
106 NodeConfig: nc,
107 capacity: tc.capacity,
108 }
109 for k, v := range cm.GetNodeAllocatableReservation() {
110 expected, exists := tc.expected[k]
111 assert.True(t, exists, "test case %d expected resource %q", idx+1, k)
112 assert.Equal(t, expected.MilliValue(), v.MilliValue(), "test case %d failed for resource %q", idx+1, k)
113 }
114 }
115
116 ephemeralStorageEvictionThreshold := resource.MustParse("100Mi")
117 ephemeralStorageTestCases := []struct {
118 kubeReserved v1.ResourceList
119 expected v1.ResourceList
120 capacity v1.ResourceList
121 hardThreshold evictionapi.ThresholdValue
122 }{
123 {
124 kubeReserved: getEphemeralStorageResourceList("100Mi"),
125 capacity: getEphemeralStorageResourceList("10Gi"),
126 expected: getEphemeralStorageResourceList("100Mi"),
127 },
128 {
129 kubeReserved: getEphemeralStorageResourceList("100Mi"),
130 hardThreshold: evictionapi.ThresholdValue{
131 Quantity: &ephemeralStorageEvictionThreshold,
132 },
133 capacity: getEphemeralStorageResourceList("10Gi"),
134 expected: getEphemeralStorageResourceList("200Mi"),
135 },
136 {
137 kubeReserved: getEphemeralStorageResourceList("150Mi"),
138 capacity: getEphemeralStorageResourceList("10Gi"),
139 hardThreshold: evictionapi.ThresholdValue{
140 Percentage: 0.05,
141 },
142 expected: getEphemeralStorageResourceList("694157320"),
143 },
144
145 {
146 kubeReserved: v1.ResourceList{},
147 capacity: getEphemeralStorageResourceList("10Gi"),
148 expected: getEphemeralStorageResourceList(""),
149 },
150 }
151 for idx, tc := range ephemeralStorageTestCases {
152 nc := NodeConfig{
153 NodeAllocatableConfig: NodeAllocatableConfig{
154 KubeReserved: tc.kubeReserved,
155 HardEvictionThresholds: []evictionapi.Threshold{
156 {
157 Signal: evictionapi.SignalNodeFsAvailable,
158 Operator: evictionapi.OpLessThan,
159 Value: tc.hardThreshold,
160 },
161 },
162 },
163 }
164 cm := &containerManagerImpl{
165 NodeConfig: nc,
166 capacity: tc.capacity,
167 }
168 for k, v := range cm.GetNodeAllocatableReservation() {
169 expected, exists := tc.expected[k]
170 assert.True(t, exists, "test case %d expected resource %q", idx+1, k)
171 assert.Equal(t, expected.MilliValue(), v.MilliValue(), "test case %d failed for resource %q", idx+1, k)
172 }
173 }
174 }
175
176 func TestNodeAllocatableForEnforcement(t *testing.T) {
177 memoryEvictionThreshold := resource.MustParse("100Mi")
178 testCases := []struct {
179 kubeReserved v1.ResourceList
180 systemReserved v1.ResourceList
181 capacity v1.ResourceList
182 expected v1.ResourceList
183 hardThreshold evictionapi.ThresholdValue
184 }{
185 {
186 kubeReserved: getResourceList("100m", "100Mi"),
187 systemReserved: getResourceList("50m", "50Mi"),
188 capacity: getResourceList("10", "10Gi"),
189 expected: getResourceList("9850m", "10090Mi"),
190 },
191 {
192 kubeReserved: getResourceList("100m", "100Mi"),
193 systemReserved: getResourceList("50m", "50Mi"),
194 hardThreshold: evictionapi.ThresholdValue{
195 Quantity: &memoryEvictionThreshold,
196 },
197 capacity: getResourceList("10", "10Gi"),
198 expected: getResourceList("9850m", "10090Mi"),
199 },
200 {
201 kubeReserved: getResourceList("100m", "100Mi"),
202 systemReserved: getResourceList("50m", "50Mi"),
203 hardThreshold: evictionapi.ThresholdValue{
204 Percentage: 0.05,
205 },
206 capacity: getResourceList("10", "10Gi"),
207 expected: getResourceList("9850m", "10090Mi"),
208 },
209
210 {
211 kubeReserved: v1.ResourceList{},
212 systemReserved: v1.ResourceList{},
213 capacity: getResourceList("10", "10Gi"),
214 expected: getResourceList("10", "10Gi"),
215 },
216 {
217 kubeReserved: getResourceList("", "100Mi"),
218 systemReserved: getResourceList("50m", "50Mi"),
219 capacity: getResourceList("10", "10Gi"),
220 expected: getResourceList("9950m", "10090Mi"),
221 },
222
223 {
224 kubeReserved: getResourceList("50m", "100Mi"),
225 systemReserved: getResourceList("", "50Mi"),
226 capacity: getResourceList("10", "10Gi"),
227 expected: getResourceList("9950m", "10090Mi"),
228 },
229 {
230 kubeReserved: getResourceList("", "100Mi"),
231 systemReserved: getResourceList("", "50Mi"),
232 capacity: getResourceList("10", ""),
233 expected: getResourceList("10", ""),
234 },
235 }
236 for idx, tc := range testCases {
237 nc := NodeConfig{
238 NodeAllocatableConfig: NodeAllocatableConfig{
239 KubeReserved: tc.kubeReserved,
240 SystemReserved: tc.systemReserved,
241 HardEvictionThresholds: []evictionapi.Threshold{
242 {
243 Signal: evictionapi.SignalMemoryAvailable,
244 Operator: evictionapi.OpLessThan,
245 Value: tc.hardThreshold,
246 },
247 },
248 },
249 }
250 cm := &containerManagerImpl{
251 NodeConfig: nc,
252 capacity: tc.capacity,
253 }
254 for k, v := range cm.GetNodeAllocatableAbsolute() {
255 expected, exists := tc.expected[k]
256 assert.True(t, exists)
257 assert.Equal(t, expected.MilliValue(), v.MilliValue(), "test case %d failed for resource %q", idx+1, k)
258 }
259 }
260 }
261
262 func TestNodeAllocatableInputValidation(t *testing.T) {
263 memoryEvictionThreshold := resource.MustParse("100Mi")
264 highMemoryEvictionThreshold := resource.MustParse("2Gi")
265 cpuMemTestCases := []struct {
266 kubeReserved v1.ResourceList
267 systemReserved v1.ResourceList
268 capacity v1.ResourceList
269 hardThreshold evictionapi.ThresholdValue
270 invalidConfiguration bool
271 }{
272 {
273 kubeReserved: getResourceList("100m", "100Mi"),
274 systemReserved: getResourceList("50m", "50Mi"),
275 capacity: getResourceList("10", "10Gi"),
276 },
277 {
278 kubeReserved: getResourceList("100m", "100Mi"),
279 systemReserved: getResourceList("50m", "50Mi"),
280 hardThreshold: evictionapi.ThresholdValue{
281 Quantity: &memoryEvictionThreshold,
282 },
283 capacity: getResourceList("10", "10Gi"),
284 },
285 {
286 kubeReserved: getResourceList("100m", "100Mi"),
287 systemReserved: getResourceList("50m", "50Mi"),
288 hardThreshold: evictionapi.ThresholdValue{
289 Percentage: 0.05,
290 },
291 capacity: getResourceList("10", "10Gi"),
292 },
293 {
294 kubeReserved: v1.ResourceList{},
295 systemReserved: v1.ResourceList{},
296 capacity: getResourceList("10", "10Gi"),
297 },
298 {
299 kubeReserved: getResourceList("", "100Mi"),
300 systemReserved: getResourceList("50m", "50Mi"),
301 capacity: getResourceList("10", "10Gi"),
302 },
303 {
304 kubeReserved: getResourceList("50m", "100Mi"),
305 systemReserved: getResourceList("", "50Mi"),
306 capacity: getResourceList("10", "10Gi"),
307 },
308 {
309 kubeReserved: getResourceList("", "100Mi"),
310 systemReserved: getResourceList("", "50Mi"),
311 capacity: getResourceList("10", ""),
312 },
313 {
314 kubeReserved: getResourceList("5", "10Gi"),
315 systemReserved: getResourceList("5", "10Gi"),
316 hardThreshold: evictionapi.ThresholdValue{
317 Quantity: &highMemoryEvictionThreshold,
318 },
319 capacity: getResourceList("10", "11Gi"),
320 invalidConfiguration: true,
321 },
322 }
323 for _, tc := range cpuMemTestCases {
324 nc := NodeConfig{
325 NodeAllocatableConfig: NodeAllocatableConfig{
326 KubeReserved: tc.kubeReserved,
327 SystemReserved: tc.systemReserved,
328 HardEvictionThresholds: []evictionapi.Threshold{
329 {
330 Signal: evictionapi.SignalMemoryAvailable,
331 Operator: evictionapi.OpLessThan,
332 Value: tc.hardThreshold,
333 },
334 },
335 },
336 }
337 cm := &containerManagerImpl{
338 NodeConfig: nc,
339 capacity: tc.capacity,
340 }
341 err := cm.validateNodeAllocatable()
342 if err == nil && tc.invalidConfiguration {
343 t.Fatalf("Expected invalid node allocatable configuration")
344 } else if err != nil && !tc.invalidConfiguration {
345 t.Fatalf("Expected valid node allocatable configuration: %v", err)
346 }
347 }
348
349 ephemeralStorageEvictionThreshold := resource.MustParse("100Mi")
350 ephemeralStorageTestCases := []struct {
351 kubeReserved v1.ResourceList
352 capacity v1.ResourceList
353 hardThreshold evictionapi.ThresholdValue
354 invalidConfiguration bool
355 }{
356 {
357 kubeReserved: getEphemeralStorageResourceList("100Mi"),
358 capacity: getEphemeralStorageResourceList("500Mi"),
359 },
360 {
361 kubeReserved: getEphemeralStorageResourceList("20Gi"),
362 hardThreshold: evictionapi.ThresholdValue{
363 Quantity: &ephemeralStorageEvictionThreshold,
364 },
365 capacity: getEphemeralStorageResourceList("20Gi"),
366 invalidConfiguration: true,
367 },
368 }
369 for _, tc := range ephemeralStorageTestCases {
370 nc := NodeConfig{
371 NodeAllocatableConfig: NodeAllocatableConfig{
372 KubeReserved: tc.kubeReserved,
373 HardEvictionThresholds: []evictionapi.Threshold{
374 {
375 Signal: evictionapi.SignalNodeFsAvailable,
376 Operator: evictionapi.OpLessThan,
377 Value: tc.hardThreshold,
378 },
379 },
380 },
381 }
382 cm := &containerManagerImpl{
383 NodeConfig: nc,
384 capacity: tc.capacity,
385 }
386 err := cm.validateNodeAllocatable()
387 if err == nil && tc.invalidConfiguration {
388 t.Fatalf("Expected invalid node allocatable configuration")
389 } else if err != nil && !tc.invalidConfiguration {
390 t.Fatalf("Expected valid node allocatable configuration: %v", err)
391 }
392 }
393 }
394
395
396
397 func getEphemeralStorageResourceList(storage string) v1.ResourceList {
398 res := v1.ResourceList{}
399 if storage != "" {
400 res[v1.ResourceEphemeralStorage] = resource.MustParse(storage)
401 }
402 return res
403 }
404
View as plain text