Skip to content

Commit 2cfc3c6

Browse files
committed
apiextensions: avoid two HA API server to fight for NonStructural condition message
1 parent 4f28fa8 commit 2cfc3c6

File tree

1 file changed

+46
-5
lines changed

1 file changed

+46
-5
lines changed

staging/src/k8s.io/apiextensions-apiserver/pkg/controller/nonstructuralschema/nonstructuralschema_controller.go

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package nonstructuralschema
1818

1919
import (
2020
"fmt"
21+
"sync"
2122
"time"
2223

2324
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -47,6 +48,11 @@ type ConditionController struct {
4748
syncFn func(key string) error
4849

4950
queue workqueue.RateLimitingInterface
51+
52+
// last generation this controller updated the condition per CRD name (to avoid two
53+
// different version of the apiextensions-apiservers in HA to fight for the right message)
54+
lastSeenGenerationLock sync.Mutex
55+
lastSeenGeneration map[string]int64
5056
}
5157

5258
// NewConditionController constructs a non-structural schema condition controller.
@@ -55,16 +61,17 @@ func NewConditionController(
5561
crdClient client.CustomResourceDefinitionsGetter,
5662
) *ConditionController {
5763
c := &ConditionController{
58-
crdClient: crdClient,
59-
crdLister: crdInformer.Lister(),
60-
crdSynced: crdInformer.Informer().HasSynced,
61-
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "non_structural_schema_condition_controller"),
64+
crdClient: crdClient,
65+
crdLister: crdInformer.Lister(),
66+
crdSynced: crdInformer.Informer().HasSynced,
67+
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "non_structural_schema_condition_controller"),
68+
lastSeenGeneration: map[string]int64{},
6269
}
6370

6471
crdInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
6572
AddFunc: c.addCustomResourceDefinition,
6673
UpdateFunc: c.updateCustomResourceDefinition,
67-
DeleteFunc: nil,
74+
DeleteFunc: c.deleteCustomResourceDefinition,
6875
})
6976

7077
c.syncFn = c.sync
@@ -130,6 +137,14 @@ func (c *ConditionController) sync(key string) error {
130137
return err
131138
}
132139

140+
// avoid repeated calculation for the same generation
141+
c.lastSeenGenerationLock.Lock()
142+
lastSeen, seenBefore := c.lastSeenGeneration[inCustomResourceDefinition.Name]
143+
c.lastSeenGenerationLock.Unlock()
144+
if seenBefore && inCustomResourceDefinition.Generation <= lastSeen {
145+
return nil
146+
}
147+
133148
// check old condition
134149
cond := calculateCondition(inCustomResourceDefinition)
135150
old := apiextensions.FindCRDCondition(inCustomResourceDefinition, apiextensions.NonStructuralSchema)
@@ -159,6 +174,12 @@ func (c *ConditionController) sync(key string) error {
159174
return err
160175
}
161176

177+
// store generation in order to avoid repeated updates for the same generation (and potential
178+
// fights of API server in HA environments).
179+
c.lastSeenGenerationLock.Lock()
180+
defer c.lastSeenGenerationLock.Unlock()
181+
c.lastSeenGeneration[crd.Name] = crd.Generation
182+
162183
return nil
163184
}
164185

@@ -227,3 +248,23 @@ func (c *ConditionController) updateCustomResourceDefinition(obj, _ interface{})
227248
klog.V(4).Infof("Updating %s", castObj.Name)
228249
c.enqueue(castObj)
229250
}
251+
252+
func (c *ConditionController) deleteCustomResourceDefinition(obj interface{}) {
253+
castObj, ok := obj.(*apiextensions.CustomResourceDefinition)
254+
if !ok {
255+
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
256+
if !ok {
257+
klog.Errorf("Couldn't get object from tombstone %#v", obj)
258+
return
259+
}
260+
castObj, ok = tombstone.Obj.(*apiextensions.CustomResourceDefinition)
261+
if !ok {
262+
klog.Errorf("Tombstone contained object that is not expected %#v", obj)
263+
return
264+
}
265+
}
266+
267+
c.lastSeenGenerationLock.Lock()
268+
defer c.lastSeenGenerationLock.Unlock()
269+
delete(c.lastSeenGeneration, castObj.Name)
270+
}

0 commit comments

Comments
 (0)