66 lines
2.5 KiB
Go
66 lines
2.5 KiB
Go
/*
|
|
Copyright 2021 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package notfoundhandler
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
|
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
|
|
apirequest "k8s.io/apiserver/pkg/endpoints/request"
|
|
)
|
|
|
|
// New returns an HTTP handler that is meant to be executed at the end of the delegation chain.
|
|
// It checks if the request have been made before the server has installed all known HTTP paths.
|
|
// In that case it returns a 503 response otherwise it returns a 404.
|
|
//
|
|
// Note that we don't want to add additional checks to the readyz path as it might prevent fixing bricked clusters.
|
|
// This specific handler is meant to "protect" requests that arrive before the paths and handlers are fully initialized.
|
|
func New(serializer runtime.NegotiatedSerializer, isMuxAndDiscoveryCompleteFn func(ctx context.Context) bool) *Handler {
|
|
return &Handler{serializer: serializer, isMuxAndDiscoveryCompleteFn: isMuxAndDiscoveryCompleteFn}
|
|
}
|
|
|
|
type Handler struct {
|
|
serializer runtime.NegotiatedSerializer
|
|
isMuxAndDiscoveryCompleteFn func(ctx context.Context) bool
|
|
}
|
|
|
|
func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|
if !h.isMuxAndDiscoveryCompleteFn(req.Context()) {
|
|
errMsg := "the request has been made before all known HTTP paths have been installed, please try again"
|
|
err := apierrors.NewServiceUnavailable(errMsg)
|
|
if err.ErrStatus.Details == nil {
|
|
err.ErrStatus.Details = &metav1.StatusDetails{}
|
|
}
|
|
err.ErrStatus.Details.RetryAfterSeconds = int32(5)
|
|
|
|
gv := schema.GroupVersion{Group: "unknown", Version: "unknown"}
|
|
requestInfo, ok := apirequest.RequestInfoFrom(req.Context())
|
|
if ok {
|
|
gv.Group = requestInfo.APIGroup
|
|
gv.Version = requestInfo.APIVersion
|
|
}
|
|
responsewriters.ErrorNegotiated(err, h.serializer, gv, rw, req)
|
|
return
|
|
}
|
|
http.NotFound(rw, req)
|
|
}
|