mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 18:43:34 +00:00
rebase: update k8s.io packages to v0.29.0
Signed-off-by: Niels de Vos <ndevos@ibm.com>
This commit is contained in:
committed by
mergify[bot]
parent
328a264202
commit
f080b9e0c9
150
vendor/k8s.io/apiserver/pkg/endpoints/handlers/watch.go
generated
vendored
150
vendor/k8s.io/apiserver/pkg/endpoints/handlers/watch.go
generated
vendored
@ -19,9 +19,7 @@ package handlers
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/websocket"
|
||||
@ -29,13 +27,15 @@ import (
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
|
||||
"k8s.io/apimachinery/pkg/util/httpstream/wsstream"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/apiserver/pkg/endpoints/handlers/negotiation"
|
||||
"k8s.io/apiserver/pkg/endpoints/metrics"
|
||||
apirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/apiserver/pkg/features"
|
||||
"k8s.io/apiserver/pkg/storage"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
)
|
||||
|
||||
// nothing will ever be sent down this channel
|
||||
@ -63,7 +63,7 @@ func (w *realTimeoutFactory) TimeoutCh() (<-chan time.Time, func() bool) {
|
||||
|
||||
// serveWatch will serve a watch response.
|
||||
// TODO: the functionality in this method and in WatchServer.Serve is not cleanly decoupled.
|
||||
func serveWatch(watcher watch.Interface, scope *RequestScope, mediaTypeOptions negotiation.MediaTypeOptions, req *http.Request, w http.ResponseWriter, timeout time.Duration) {
|
||||
func serveWatch(watcher watch.Interface, scope *RequestScope, mediaTypeOptions negotiation.MediaTypeOptions, req *http.Request, w http.ResponseWriter, timeout time.Duration, metricsScope string) {
|
||||
defer watcher.Stop()
|
||||
|
||||
options, err := optionsForTransform(mediaTypeOptions, req)
|
||||
@ -92,6 +92,8 @@ func serveWatch(watcher watch.Interface, scope *RequestScope, mediaTypeOptions n
|
||||
mediaType += ";stream=watch"
|
||||
}
|
||||
|
||||
ctx := req.Context()
|
||||
|
||||
// locate the appropriate embedded encoder based on the transform
|
||||
var embeddedEncoder runtime.Encoder
|
||||
contentKind, contentSerializer, transform := targetEncodingForTransform(scope, mediaTypeOptions, req)
|
||||
@ -106,13 +108,41 @@ func serveWatch(watcher watch.Interface, scope *RequestScope, mediaTypeOptions n
|
||||
embeddedEncoder = scope.Serializer.EncoderForVersion(serializer.Serializer, contentKind.GroupVersion())
|
||||
}
|
||||
|
||||
var memoryAllocator runtime.MemoryAllocator
|
||||
|
||||
if encoderWithAllocator, supportsAllocator := embeddedEncoder.(runtime.EncoderWithAllocator); supportsAllocator {
|
||||
// don't put the allocator inside the embeddedEncodeFn as that would allocate memory on every call.
|
||||
// instead, we allocate the buffer for the entire watch session and release it when we close the connection.
|
||||
memoryAllocator = runtime.AllocatorPool.Get().(*runtime.Allocator)
|
||||
defer runtime.AllocatorPool.Put(memoryAllocator)
|
||||
embeddedEncoder = runtime.NewEncoderWithAllocator(encoderWithAllocator, memoryAllocator)
|
||||
}
|
||||
var tableOptions *metav1.TableOptions
|
||||
if options != nil {
|
||||
if passedOptions, ok := options.(*metav1.TableOptions); ok {
|
||||
tableOptions = passedOptions
|
||||
} else {
|
||||
scope.err(fmt.Errorf("unexpected options type: %T", options), w, req)
|
||||
return
|
||||
}
|
||||
}
|
||||
embeddedEncoder = newWatchEmbeddedEncoder(ctx, embeddedEncoder, mediaTypeOptions.Convert, tableOptions, scope)
|
||||
|
||||
if encoderWithAllocator, supportsAllocator := encoder.(runtime.EncoderWithAllocator); supportsAllocator {
|
||||
if memoryAllocator == nil {
|
||||
// don't put the allocator inside the embeddedEncodeFn as that would allocate memory on every call.
|
||||
// instead, we allocate the buffer for the entire watch session and release it when we close the connection.
|
||||
memoryAllocator = runtime.AllocatorPool.Get().(*runtime.Allocator)
|
||||
defer runtime.AllocatorPool.Put(memoryAllocator)
|
||||
}
|
||||
encoder = runtime.NewEncoderWithAllocator(encoderWithAllocator, memoryAllocator)
|
||||
}
|
||||
|
||||
var serverShuttingDownCh <-chan struct{}
|
||||
if signals := apirequest.ServerShutdownSignalFrom(req.Context()); signals != nil {
|
||||
serverShuttingDownCh = signals.ShuttingDown()
|
||||
}
|
||||
|
||||
ctx := req.Context()
|
||||
|
||||
server := &WatchServer{
|
||||
Watching: watcher,
|
||||
Scope: scope,
|
||||
@ -123,23 +153,10 @@ func serveWatch(watcher watch.Interface, scope *RequestScope, mediaTypeOptions n
|
||||
Encoder: encoder,
|
||||
EmbeddedEncoder: embeddedEncoder,
|
||||
|
||||
Fixup: func(obj runtime.Object) runtime.Object {
|
||||
result, err := transformObject(ctx, obj, options, mediaTypeOptions, scope, req)
|
||||
if err != nil {
|
||||
utilruntime.HandleError(fmt.Errorf("failed to transform object %v: %v", reflect.TypeOf(obj), err))
|
||||
return obj
|
||||
}
|
||||
// When we are transformed to a table, use the table options as the state for whether we
|
||||
// should print headers - on watch, we only want to print table headers on the first object
|
||||
// and omit them on subsequent events.
|
||||
if tableOptions, ok := options.(*metav1.TableOptions); ok {
|
||||
tableOptions.NoHeaders = true
|
||||
}
|
||||
return result
|
||||
},
|
||||
|
||||
TimeoutFactory: &realTimeoutFactory{timeout},
|
||||
ServerShuttingDownCh: serverShuttingDownCh,
|
||||
|
||||
metricsScope: metricsScope,
|
||||
}
|
||||
|
||||
server.ServeHTTP(w, req)
|
||||
@ -160,11 +177,11 @@ type WatchServer struct {
|
||||
Encoder runtime.Encoder
|
||||
// used to encode the nested object in the watch stream
|
||||
EmbeddedEncoder runtime.Encoder
|
||||
// used to correct the object before we send it to the serializer
|
||||
Fixup func(runtime.Object) runtime.Object
|
||||
|
||||
TimeoutFactory TimeoutFactory
|
||||
ServerShuttingDownCh <-chan struct{}
|
||||
|
||||
metricsScope string
|
||||
}
|
||||
|
||||
// ServeHTTP serves a series of encoded events via HTTP with Transfer-Encoding: chunked
|
||||
@ -195,17 +212,6 @@ func (s *WatchServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
var e streaming.Encoder
|
||||
var memoryAllocator runtime.MemoryAllocator
|
||||
|
||||
if encoder, supportsAllocator := s.Encoder.(runtime.EncoderWithAllocator); supportsAllocator {
|
||||
memoryAllocator = runtime.AllocatorPool.Get().(*runtime.Allocator)
|
||||
defer runtime.AllocatorPool.Put(memoryAllocator)
|
||||
e = streaming.NewEncoderWithAllocator(framer, encoder, memoryAllocator)
|
||||
} else {
|
||||
e = streaming.NewEncoder(framer, s.Encoder)
|
||||
}
|
||||
|
||||
// ensure the connection times out
|
||||
timeoutCh, cleanup := s.TimeoutFactory.TimeoutCh()
|
||||
defer cleanup()
|
||||
@ -216,26 +222,10 @@ func (s *WatchServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
flusher.Flush()
|
||||
|
||||
var unknown runtime.Unknown
|
||||
internalEvent := &metav1.InternalEvent{}
|
||||
outEvent := &metav1.WatchEvent{}
|
||||
buf := runtime.NewSpliceBuffer()
|
||||
watchEncoder := newWatchEncoder(req.Context(), kind, s.EmbeddedEncoder, s.Encoder, framer)
|
||||
ch := s.Watching.ResultChan()
|
||||
done := req.Context().Done()
|
||||
|
||||
embeddedEncodeFn := s.EmbeddedEncoder.Encode
|
||||
if encoder, supportsAllocator := s.EmbeddedEncoder.(runtime.EncoderWithAllocator); supportsAllocator {
|
||||
if memoryAllocator == nil {
|
||||
// don't put the allocator inside the embeddedEncodeFn as that would allocate memory on every call.
|
||||
// instead, we allocate the buffer for the entire watch session and release it when we close the connection.
|
||||
memoryAllocator = runtime.AllocatorPool.Get().(*runtime.Allocator)
|
||||
defer runtime.AllocatorPool.Put(memoryAllocator)
|
||||
}
|
||||
embeddedEncodeFn = func(obj runtime.Object, w io.Writer) error {
|
||||
return encoder.EncodeWithAllocator(obj, w, memoryAllocator)
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-s.ServerShuttingDownCh:
|
||||
@ -257,42 +247,20 @@ func (s *WatchServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
metrics.WatchEvents.WithContext(req.Context()).WithLabelValues(kind.Group, kind.Version, kind.Kind).Inc()
|
||||
isWatchListLatencyRecordingRequired := shouldRecordWatchListLatency(event)
|
||||
|
||||
obj := s.Fixup(event.Object)
|
||||
if err := embeddedEncodeFn(obj, buf); err != nil {
|
||||
// unexpected error
|
||||
utilruntime.HandleError(fmt.Errorf("unable to encode watch object %T: %v", obj, err))
|
||||
return
|
||||
}
|
||||
|
||||
// ContentType is not required here because we are defaulting to the serializer
|
||||
// type
|
||||
unknown.Raw = buf.Bytes()
|
||||
event.Object = &unknown
|
||||
metrics.WatchEventsSizes.WithContext(req.Context()).WithLabelValues(kind.Group, kind.Version, kind.Kind).Observe(float64(len(unknown.Raw)))
|
||||
|
||||
*outEvent = metav1.WatchEvent{}
|
||||
|
||||
// create the external type directly and encode it. Clients will only recognize the serialization we provide.
|
||||
// The internal event is being reused, not reallocated so its just a few extra assignments to do it this way
|
||||
// and we get the benefit of using conversion functions which already have to stay in sync
|
||||
*internalEvent = metav1.InternalEvent(event)
|
||||
err := metav1.Convert_v1_InternalEvent_To_v1_WatchEvent(internalEvent, outEvent, nil)
|
||||
if err != nil {
|
||||
utilruntime.HandleError(fmt.Errorf("unable to convert watch object: %v", err))
|
||||
// client disconnect.
|
||||
return
|
||||
}
|
||||
if err := e.Encode(outEvent); err != nil {
|
||||
utilruntime.HandleError(fmt.Errorf("unable to encode watch object %T: %v (%#v)", outEvent, err, e))
|
||||
if err := watchEncoder.Encode(event); err != nil {
|
||||
utilruntime.HandleError(err)
|
||||
// client disconnect.
|
||||
return
|
||||
}
|
||||
|
||||
if len(ch) == 0 {
|
||||
flusher.Flush()
|
||||
}
|
||||
|
||||
buf.Reset()
|
||||
if isWatchListLatencyRecordingRequired {
|
||||
metrics.RecordWatchListLatency(req.Context(), s.Scope.Resource, s.metricsScope)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -326,10 +294,10 @@ func (s *WatchServer) HandleWS(ws *websocket.Conn) {
|
||||
// End of results.
|
||||
return
|
||||
}
|
||||
obj := s.Fixup(event.Object)
|
||||
if err := s.EmbeddedEncoder.Encode(obj, buf); err != nil {
|
||||
|
||||
if err := s.EmbeddedEncoder.Encode(event.Object, buf); err != nil {
|
||||
// unexpected error
|
||||
utilruntime.HandleError(fmt.Errorf("unable to encode watch object %T: %v", obj, err))
|
||||
utilruntime.HandleError(fmt.Errorf("unable to encode watch object %T: %v", event.Object, err))
|
||||
return
|
||||
}
|
||||
|
||||
@ -371,3 +339,19 @@ func (s *WatchServer) HandleWS(ws *websocket.Conn) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func shouldRecordWatchListLatency(event watch.Event) bool {
|
||||
if event.Type != watch.Bookmark || !utilfeature.DefaultFeatureGate.Enabled(features.WatchList) {
|
||||
return false
|
||||
}
|
||||
// as of today the initial-events-end annotation is added only to a single event
|
||||
// by the watch cache and only when certain conditions are met
|
||||
//
|
||||
// for more please read https://github.com/kubernetes/enhancements/tree/master/keps/sig-api-machinery/3157-watch-list
|
||||
hasAnnotation, err := storage.HasInitialEventsEndBookmarkAnnotation(event.Object)
|
||||
if err != nil {
|
||||
utilruntime.HandleError(fmt.Errorf("unable to determine if the obj has the required annotation for measuring watchlist latency, obj %T: %v", event.Object, err))
|
||||
return false
|
||||
}
|
||||
return hasAnnotation
|
||||
}
|
||||
|
Reference in New Issue
Block a user