Fix handler panic when bootstrapper returned empty peer list

Panic gets rescued by the http server, and was only visible when running in debug mode, but should be handled properly.

Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
This commit is contained in:
Brad Davidson 2025-04-18 07:55:58 +00:00 committed by Brad Davidson
parent 0226ea511c
commit b8a705d9c2
5 changed files with 18 additions and 9 deletions

View file

@ -56,7 +56,7 @@ func Start(ctx context.Context, nodeConfig *config.Node, runtime *config.Control
runtime.Handler = router
}
router.Use(auth.Delegated(nodeConfig.AgentConfig.ClientCA, nodeConfig.AgentConfig.KubeConfigKubelet, config))
router.Use(auth.RequestInfo(), auth.Delegated(nodeConfig.AgentConfig.ClientCA, nodeConfig.AgentConfig.KubeConfigKubelet, config))
if config.SecureServing != nil {
_, _, err = config.SecureServing.Serve(router, 0, ctx.Done())

View file

@ -124,19 +124,23 @@ func Delegated(clientCA, kubeConfig string, config *server.Config) mux.Middlewar
return func(handler http.Handler) http.Handler {
handler = genericapifilters.WithAuthorization(handler, config.Authorization.Authorizer, scheme.Codecs)
handler = genericapifilters.WithAuthentication(handler, config.Authentication.Authenticator, failedHandler, nil, nil)
handler = genericapifilters.WithRequestInfo(handler, requestInfoResolver)
handler = genericapifilters.WithCacheControl(handler)
return handler
}
}
// RequestInfo returns a middleware function that adds verb/resource/gvk/etc info to the request context.
// This must be set for other filters to function, but only needs to be in each middleware chain once.
func RequestInfo() mux.MiddlewareFunc {
return func(handler http.Handler) http.Handler {
return genericapifilters.WithRequestInfo(handler, requestInfoResolver)
}
}
// MaxInFlight returns a middleware function that limits the number of requests that are executed concurrently.
// This is not strictly auth related, but it also uses the core Kubernetes request filters.
func MaxInFlight(nonMutatingLimit, mutatingLimit int) mux.MiddlewareFunc {
return func(handler http.Handler) http.Handler {
handler = genericfilters.WithMaxInFlightLimit(handler, nonMutatingLimit, mutatingLimit, nil)
handler = genericapifilters.WithRequestInfo(handler, requestInfoResolver)
handler = genericapifilters.WithCacheControl(handler)
return handler
return genericfilters.WithMaxInFlightLimit(handler, nonMutatingLimit, mutatingLimit, nil)
}
}

View file

@ -33,7 +33,7 @@ func NewHandler(ctx context.Context, control *config.Control, cfg *cmds.Server)
prefix := "/v1-{program}"
authed := mux.NewRouter().SkipClean(true)
authed.NotFoundHandler = APIServer(control, cfg)
authed.Use(auth.HasRole(control, version.Program+":agent", user.NodesGroup, bootstrapapi.BootstrapDefaultGroup), auth.MaxInFlight(maxNonMutatingAgentRequests, maxMutatingAgentRequests))
authed.Use(auth.HasRole(control, version.Program+":agent", user.NodesGroup, bootstrapapi.BootstrapDefaultGroup), auth.RequestInfo(), auth.MaxInFlight(maxNonMutatingAgentRequests, maxMutatingAgentRequests))
authed.Handle(prefix+"/serving-kubelet.crt", ServingKubeletCert(control, nodeAuth))
authed.Handle(prefix+"/client-kubelet.crt", ClientKubeletCert(control, nodeAuth))
authed.Handle(prefix+"/client-kube-proxy.crt", ClientKubeProxyCert(control))

View file

@ -241,7 +241,7 @@ func (c *chainingBootstrapper) Get(ctx context.Context) ([]peer.AddrInfo, error)
as, err := b.Get(ctx)
if err != nil {
errs = append(errs, err)
} else {
} else if len(as) != 0 {
return as, nil
}
}

View file

@ -256,7 +256,7 @@ func (c *Config) Start(ctx context.Context, nodeConfig *config.Node) error {
func (c *Config) peerInfo() http.HandlerFunc {
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
info, err := c.Bootstrapper.Get(req.Context())
if err != nil || len(info) == 0 {
if err != nil {
http.Error(resp, err.Error(), http.StatusInternalServerError)
return
}
@ -268,6 +268,11 @@ func (c *Config) peerInfo() http.HandlerFunc {
}
}
if len(addrs) == 0 {
http.Error(resp, "no peer addresses available", http.StatusServiceUnavailable)
return
}
client, _, _ := net.SplitHostPort(req.RemoteAddr)
if req.Header.Get("Accept") == "application/json" {
b, err := json.Marshal(addrs)