@@ -169,6 +169,43 @@ type nodeHealthData struct {
169
169
lease * coordv1beta1.Lease
170
170
}
171
171
172
+ func (n * nodeHealthData ) deepCopy () * nodeHealthData {
173
+ if n == nil {
174
+ return nil
175
+ }
176
+ return & nodeHealthData {
177
+ probeTimestamp : n .probeTimestamp ,
178
+ readyTransitionTimestamp : n .readyTransitionTimestamp ,
179
+ status : n .status .DeepCopy (),
180
+ lease : n .lease .DeepCopy (),
181
+ }
182
+ }
183
+
184
+ type nodeHealthMap struct {
185
+ lock sync.RWMutex
186
+ nodeHealths map [string ]* nodeHealthData
187
+ }
188
+
189
+ func newNodeHealthMap () * nodeHealthMap {
190
+ return & nodeHealthMap {
191
+ nodeHealths : make (map [string ]* nodeHealthData ),
192
+ }
193
+ }
194
+
195
+ // getDeepCopy - returns copy of node health data.
196
+ // It prevents data being changed after retrieving it from the map.
197
+ func (n * nodeHealthMap ) getDeepCopy (name string ) * nodeHealthData {
198
+ n .lock .RLock ()
199
+ defer n .lock .RUnlock ()
200
+ return n .nodeHealths [name ].deepCopy ()
201
+ }
202
+
203
+ func (n * nodeHealthMap ) set (name string , data * nodeHealthData ) {
204
+ n .lock .Lock ()
205
+ defer n .lock .Unlock ()
206
+ n .nodeHealths [name ] = data
207
+ }
208
+
172
209
// Controller is the controller that manages node's life cycle.
173
210
type Controller struct {
174
211
taintManager * scheduler.NoExecuteTaintManager
@@ -186,7 +223,7 @@ type Controller struct {
186
223
187
224
knownNodeSet map [string ]* v1.Node
188
225
// per Node map storing last observed health together with a local time when it was observed.
189
- nodeHealthMap map [ string ] * nodeHealthData
226
+ nodeHealthMap * nodeHealthMap
190
227
191
228
// Lock to access evictor workers
192
229
evictorLock sync.Mutex
@@ -305,7 +342,7 @@ func NewNodeLifecycleController(
305
342
kubeClient : kubeClient ,
306
343
now : metav1 .Now ,
307
344
knownNodeSet : make (map [string ]* v1.Node ),
308
- nodeHealthMap : make ( map [ string ] * nodeHealthData ),
345
+ nodeHealthMap : newNodeHealthMap ( ),
309
346
recorder : recorder ,
310
347
nodeMonitorPeriod : nodeMonitorPeriod ,
311
348
nodeStartupGracePeriod : nodeStartupGracePeriod ,
@@ -722,6 +759,11 @@ func (nc *Controller) monitorNodeHealth() error {
722
759
}
723
760
724
761
decisionTimestamp := nc .now ()
762
+ nodeHealthData := nc .nodeHealthMap .getDeepCopy (node .Name )
763
+ if nodeHealthData == nil {
764
+ klog .Errorf ("Skipping %v node processing: health data doesn't exist." , node .Name )
765
+ continue
766
+ }
725
767
if currentReadyCondition != nil {
726
768
// Check eviction timeout against decisionTimestamp
727
769
switch observedReadyCondition .Status {
@@ -740,12 +782,12 @@ func (nc *Controller) monitorNodeHealth() error {
740
782
)
741
783
}
742
784
} else {
743
- if decisionTimestamp .After (nc . nodeHealthMap [ node . Name ] .readyTransitionTimestamp .Add (nc .podEvictionTimeout )) {
785
+ if decisionTimestamp .After (nodeHealthData .readyTransitionTimestamp .Add (nc .podEvictionTimeout )) {
744
786
if nc .evictPods (node ) {
745
787
klog .V (2 ).Infof ("Node is NotReady. Adding Pods on Node %s to eviction queue: %v is later than %v + %v" ,
746
788
node .Name ,
747
789
decisionTimestamp ,
748
- nc . nodeHealthMap [ node . Name ] .readyTransitionTimestamp ,
790
+ nodeHealthData .readyTransitionTimestamp ,
749
791
nc .podEvictionTimeout ,
750
792
)
751
793
}
@@ -766,12 +808,12 @@ func (nc *Controller) monitorNodeHealth() error {
766
808
)
767
809
}
768
810
} else {
769
- if decisionTimestamp .After (nc . nodeHealthMap [ node . Name ] .probeTimestamp .Add (nc .podEvictionTimeout )) {
811
+ if decisionTimestamp .After (nodeHealthData .probeTimestamp .Add (nc .podEvictionTimeout )) {
770
812
if nc .evictPods (node ) {
771
813
klog .V (2 ).Infof ("Node is unresponsive. Adding Pods on Node %s to eviction queues: %v is later than %v + %v" ,
772
814
node .Name ,
773
815
decisionTimestamp ,
774
- nc . nodeHealthMap [ node . Name ] .readyTransitionTimestamp ,
816
+ nodeHealthData .readyTransitionTimestamp ,
775
817
nc .podEvictionTimeout - gracePeriod ,
776
818
)
777
819
}
@@ -849,6 +891,11 @@ func legacyIsMasterNode(nodeName string) bool {
849
891
// tryUpdateNodeHealth checks a given node's conditions and tries to update it. Returns grace period to
850
892
// which given node is entitled, state of current and last observed Ready Condition, and an error if it occurred.
851
893
func (nc * Controller ) tryUpdateNodeHealth (node * v1.Node ) (time.Duration , v1.NodeCondition , * v1.NodeCondition , error ) {
894
+ nodeHealth := nc .nodeHealthMap .getDeepCopy (node .Name )
895
+ defer func () {
896
+ nc .nodeHealthMap .set (node .Name , nodeHealth )
897
+ }()
898
+
852
899
var gracePeriod time.Duration
853
900
var observedReadyCondition v1.NodeCondition
854
901
_ , currentReadyCondition := nodeutil .GetNodeCondition (& node .Status , v1 .NodeReady )
@@ -863,10 +910,10 @@ func (nc *Controller) tryUpdateNodeHealth(node *v1.Node) (time.Duration, v1.Node
863
910
LastTransitionTime : node .CreationTimestamp ,
864
911
}
865
912
gracePeriod = nc .nodeStartupGracePeriod
866
- if _ , found := nc . nodeHealthMap [ node . Name ]; found {
867
- nc . nodeHealthMap [ node . Name ] .status = & node .Status
913
+ if nodeHealth != nil {
914
+ nodeHealth .status = & node .Status
868
915
} else {
869
- nc . nodeHealthMap [ node . Name ] = & nodeHealthData {
916
+ nodeHealth = & nodeHealthData {
870
917
status : & node .Status ,
871
918
probeTimestamp : node .CreationTimestamp ,
872
919
readyTransitionTimestamp : node .CreationTimestamp ,
@@ -877,7 +924,6 @@ func (nc *Controller) tryUpdateNodeHealth(node *v1.Node) (time.Duration, v1.Node
877
924
observedReadyCondition = * currentReadyCondition
878
925
gracePeriod = nc .nodeMonitorGracePeriod
879
926
}
880
- savedNodeHealth , found := nc .nodeHealthMap [node .Name ]
881
927
// There are following cases to check:
882
928
// - both saved and new status have no Ready Condition set - we leave everything as it is,
883
929
// - saved status have no Ready Condition, but current one does - Controller was restarted with Node data already present in etcd,
@@ -894,29 +940,29 @@ func (nc *Controller) tryUpdateNodeHealth(node *v1.Node) (time.Duration, v1.Node
894
940
// if that's the case, but it does not seem necessary.
895
941
var savedCondition * v1.NodeCondition
896
942
var savedLease * coordv1beta1.Lease
897
- if found {
898
- _ , savedCondition = nodeutil .GetNodeCondition (savedNodeHealth .status , v1 .NodeReady )
899
- savedLease = savedNodeHealth .lease
943
+ if nodeHealth != nil {
944
+ _ , savedCondition = nodeutil .GetNodeCondition (nodeHealth .status , v1 .NodeReady )
945
+ savedLease = nodeHealth .lease
900
946
}
901
947
902
- if ! found {
948
+ if nodeHealth == nil {
903
949
klog .Warningf ("Missing timestamp for Node %s. Assuming now as a timestamp." , node .Name )
904
- savedNodeHealth = & nodeHealthData {
950
+ nodeHealth = & nodeHealthData {
905
951
status : & node .Status ,
906
952
probeTimestamp : nc .now (),
907
953
readyTransitionTimestamp : nc .now (),
908
954
}
909
955
} else if savedCondition == nil && currentReadyCondition != nil {
910
956
klog .V (1 ).Infof ("Creating timestamp entry for newly observed Node %s" , node .Name )
911
- savedNodeHealth = & nodeHealthData {
957
+ nodeHealth = & nodeHealthData {
912
958
status : & node .Status ,
913
959
probeTimestamp : nc .now (),
914
960
readyTransitionTimestamp : nc .now (),
915
961
}
916
962
} else if savedCondition != nil && currentReadyCondition == nil {
917
963
klog .Errorf ("ReadyCondition was removed from Status of Node %s" , node .Name )
918
964
// TODO: figure out what to do in this case. For now we do the same thing as above.
919
- savedNodeHealth = & nodeHealthData {
965
+ nodeHealth = & nodeHealthData {
920
966
status : & node .Status ,
921
967
probeTimestamp : nc .now (),
922
968
readyTransitionTimestamp : nc .now (),
@@ -929,14 +975,14 @@ func (nc *Controller) tryUpdateNodeHealth(node *v1.Node) (time.Duration, v1.Node
929
975
klog .V (3 ).Infof ("ReadyCondition for Node %s transitioned from %v to %v" , node .Name , savedCondition , currentReadyCondition )
930
976
transitionTime = nc .now ()
931
977
} else {
932
- transitionTime = savedNodeHealth .readyTransitionTimestamp
978
+ transitionTime = nodeHealth .readyTransitionTimestamp
933
979
}
934
980
if klog .V (5 ) {
935
- klog .Infof ("Node %s ReadyCondition updated. Updating timestamp: %+v vs %+v." , node .Name , savedNodeHealth .status , node .Status )
981
+ klog .Infof ("Node %s ReadyCondition updated. Updating timestamp: %+v vs %+v." , node .Name , nodeHealth .status , node .Status )
936
982
} else {
937
983
klog .V (3 ).Infof ("Node %s ReadyCondition updated. Updating timestamp." , node .Name )
938
984
}
939
- savedNodeHealth = & nodeHealthData {
985
+ nodeHealth = & nodeHealthData {
940
986
status : & node .Status ,
941
987
probeTimestamp : nc .now (),
942
988
readyTransitionTimestamp : transitionTime ,
@@ -950,13 +996,12 @@ func (nc *Controller) tryUpdateNodeHealth(node *v1.Node) (time.Duration, v1.Node
950
996
// take no action.
951
997
observedLease , _ = nc .leaseLister .Leases (v1 .NamespaceNodeLease ).Get (node .Name )
952
998
if observedLease != nil && (savedLease == nil || savedLease .Spec .RenewTime .Before (observedLease .Spec .RenewTime )) {
953
- savedNodeHealth .lease = observedLease
954
- savedNodeHealth .probeTimestamp = nc .now ()
999
+ nodeHealth .lease = observedLease
1000
+ nodeHealth .probeTimestamp = nc .now ()
955
1001
}
956
1002
}
957
- nc .nodeHealthMap [node .Name ] = savedNodeHealth
958
1003
959
- if nc .now ().After (savedNodeHealth .probeTimestamp .Add (gracePeriod )) {
1004
+ if nc .now ().After (nodeHealth .probeTimestamp .Add (gracePeriod )) {
960
1005
// NodeReady condition or lease was last set longer ago than gracePeriod, so
961
1006
// update it to Unknown (regardless of its current value) in the master.
962
1007
@@ -984,7 +1029,7 @@ func (nc *Controller) tryUpdateNodeHealth(node *v1.Node) (time.Duration, v1.Node
984
1029
})
985
1030
} else {
986
1031
klog .V (4 ).Infof ("node %v hasn't been updated for %+v. Last %v is: %+v" ,
987
- node .Name , nc .now ().Time .Sub (savedNodeHealth .probeTimestamp .Time ), nodeConditionType , currentCondition )
1032
+ node .Name , nc .now ().Time .Sub (nodeHealth .probeTimestamp .Time ), nodeConditionType , currentCondition )
988
1033
if currentCondition .Status != v1 .ConditionUnknown {
989
1034
currentCondition .Status = v1 .ConditionUnknown
990
1035
currentCondition .Reason = "NodeStatusUnknown"
@@ -1001,9 +1046,9 @@ func (nc *Controller) tryUpdateNodeHealth(node *v1.Node) (time.Duration, v1.Node
1001
1046
klog .Errorf ("Error updating node %s: %v" , node .Name , err )
1002
1047
return gracePeriod , observedReadyCondition , currentReadyCondition , err
1003
1048
}
1004
- nc . nodeHealthMap [ node . Name ] = & nodeHealthData {
1049
+ nodeHealth = & nodeHealthData {
1005
1050
status : & node .Status ,
1006
- probeTimestamp : nc . nodeHealthMap [ node . Name ] .probeTimestamp ,
1051
+ probeTimestamp : nodeHealth .probeTimestamp ,
1007
1052
readyTransitionTimestamp : nc .now (),
1008
1053
lease : observedLease ,
1009
1054
}
@@ -1086,10 +1131,10 @@ func (nc *Controller) handleDisruption(zoneToNodeConditions map[string][]*v1.Nod
1086
1131
// When exiting disruption mode update probe timestamps on all Nodes.
1087
1132
now := nc .now ()
1088
1133
for i := range nodes {
1089
- v := nc .nodeHealthMap [ nodes [i ].Name ]
1134
+ v := nc .nodeHealthMap . getDeepCopy ( nodes [i ].Name )
1090
1135
v .probeTimestamp = now
1091
1136
v .readyTransitionTimestamp = now
1092
- nc .nodeHealthMap [ nodes [i ].Name ] = v
1137
+ nc .nodeHealthMap . set ( nodes [i ].Name , v )
1093
1138
}
1094
1139
// We reset all rate limiters to settings appropriate for the given state.
1095
1140
for k := range nc .zoneStates {
0 commit comments