diff --git a/pkg/server/config.go b/pkg/server/config.go index 998999e8a..abd8bec09 100644 --- a/pkg/server/config.go +++ b/pkg/server/config.go @@ -23,6 +23,7 @@ import ( "net" "net/http" goruntime "runtime" + "runtime/debug" "sort" "strconv" "strings" @@ -116,6 +117,8 @@ type Config struct { EnableMetrics bool DisabledPostStartHooks sets.String + // done values in this values for this map are ignored. + PostStartHooks map[string]PostStartHookConfigEntry // Version will enable the /version endpoint if non-nil Version *version.Info @@ -282,6 +285,7 @@ func NewConfig(codecs serializer.CodecFactory) *Config { HandlerChainWaitGroup: new(utilwaitgroup.SafeWaitGroup), LegacyAPIGroupPrefixes: sets.NewString(DefaultLegacyAPIPrefix), DisabledPostStartHooks: sets.NewString(), + PostStartHooks: map[string]PostStartHookConfigEntry{}, HealthzChecks: append([]healthz.HealthChecker{}, defaultHealthChecks...), ReadyzChecks: append([]healthz.HealthChecker{}, defaultHealthChecks...), LivezChecks: append([]healthz.HealthChecker{}, defaultHealthChecks...), @@ -389,6 +393,36 @@ func (c *Config) AddHealthChecks(healthChecks ...healthz.HealthChecker) { } } +// AddPostStartHook allows you to add a PostStartHook that will later be added to the server itself in a New call. +// Name conflicts will cause an error. +func (c *Config) AddPostStartHook(name string, hook PostStartHookFunc) error { + if len(name) == 0 { + return fmt.Errorf("missing name") + } + if hook == nil { + return fmt.Errorf("hook func may not be nil: %q", name) + } + if c.DisabledPostStartHooks.Has(name) { + klog.V(1).Infof("skipping %q because it was explicitly disabled", name) + return nil + } + + if postStartHook, exists := c.PostStartHooks[name]; exists { + // this is programmer error, but it can be hard to debug + return fmt.Errorf("unable to add %q because it was already registered by: %s", name, postStartHook.originatingStack) + } + c.PostStartHooks[name] = PostStartHookConfigEntry{hook: hook, originatingStack: string(debug.Stack())} + + return nil +} + +// AddPostStartHookOrDie allows you to add a PostStartHook, but dies on failure. +func (c *Config) AddPostStartHookOrDie(name string, hook PostStartHookFunc) { + if err := c.AddPostStartHook(name, hook); err != nil { + klog.Fatalf("Error registering PostStartHook %q: %v", name, err) + } +} + // Complete fills in any fields not set that are required to have valid data and can be derived // from other fields. If you're going to `ApplyOptions`, do that first. It's mutating the receiver. func (c *Config) Complete(informers informers.SharedInformerFactory) CompletedConfig { @@ -550,6 +584,7 @@ func (c completedConfig) New(name string, delegationTarget DelegationTarget) (*G } } + // first add poststarthooks from delegated targets for k, v := range delegationTarget.PostStartHooks() { s.postStartHooks[k] = v } @@ -558,6 +593,13 @@ func (c completedConfig) New(name string, delegationTarget DelegationTarget) (*G s.preShutdownHooks[k] = v } + // add poststarthooks that were preconfigured. Using the add method will give us an error if the same name has already been registered. + for name, preconfiguredPostStartHook := range c.PostStartHooks { + if err := s.AddPostStartHook(name, preconfiguredPostStartHook.hook); err != nil { + return nil, err + } + } + genericApiServerHookName := "generic-apiserver-start-informers" if c.SharedInformerFactory != nil && !s.isPostStartHookRegistered(genericApiServerHookName) { err := s.AddPostStartHook(genericApiServerHookName, func(context PostStartHookContext) error { @@ -611,7 +653,6 @@ func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler { handler = genericfilters.WithTimeoutForNonLongRunningRequests(handler, c.LongRunningFunc, c.RequestTimeout) handler = genericfilters.WithWaitGroup(handler, c.LongRunningFunc, c.HandlerChainWaitGroup) handler = genericapifilters.WithRequestInfo(handler, c.RequestInfoResolver) - handler = genericapifilters.WithCacheControl(handler) handler = genericfilters.WithPanicRecovery(handler) return handler } diff --git a/pkg/server/hooks.go b/pkg/server/hooks.go index fba876d25..04e7f8302 100644 --- a/pkg/server/hooks.go +++ b/pkg/server/hooks.go @@ -66,6 +66,13 @@ type postStartHookEntry struct { done chan struct{} } +type PostStartHookConfigEntry struct { + hook PostStartHookFunc + // originatingStack holds the stack that registered postStartHooks. This allows us to show a more helpful message + // for duplicate registration. + originatingStack string +} + type preShutdownHookEntry struct { hook PreShutdownHookFunc } @@ -76,9 +83,10 @@ func (s *GenericAPIServer) AddPostStartHook(name string, hook PostStartHookFunc) return fmt.Errorf("missing name") } if hook == nil { - return nil + return fmt.Errorf("hook func may not be nil: %q", name) } if s.disabledPostStartHooks.Has(name) { + klog.V(1).Infof("skipping %q because it was explicitly disabled", name) return nil }