diff --git a/pkg/controller/garbagecollector/garbagecollector.go b/pkg/controller/garbagecollector/garbagecollector.go index 9028accb14c..4f6d445c763 100644 --- a/pkg/controller/garbagecollector/garbagecollector.go +++ b/pkg/controller/garbagecollector/garbagecollector.go @@ -24,8 +24,6 @@ import ( "sync" "time" - "k8s.io/klog/v2" - v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" @@ -45,6 +43,7 @@ import ( "k8s.io/client-go/util/workqueue" "k8s.io/controller-manager/controller" "k8s.io/controller-manager/pkg/informerfactory" + "k8s.io/klog/v2" c "k8s.io/kubernetes/pkg/controller" "k8s.io/kubernetes/pkg/controller/apis/config/scheme" @@ -67,7 +66,7 @@ const ResourceResyncTime time.Duration = 0 // ensures that the garbage collector operates with a graph that is at least as // up to date as the notification is sent. type GarbageCollector struct { - restMapper resettableRESTMapper + restMapper meta.ResettableRESTMapper metadataClient metadata.Interface // garbage collector attempts to delete the items in attemptToDelete queue when the time is ripe. attemptToDelete workqueue.RateLimitingInterface @@ -87,7 +86,7 @@ var _ controller.Debuggable = (*GarbageCollector)(nil) func NewGarbageCollector( kubeClient clientset.Interface, metadataClient metadata.Interface, - mapper resettableRESTMapper, + mapper meta.ResettableRESTMapper, ignoredResources map[schema.GroupResource]struct{}, sharedInformers informerfactory.InformerFactory, informersStarted <-chan struct{}, @@ -164,13 +163,6 @@ func (gc *GarbageCollector) Run(ctx context.Context, workers int) { <-ctx.Done() } -// resettableRESTMapper is a RESTMapper which is capable of resetting itself -// from discovery. -type resettableRESTMapper interface { - meta.RESTMapper - Reset() -} - // Sync periodically resyncs the garbage collector when new resources are // observed from discovery. When new resources are detected, Sync will stop all // GC workers, reset gc.restMapper, and resync the monitors. diff --git a/pkg/controller/garbagecollector/garbagecollector_test.go b/pkg/controller/garbagecollector/garbagecollector_test.go index e239c51a4a8..64b3f0faccc 100644 --- a/pkg/controller/garbagecollector/garbagecollector_test.go +++ b/pkg/controller/garbagecollector/garbagecollector_test.go @@ -67,7 +67,9 @@ type testRESTMapper struct { meta.RESTMapper } -func (*testRESTMapper) Reset() {} +func (m *testRESTMapper) Reset() { + meta.MaybeResetRESTMapper(m.RESTMapper) +} func TestGarbageCollectorConstruction(t *testing.T) { config := &restclient.Config{} diff --git a/staging/src/k8s.io/apimachinery/pkg/api/meta/firsthit_restmapper.go b/staging/src/k8s.io/apimachinery/pkg/api/meta/firsthit_restmapper.go index fd221002290..1bc816fe3f3 100644 --- a/staging/src/k8s.io/apimachinery/pkg/api/meta/firsthit_restmapper.go +++ b/staging/src/k8s.io/apimachinery/pkg/api/meta/firsthit_restmapper.go @@ -23,6 +23,10 @@ import ( utilerrors "k8s.io/apimachinery/pkg/util/errors" ) +var ( + _ ResettableRESTMapper = &FirstHitRESTMapper{} +) + // FirstHitRESTMapper is a wrapper for multiple RESTMappers which returns the // first successful result for the singular requests type FirstHitRESTMapper struct { @@ -75,6 +79,10 @@ func (m FirstHitRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) return nil, collapseAggregateErrors(errors) } +func (m FirstHitRESTMapper) Reset() { + m.MultiRESTMapper.Reset() +} + // collapseAggregateErrors returns the minimal errors. it handles empty as nil, handles one item in a list // by returning the item, and collapses all NoMatchErrors to a single one (since they should all be the same) func collapseAggregateErrors(errors []error) error { diff --git a/staging/src/k8s.io/apimachinery/pkg/api/meta/interfaces.go b/staging/src/k8s.io/apimachinery/pkg/api/meta/interfaces.go index 42eac3af001..a35ce3bd0aa 100644 --- a/staging/src/k8s.io/apimachinery/pkg/api/meta/interfaces.go +++ b/staging/src/k8s.io/apimachinery/pkg/api/meta/interfaces.go @@ -132,3 +132,12 @@ type RESTMapper interface { ResourceSingularizer(resource string) (singular string, err error) } + +// ResettableRESTMapper is a RESTMapper which is capable of resetting itself +// from discovery. +// All rest mappers that delegate to other rest mappers must implement this interface and dynamically +// check if the delegate mapper supports the Reset() operation. +type ResettableRESTMapper interface { + RESTMapper + Reset() +} diff --git a/staging/src/k8s.io/apimachinery/pkg/api/meta/lazy.go b/staging/src/k8s.io/apimachinery/pkg/api/meta/lazy.go index 431a0a63532..a4298114b6d 100644 --- a/staging/src/k8s.io/apimachinery/pkg/api/meta/lazy.go +++ b/staging/src/k8s.io/apimachinery/pkg/api/meta/lazy.go @@ -32,7 +32,7 @@ type lazyObject struct { mapper RESTMapper } -// NewLazyObjectLoader handles unrecoverable errors when creating a RESTMapper / ObjectTyper by +// NewLazyRESTMapperLoader handles unrecoverable errors when creating a RESTMapper / ObjectTyper by // returning those initialization errors when the interface methods are invoked. This defers the // initialization and any server calls until a client actually needs to perform the action. func NewLazyRESTMapperLoader(fn func() (RESTMapper, error)) RESTMapper { @@ -52,7 +52,7 @@ func (o *lazyObject) init() error { return o.err } -var _ RESTMapper = &lazyObject{} +var _ ResettableRESTMapper = &lazyObject{} func (o *lazyObject) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) { if err := o.init(); err != nil { @@ -102,3 +102,11 @@ func (o *lazyObject) ResourceSingularizer(resource string) (singular string, err } return o.mapper.ResourceSingularizer(resource) } + +func (o *lazyObject) Reset() { + o.lock.Lock() + defer o.lock.Unlock() + if o.loaded && o.err == nil { + MaybeResetRESTMapper(o.mapper) + } +} diff --git a/staging/src/k8s.io/apimachinery/pkg/api/meta/multirestmapper.go b/staging/src/k8s.io/apimachinery/pkg/api/meta/multirestmapper.go index 6b01bf197fa..b7e97125052 100644 --- a/staging/src/k8s.io/apimachinery/pkg/api/meta/multirestmapper.go +++ b/staging/src/k8s.io/apimachinery/pkg/api/meta/multirestmapper.go @@ -24,11 +24,15 @@ import ( utilerrors "k8s.io/apimachinery/pkg/util/errors" ) +var ( + _ ResettableRESTMapper = MultiRESTMapper{} +) + // MultiRESTMapper is a wrapper for multiple RESTMappers. type MultiRESTMapper []RESTMapper func (m MultiRESTMapper) String() string { - nested := []string{} + nested := make([]string, 0, len(m)) for _, t := range m { currString := fmt.Sprintf("%v", t) splitStrings := strings.Split(currString, "\n") @@ -208,3 +212,9 @@ func (m MultiRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) ( } return allMappings, nil } + +func (m MultiRESTMapper) Reset() { + for _, t := range m { + MaybeResetRESTMapper(t) + } +} diff --git a/staging/src/k8s.io/apimachinery/pkg/api/meta/priority.go b/staging/src/k8s.io/apimachinery/pkg/api/meta/priority.go index fa11c580f70..4f097c9c90d 100644 --- a/staging/src/k8s.io/apimachinery/pkg/api/meta/priority.go +++ b/staging/src/k8s.io/apimachinery/pkg/api/meta/priority.go @@ -29,6 +29,10 @@ const ( AnyKind = "*" ) +var ( + _ ResettableRESTMapper = PriorityRESTMapper{} +) + // PriorityRESTMapper is a wrapper for automatically choosing a particular Resource or Kind // when multiple matches are possible type PriorityRESTMapper struct { @@ -220,3 +224,7 @@ func (m PriorityRESTMapper) ResourcesFor(partiallySpecifiedResource schema.Group func (m PriorityRESTMapper) KindsFor(partiallySpecifiedResource schema.GroupVersionResource) (gvk []schema.GroupVersionKind, err error) { return m.Delegate.KindsFor(partiallySpecifiedResource) } + +func (m PriorityRESTMapper) Reset() { + MaybeResetRESTMapper(m.Delegate) +} diff --git a/staging/src/k8s.io/apimachinery/pkg/api/meta/restmapper.go b/staging/src/k8s.io/apimachinery/pkg/api/meta/restmapper.go index 00bd86f51a7..f41b9bf78ce 100644 --- a/staging/src/k8s.io/apimachinery/pkg/api/meta/restmapper.go +++ b/staging/src/k8s.io/apimachinery/pkg/api/meta/restmapper.go @@ -519,3 +519,12 @@ func (m *DefaultRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string } return mappings, nil } + +// MaybeResetRESTMapper calls Reset() on the mapper if it is a ResettableRESTMapper. +func MaybeResetRESTMapper(mapper RESTMapper) bool { + m, ok := mapper.(ResettableRESTMapper) + if ok { + m.Reset() + } + return ok +} diff --git a/staging/src/k8s.io/cli-runtime/pkg/resource/builder_test.go b/staging/src/k8s.io/cli-runtime/pkg/resource/builder_test.go index bc6e3c66fb0..e990ec5ed34 100644 --- a/staging/src/k8s.io/cli-runtime/pkg/resource/builder_test.go +++ b/staging/src/k8s.io/cli-runtime/pkg/resource/builder_test.go @@ -335,6 +335,10 @@ func (l *errorRestMapper) RESTMapping(gk schema.GroupKind, versions ...string) ( return nil, l.err } +func (l *errorRestMapper) Reset() { + meta.MaybeResetRESTMapper(l.RESTMapper) +} + func newDefaultBuilderWithMapperError(fakeClientFn FakeClientFunc, err error) *Builder { return NewFakeBuilder( fakeClientFn, diff --git a/staging/src/k8s.io/client-go/restmapper/discovery.go b/staging/src/k8s.io/client-go/restmapper/discovery.go index d560db84dc9..3505178b669 100644 --- a/staging/src/k8s.io/client-go/restmapper/discovery.go +++ b/staging/src/k8s.io/client-go/restmapper/discovery.go @@ -335,4 +335,4 @@ func (d *DeferredDiscoveryRESTMapper) String() string { } // Make sure it satisfies the interface -var _ meta.RESTMapper = &DeferredDiscoveryRESTMapper{} +var _ meta.ResettableRESTMapper = &DeferredDiscoveryRESTMapper{} diff --git a/staging/src/k8s.io/client-go/restmapper/shortcut.go b/staging/src/k8s.io/client-go/restmapper/shortcut.go index 73b317c1ca4..714ba90a7aa 100644 --- a/staging/src/k8s.io/client-go/restmapper/shortcut.go +++ b/staging/src/k8s.io/client-go/restmapper/shortcut.go @@ -34,7 +34,7 @@ type shortcutExpander struct { discoveryClient discovery.DiscoveryInterface } -var _ meta.RESTMapper = &shortcutExpander{} +var _ meta.ResettableRESTMapper = shortcutExpander{} // NewShortcutExpander wraps a restmapper in a layer that expands shortcuts found via discovery func NewShortcutExpander(delegate meta.RESTMapper, client discovery.DiscoveryInterface) meta.RESTMapper { @@ -164,6 +164,10 @@ func (e shortcutExpander) expandResourceShortcut(resource schema.GroupVersionRes return resource } +func (e shortcutExpander) Reset() { + meta.MaybeResetRESTMapper(e.RESTMapper) +} + // ResourceShortcuts represents a structure that holds the information how to // transition from resource's shortcut to its full name. type resourceShortcuts struct {