@@ -49,9 +49,13 @@ import (
4949 "github.com/libopenstorage/operator/pkg/util/k8s"
5050)
5151
52+ const (
53+ k8sNodeUpdateAttempts = 5
54+ )
55+
5256// rollingUpdate deletes old storage cluster pods making sure that no more than
5357// cluster.Spec.UpdateStrategy.RollingUpdate.MaxUnavailable pods are unavailable
54- func (c * Controller ) rollingUpdate (cluster * corev1.StorageCluster , hash string ) error {
58+ func (c * Controller ) rollingUpdate (cluster * corev1.StorageCluster , hash string , nodeList * v1. NodeList ) error {
5559 logrus .Debug ("Perform rolling update" )
5660 nodeToStoragePods , err := c .getNodeToStoragePods (cluster )
5761 if err != nil {
@@ -74,7 +78,7 @@ func (c *Controller) rollingUpdate(cluster *corev1.StorageCluster, hash string)
7478 continue
7579 }
7680 if _ , ok := availablePods [pod .Name ]; ok {
77- if err := c .removeStorkUnschedulableLabel (pod .Spec .NodeName ); err != nil {
81+ if err := c .removeNodeUnschedulableLabel (pod .Spec .NodeName ); err != nil {
7882 return err
7983 }
8084 }
@@ -94,7 +98,7 @@ func (c *Controller) rollingUpdate(cluster *corev1.StorageCluster, hash string)
9498 oldPodsToDelete = append (oldPodsToDelete , pod .Name )
9599 }
96100
97- // TODO: Max unavaibable kvdb nodes has been set to 1 assuming default setup of 3 KVDB nodes.
101+ // TODO: Max unavailable kvdb nodes has been set to 1 assuming default setup of 3 KVDB nodes.
98102 // Need to generalise code for 5 KVDB nodes
99103
100104 // get the number of kvdb members which are unavailable in case of internal kvdb
@@ -107,7 +111,21 @@ func (c *Controller) rollingUpdate(cluster *corev1.StorageCluster, hash string)
107111 }
108112 }
109113
114+ nodesMarkedUnschedulable := map [string ]bool {}
115+ for _ , node := range nodeList .Items {
116+ if nodeMarkedUnschedulable (& node ) {
117+ nodesMarkedUnschedulable [node .Name ] = true
118+ }
119+ }
110120 logrus .Debugf ("Marking old pods for deletion" )
121+ // sort the pods such that the pods on the nodes that we marked unschedulable are deleted first
122+ // Otherwise, we will end up marking too many nodes as unschedulable (or ping-ponging VMs between the nodes).
123+ sort .Slice (oldAvailablePods , func (i , j int ) bool {
124+ iUnschedulable := nodesMarkedUnschedulable [oldAvailablePods [i ].Spec .NodeName ]
125+ jUnschedulable := nodesMarkedUnschedulable [oldAvailablePods [j ].Spec .NodeName ]
126+
127+ return iUnschedulable && ! jUnschedulable
128+ })
111129 for _ , pod := range oldAvailablePods {
112130 if numUnavailable >= maxUnavailable {
113131 logrus .Infof ("Number of unavailable StorageCluster pods: %d, is equal " +
@@ -166,7 +184,7 @@ func (c *Controller) rollingUpdate(cluster *corev1.StorageCluster, hash string)
166184 logrus .Warnf ("Pod %s has no node name; cannot add unschedulable label to the node" , podName )
167185 continue
168186 }
169- if err := c .addStorkUnschedulableAnnotation (pod .Spec .NodeName ); err != nil {
187+ if err := c .addNodeUnschedulableAnnotation (pod .Spec .NodeName ); err != nil {
170188 return err
171189 }
172190 }
@@ -220,15 +238,30 @@ func (c *Controller) rollingUpdate(cluster *corev1.StorageCluster, hash string)
220238 return c .syncNodes (cluster , oldPodsToDeletePruned , []string {}, hash )
221239}
222240
223- func (c * Controller ) addStorkUnschedulableAnnotation (nodeName string ) error {
224- return storkUnschedulableAnnotationHelper (c .client , nodeName , true )
241+ func (c * Controller ) addNodeUnschedulableAnnotation (nodeName string ) error {
242+ return nodeUnschedulableAnnotationHelperWithRetries (c .client , nodeName , true )
225243}
226244
227- func (c * Controller ) removeStorkUnschedulableLabel (nodeName string ) error {
228- return storkUnschedulableAnnotationHelper (c .client , nodeName , false )
245+ func (c * Controller ) removeNodeUnschedulableLabel (nodeName string ) error {
246+ return nodeUnschedulableAnnotationHelperWithRetries (c .client , nodeName , false )
229247}
230248
231- func storkUnschedulableAnnotationHelper (k8sClient client.Client , nodeName string , unschedulable bool ) error {
249+ func nodeUnschedulableAnnotationHelperWithRetries (
250+ k8sClient client.Client , nodeName string , unschedulable bool ,
251+ ) error {
252+ var err error
253+ for i := 0 ; i < k8sNodeUpdateAttempts ; i ++ {
254+ err = nodeUnschedulableAnnotationHelper (k8sClient , nodeName , unschedulable )
255+ if err == nil || ! errors .IsConflict (err ) {
256+ return err
257+ }
258+ logrus .Warnf ("Conflict while updating annotation %s on node %s in attempt %d: %v" ,
259+ constants .AnnotationUnschedulable , nodeName , i , err )
260+ }
261+ return err
262+ }
263+
264+ func nodeUnschedulableAnnotationHelper (k8sClient client.Client , nodeName string , unschedulable bool ) error {
232265 ctx := context .TODO ()
233266 node := & v1.Node {}
234267 err := k8sClient .Get (ctx , types.NamespacedName {Name : nodeName }, node )
@@ -240,28 +273,25 @@ func storkUnschedulableAnnotationHelper(k8sClient client.Client, nodeName string
240273 return fmt .Errorf ("failed to get node %s: %w" , nodeName , err )
241274 }
242275 needsUpdate := false
243- val , ok := node .Annotations [constants .StorkAnnotationUnschedulable ]
244- if unschedulable && val != "true" {
276+ val := nodeMarkedUnschedulable (node )
277+ if unschedulable && ! val {
278+ logrus .Infof ("Adding annotation %s to node %s" , constants .AnnotationUnschedulable , nodeName )
245279 if node .Annotations == nil {
246280 node .Annotations = make (map [string ]string )
247281 }
248- node .Annotations [constants .StorkAnnotationUnschedulable ] = "true"
282+ node .Annotations [constants .AnnotationUnschedulable ] = "true"
249283 needsUpdate = true
250- } else if ! unschedulable && ok {
251- delete (node .Annotations , constants .StorkAnnotationUnschedulable )
284+ } else if ! unschedulable && val {
285+ logrus .Infof ("Removing annotation %s from node %s" , constants .AnnotationUnschedulable , nodeName )
286+ delete (node .Annotations , constants .AnnotationUnschedulable )
252287 needsUpdate = true
253288 }
254289 if ! needsUpdate {
255290 return nil
256291 }
257- if unschedulable {
258- logrus .Infof ("Adding annotation %s to node %s" , constants .StorkAnnotationUnschedulable , nodeName )
259- } else {
260- logrus .Infof ("Removing annotation %s from node %s" , constants .StorkAnnotationUnschedulable , nodeName )
261- }
262292 if err := k8sClient .Update (ctx , node ); err != nil {
263293 return fmt .Errorf ("failed to update annotation %s on node %s: %w" ,
264- constants .StorkAnnotationUnschedulable , nodeName , err )
294+ constants .AnnotationUnschedulable , nodeName , err )
265295 }
266296 return nil
267297}
0 commit comments