Merge pull request #105623 from ash2k/ash2k/resettable-rest-mapper

ResettableRESTMapper to make it possible to reset wrapped mappers
This commit is contained in:
Kubernetes Prow Robot 2021-11-16 16:36:08 -08:00 committed by GitHub
commit 165b581759
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 71 additions and 17 deletions

View File

@ -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.

View File

@ -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{}

View File

@ -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 {

View File

@ -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()
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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,

View File

@ -335,4 +335,4 @@ func (d *DeferredDiscoveryRESTMapper) String() string {
}
// Make sure it satisfies the interface
var _ meta.RESTMapper = &DeferredDiscoveryRESTMapper{}
var _ meta.ResettableRESTMapper = &DeferredDiscoveryRESTMapper{}

View File

@ -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 {