@@ -28,7 +28,11 @@ import (
28
28
"github.com/onsi/gomega"
29
29
30
30
v1 "k8s.io/api/core/v1"
31
+ "k8s.io/apimachinery/pkg/api/resource"
31
32
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
33
+ "k8s.io/apimachinery/pkg/conversion"
34
+ "k8s.io/apimachinery/pkg/fields"
35
+ "k8s.io/apimachinery/pkg/labels"
32
36
"k8s.io/apimachinery/pkg/types"
33
37
"k8s.io/apimachinery/pkg/util/rand"
34
38
"k8s.io/apimachinery/pkg/util/sets"
@@ -39,7 +43,6 @@ import (
39
43
e2elog "k8s.io/kubernetes/test/e2e/framework/log"
40
44
41
45
// TODO remove the direct dependency for internal k8s.io/kubernetes
42
- "k8s.io/kubernetes/pkg/controller"
43
46
"k8s.io/kubernetes/test/e2e/system"
44
47
)
45
48
@@ -575,10 +578,107 @@ func RemoveTaintOffNode(c clientset.Interface, nodeName string, taint v1.Taint)
575
578
func AddOrUpdateTaintOnNode (c clientset.Interface , nodeName string , taint v1.Taint ) {
576
579
// TODO use wrapper methods in expect.go after removing the dependency on this
577
580
// package from the core e2e framework.
578
- err := controller . AddOrUpdateTaintOnNode (c , nodeName , & taint )
581
+ err := addOrUpdateTaintOnNode (c , nodeName , & taint )
579
582
gomega .ExpectWithOffset (2 , err ).NotTo (gomega .HaveOccurred ())
580
583
}
581
584
585
+ // addOrUpdateTaintOnNode add taints to the node. If taint was added into node, it'll issue API calls
586
+ // to update nodes; otherwise, no API calls. Return error if any.
587
+ // copied from pkg/controller/controller_utils.go AddOrUpdateTaintOnNode()
588
+ func addOrUpdateTaintOnNode (c clientset.Interface , nodeName string , taints ... * v1.Taint ) error {
589
+ if len (taints ) == 0 {
590
+ return nil
591
+ }
592
+ firstTry := true
593
+ return clientretry .RetryOnConflict (updateTaintBackOff , func () error {
594
+ var err error
595
+ var oldNode * v1.Node
596
+ // First we try getting node from the API server cache, as it's cheaper. If it fails
597
+ // we get it from etcd to be sure to have fresh data.
598
+ if firstTry {
599
+ oldNode , err = c .CoreV1 ().Nodes ().Get (context .TODO (), nodeName , metav1.GetOptions {ResourceVersion : "0" })
600
+ firstTry = false
601
+ } else {
602
+ oldNode , err = c .CoreV1 ().Nodes ().Get (context .TODO (), nodeName , metav1.GetOptions {})
603
+ }
604
+ if err != nil {
605
+ return err
606
+ }
607
+
608
+ var newNode * v1.Node
609
+ oldNodeCopy := oldNode
610
+ updated := false
611
+ for _ , taint := range taints {
612
+ curNewNode , ok , err := addOrUpdateTaint (oldNodeCopy , taint )
613
+ if err != nil {
614
+ return fmt .Errorf ("failed to update taint of node" )
615
+ }
616
+ updated = updated || ok
617
+ newNode = curNewNode
618
+ oldNodeCopy = curNewNode
619
+ }
620
+ if ! updated {
621
+ return nil
622
+ }
623
+ return patchNodeTaints (c , nodeName , oldNode , newNode )
624
+ })
625
+ }
626
+
627
+ // addOrUpdateTaint tries to add a taint to annotations list. Returns a new copy of updated Node and true if something was updated
628
+ // false otherwise.
629
+ // copied from pkg/util/taints/taints.go AddOrUpdateTaint()
630
+ func addOrUpdateTaint (node * v1.Node , taint * v1.Taint ) (* v1.Node , bool , error ) {
631
+ newNode := node .DeepCopy ()
632
+ nodeTaints := newNode .Spec .Taints
633
+
634
+ var newTaints []v1.Taint
635
+ updated := false
636
+ for i := range nodeTaints {
637
+ if taint .MatchTaint (& nodeTaints [i ]) {
638
+ if semantic .DeepEqual (* taint , nodeTaints [i ]) {
639
+ return newNode , false , nil
640
+ }
641
+ newTaints = append (newTaints , * taint )
642
+ updated = true
643
+ continue
644
+ }
645
+
646
+ newTaints = append (newTaints , nodeTaints [i ])
647
+ }
648
+
649
+ if ! updated {
650
+ newTaints = append (newTaints , * taint )
651
+ }
652
+
653
+ newNode .Spec .Taints = newTaints
654
+ return newNode , true , nil
655
+ }
656
+
657
+ // semantic can do semantic deep equality checks for core objects.
658
+ // Example: apiequality.Semantic.DeepEqual(aPod, aPodWithNonNilButEmptyMaps) == true
659
+ // copied from pkg/apis/core/helper/helpers.go Semantic
660
+ var semantic = conversion .EqualitiesOrDie (
661
+ func (a , b resource.Quantity ) bool {
662
+ // Ignore formatting, only care that numeric value stayed the same.
663
+ // TODO: if we decide it's important, it should be safe to start comparing the format.
664
+ //
665
+ // Uninitialized quantities are equivalent to 0 quantities.
666
+ return a .Cmp (b ) == 0
667
+ },
668
+ func (a , b metav1.MicroTime ) bool {
669
+ return a .UTC () == b .UTC ()
670
+ },
671
+ func (a , b metav1.Time ) bool {
672
+ return a .UTC () == b .UTC ()
673
+ },
674
+ func (a , b labels.Selector ) bool {
675
+ return a .String () == b .String ()
676
+ },
677
+ func (a , b fields.Selector ) bool {
678
+ return a .String () == b .String ()
679
+ },
680
+ )
681
+
582
682
// removeNodeTaint is for cleaning up taints temporarily added to node,
583
683
// won't fail if target taint doesn't exist or has been removed.
584
684
// If passed a node it'll check if there's anything to be done, if taint is not present it won't issue
0 commit comments