@@ -19,6 +19,7 @@ package node
19
19
import (
20
20
"fmt"
21
21
"net"
22
+ "strings"
22
23
"time"
23
24
24
25
v1 "k8s.io/api/core/v1"
@@ -342,7 +343,7 @@ func GetReadySchedulableNodesOrDie(c clientset.Interface) (nodes *v1.NodeList, e
342
343
// previous tests may have cause failures of some nodes. Let's skip
343
344
// 'Not Ready' nodes, just in case (there is no need to fail the test).
344
345
Filter (nodes , func (node v1.Node ) bool {
345
- return isNodeSchedulable (& node ) && isNodeUntainted (& node )
346
+ return IsNodeSchedulable (& node ) && IsNodeUntainted (& node )
346
347
})
347
348
return nodes , nil
348
349
}
@@ -357,7 +358,7 @@ func GetReadyNodesIncludingTainted(c clientset.Interface) (nodes *v1.NodeList, e
357
358
return nil , fmt .Errorf ("listing schedulable nodes error: %s" , err )
358
359
}
359
360
Filter (nodes , func (node v1.Node ) bool {
360
- return isNodeSchedulable (& node )
361
+ return IsNodeSchedulable (& node )
361
362
})
362
363
return nodes , nil
363
364
}
@@ -373,16 +374,22 @@ func GetMasterAndWorkerNodes(c clientset.Interface) (sets.String, *v1.NodeList,
373
374
for _ , n := range all .Items {
374
375
if system .DeprecatedMightBeMasterNode (n .Name ) {
375
376
masters .Insert (n .Name )
376
- } else if isNodeSchedulable (& n ) && isNodeUntainted (& n ) {
377
+ } else if IsNodeSchedulable (& n ) && IsNodeUntainted (& n ) {
377
378
nodes .Items = append (nodes .Items , n )
378
379
}
379
380
}
380
381
return masters , nodes , nil
381
382
}
382
383
383
- // Test whether a fake pod can be scheduled on "node", given its current taints.
384
+ // IsNodeUntainted tests whether a fake pod can be scheduled on "node", given its current taints.
384
385
// TODO: need to discuss wether to return bool and error type
385
- func isNodeUntainted (node * v1.Node ) bool {
386
+ func IsNodeUntainted (node * v1.Node ) bool {
387
+ return isNodeUntaintedWithNonblocking (node , "" )
388
+ }
389
+
390
+ // isNodeUntaintedWithNonblocking tests whether a fake pod can be scheduled on "node"
391
+ // but allows for taints in the list of non-blocking taints.
392
+ func isNodeUntaintedWithNonblocking (node * v1.Node , nonblockingTaints string ) bool {
386
393
fakePod := & v1.Pod {
387
394
TypeMeta : metav1.TypeMeta {
388
395
Kind : "Pod" ,
@@ -401,8 +408,30 @@ func isNodeUntainted(node *v1.Node) bool {
401
408
},
402
409
},
403
410
}
411
+
404
412
nodeInfo := schedulernodeinfo .NewNodeInfo ()
405
- nodeInfo .SetNode (node )
413
+
414
+ // Simple lookup for nonblocking taints based on comma-delimited list.
415
+ nonblockingTaintsMap := map [string ]struct {}{}
416
+ for _ , t := range strings .Split (nonblockingTaints , "," ) {
417
+ if strings .TrimSpace (t ) != "" {
418
+ nonblockingTaintsMap [strings .TrimSpace (t )] = struct {}{}
419
+ }
420
+ }
421
+
422
+ if len (nonblockingTaintsMap ) > 0 {
423
+ nodeCopy := node .DeepCopy ()
424
+ nodeCopy .Spec .Taints = []v1.Taint {}
425
+ for _ , v := range node .Spec .Taints {
426
+ if _ , isNonblockingTaint := nonblockingTaintsMap [v .Key ]; ! isNonblockingTaint {
427
+ nodeCopy .Spec .Taints = append (nodeCopy .Spec .Taints , v )
428
+ }
429
+ }
430
+ nodeInfo .SetNode (nodeCopy )
431
+ } else {
432
+ nodeInfo .SetNode (node )
433
+ }
434
+
406
435
fit , _ , err := predicates .PodToleratesNodeTaints (fakePod , nil , nodeInfo )
407
436
if err != nil {
408
437
e2elog .Failf ("Can't test predicates for node %s: %v" , node .Name , err )
@@ -411,15 +440,48 @@ func isNodeUntainted(node *v1.Node) bool {
411
440
return fit
412
441
}
413
442
414
- // Node is schedulable if:
443
+ // IsNodeSchedulable returns true if:
415
444
// 1) doesn't have "unschedulable" field set
416
- // 2) it's Ready condition is set to true
417
- // 3) doesn't have NetworkUnavailable condition set to true
418
- func isNodeSchedulable (node * v1.Node ) bool {
445
+ // 2) it also returns true from IsNodeReady
446
+ func IsNodeSchedulable (node * v1.Node ) bool {
447
+ if node == nil {
448
+ return false
449
+ }
450
+ return ! node .Spec .Unschedulable && IsNodeReady (node )
451
+ }
452
+
453
+ // IsNodeReady returns true if:
454
+ // 1) it's Ready condition is set to true
455
+ // 2) doesn't have NetworkUnavailable condition set to true
456
+ func IsNodeReady (node * v1.Node ) bool {
419
457
nodeReady := IsConditionSetAsExpected (node , v1 .NodeReady , true )
420
458
networkReady := IsConditionUnset (node , v1 .NodeNetworkUnavailable ) ||
421
459
IsConditionSetAsExpectedSilent (node , v1 .NodeNetworkUnavailable , false )
422
- return ! node .Spec .Unschedulable && nodeReady && networkReady
460
+ return nodeReady && networkReady
461
+ }
462
+
463
+ // hasNonblockingTaint returns true if the node contains at least
464
+ // one taint with a key matching the regexp.
465
+ func hasNonblockingTaint (node * v1.Node , nonblockingTaints string ) bool {
466
+ if node == nil {
467
+ return false
468
+ }
469
+
470
+ // Simple lookup for nonblocking taints based on comma-delimited list.
471
+ nonblockingTaintsMap := map [string ]struct {}{}
472
+ for _ , t := range strings .Split (nonblockingTaints , "," ) {
473
+ if strings .TrimSpace (t ) != "" {
474
+ nonblockingTaintsMap [strings .TrimSpace (t )] = struct {}{}
475
+ }
476
+ }
477
+
478
+ for _ , taint := range node .Spec .Taints {
479
+ if _ , hasNonblockingTaint := nonblockingTaintsMap [taint .Key ]; hasNonblockingTaint {
480
+ return true
481
+ }
482
+ }
483
+
484
+ return false
423
485
}
424
486
425
487
// PodNodePairs return podNode pairs for all pods in a namespace
0 commit comments