@@ -85,6 +85,9 @@ type ResourceManager interface {
8585// The group from the least-numbered source is used
8686WithSource (source Source ) ResourceManager
8787
88+ // AddInvalidationCallback adds a callback to be called when the discovery cache is invalidated.
89+ AddInvalidationCallback (callback func ())
90+
8891http.Handler
8992}
9093
@@ -116,6 +119,10 @@ func (rm resourceManager) WithSource(source Source) ResourceManager {
116119}
117120}
118121
122+ func (rm resourceManager ) AddInvalidationCallback (callback func ()) {
123+ rm .resourceDiscoveryManager .AddInvalidationCallback (callback )
124+ }
125+
119126type groupKey struct {
120127name string
121128
@@ -138,16 +145,28 @@ type resourceDiscoveryManager struct {
138145
139146// Writes protected by the lock.
140147// List of all apigroups & resources indexed by the resource manager
141- lock sync.RWMutex
142- apiGroups map [groupKey ]* apidiscoveryv2.APIGroupDiscovery
143- versionPriorities map [groupVersionKey ]priorityInfo
148+ lock sync.RWMutex
149+ apiGroups map [groupKey ]* apidiscoveryv2.APIGroupDiscovery
150+ versionPriorities map [groupVersionKey ]priorityInfo
151+ invalidationCallback atomic.Pointer [func ()]
144152}
145153
146154type priorityInfo struct {
147155GroupPriorityMinimum int
148156VersionPriority int
149157}
150158
159+ func (rdm * resourceDiscoveryManager ) AddInvalidationCallback (callback func ()) {
160+ rdm .invalidationCallback .Store (& callback )
161+ }
162+
163+ func (rdm * resourceDiscoveryManager ) invalidateCacheLocked () {
164+ rdm .cache .Store (nil )
165+ if callback := rdm .invalidationCallback .Load (); callback != nil {
166+ (* callback )()
167+ }
168+ }
169+
151170func NewResourceManager (path string ) ResourceManager {
152171scheme := runtime .NewScheme ()
153172utilruntime .Must (apidiscoveryv2 .AddToScheme (scheme ))
@@ -188,15 +207,15 @@ func (rdm *resourceDiscoveryManager) SetGroupVersionPriority(source Source, gv m
188207GroupPriorityMinimum : groupPriorityMinimum ,
189208VersionPriority : versionPriority ,
190209}
191- rdm .cache . Store ( nil )
210+ rdm .invalidateCacheLocked ( )
192211}
193212
194213func (rdm * resourceDiscoveryManager ) SetGroups (source Source , groups []apidiscoveryv2.APIGroupDiscovery ) {
195214rdm .lock .Lock ()
196215defer rdm .lock .Unlock ()
197216
198217rdm .apiGroups = nil
199- rdm .cache . Store ( nil )
218+ rdm .invalidateCacheLocked ( )
200219
201220for _ , group := range groups {
202221for _ , version := range group .Versions {
@@ -297,7 +316,7 @@ func (rdm *resourceDiscoveryManager) addGroupVersionLocked(source Source, groupN
297316}
298317
299318// Reset response document so it is recreated lazily
300- rdm .cache . Store ( nil )
319+ rdm .invalidateCacheLocked ( )
301320}
302321
303322func (rdm * resourceDiscoveryManager ) RemoveGroupVersion (source Source , apiGroup metav1.GroupVersion ) {
@@ -338,7 +357,7 @@ func (rdm *resourceDiscoveryManager) RemoveGroupVersion(source Source, apiGroup
338357}
339358
340359// Reset response document so it is recreated lazily
341- rdm .cache . Store ( nil )
360+ rdm .invalidateCacheLocked ( )
342361}
343362
344363func (rdm * resourceDiscoveryManager ) RemoveGroup (source Source , groupName string ) {
@@ -521,53 +540,62 @@ func (rdm *resourceDiscoveryManager) serveHTTP(resp http.ResponseWriter, req *ht
521540response := cache .cachedResponse
522541etag := cache .cachedResponseETag
523542
524- mediaType , _ , err := negotiation .NegotiateOutputMediaType (req , rdm .serializer , DiscoveryEndpointRestrictions )
543+ writeDiscoveryResponse (& response , etag , rdm .serializer , resp , req )
544+ }
545+
546+ func writeDiscoveryResponse (
547+ resp * apidiscoveryv2.APIGroupDiscoveryList ,
548+ etag string ,
549+ serializer runtime.NegotiatedSerializer ,
550+ w http.ResponseWriter ,
551+ req * http.Request ,
552+ ) {
553+ mediaType , _ , err := negotiation .NegotiateOutputMediaType (req , serializer , DiscoveryEndpointRestrictions )
525554if err != nil {
526555// Should never happen. wrapper.go will only proxy requests to this
527556// handler if the media type passes DiscoveryEndpointRestrictions
528557utilruntime .HandleError (err )
529- resp .WriteHeader (http .StatusInternalServerError )
558+ w .WriteHeader (http .StatusInternalServerError )
530559return
531560}
532561var targetGV schema.GroupVersion
533562if mediaType .Convert == nil ||
534563(mediaType .Convert .GroupVersion () != apidiscoveryv2 .SchemeGroupVersion &&
535564mediaType .Convert .GroupVersion () != apidiscoveryv2beta1 .SchemeGroupVersion ) {
536565utilruntime .HandleError (fmt .Errorf ("expected aggregated discovery group version, got group: %s, version %s" , mediaType .Convert .Group , mediaType .Convert .Version ))
537- resp .WriteHeader (http .StatusInternalServerError )
566+ w .WriteHeader (http .StatusInternalServerError )
538567return
539568}
540569
541570if mediaType .Convert .GroupVersion () == apidiscoveryv2beta1 .SchemeGroupVersion &&
542571utilfeature .DefaultFeatureGate .Enabled (genericfeatures .AggregatedDiscoveryRemoveBetaType ) {
543572klog .Errorf ("aggregated discovery version v2beta1 is removed. Please update to use v2" )
544- resp .WriteHeader (http .StatusNotFound )
573+ w .WriteHeader (http .StatusNotFound )
545574return
546575}
547-
548576targetGV = mediaType .Convert .GroupVersion ()
549577
550578if len (etag ) > 0 {
551579// Use proper e-tag headers if one is available
552580ServeHTTPWithETag (
553- & response ,
581+ resp ,
554582etag ,
555583targetGV ,
556- rdm . serializer ,
557- resp ,
584+ serializer ,
585+ w ,
558586req ,
559587)
560588} else {
561589// Default to normal response in rare case etag is
562590// not cached with the object for some reason.
563591responsewriters .WriteObjectNegotiated (
564- rdm . serializer ,
592+ serializer ,
565593DiscoveryEndpointRestrictions ,
566594targetGV ,
567- resp ,
595+ w ,
568596req ,
569597http .StatusOK ,
570- & response ,
598+ resp ,
571599true ,
572600)
573601}
0 commit comments