mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 02:33:34 +00:00
rebase: update K8s packages to v0.32.1
Update K8s packages in go.mod to v0.32.1 Signed-off-by: Praveen M <m.praveen@ibm.com>
This commit is contained in:
159
vendor/k8s.io/client-go/rest/client.go
generated
vendored
159
vendor/k8s.io/client-go/rest/client.go
generated
vendored
@ -17,16 +17,21 @@ limitations under the License.
|
||||
package rest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/munnerz/goautoneg"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
clientfeatures "k8s.io/client-go/features"
|
||||
"k8s.io/client-go/util/flowcontrol"
|
||||
)
|
||||
|
||||
@ -85,7 +90,7 @@ type RESTClient struct {
|
||||
versionedAPIPath string
|
||||
|
||||
// content describes how a RESTClient encodes and decodes responses.
|
||||
content ClientContentConfig
|
||||
content requestClientContentConfigProvider
|
||||
|
||||
// creates BackoffManager that is passed to requests.
|
||||
createBackoffMgr func() BackoffManager
|
||||
@ -105,10 +110,6 @@ type RESTClient struct {
|
||||
// NewRESTClient creates a new RESTClient. This client performs generic REST functions
|
||||
// such as Get, Put, Post, and Delete on specified paths.
|
||||
func NewRESTClient(baseURL *url.URL, versionedAPIPath string, config ClientContentConfig, rateLimiter flowcontrol.RateLimiter, client *http.Client) (*RESTClient, error) {
|
||||
if len(config.ContentType) == 0 {
|
||||
config.ContentType = "application/json"
|
||||
}
|
||||
|
||||
base := *baseURL
|
||||
if !strings.HasSuffix(base.Path, "/") {
|
||||
base.Path += "/"
|
||||
@ -119,14 +120,53 @@ func NewRESTClient(baseURL *url.URL, versionedAPIPath string, config ClientConte
|
||||
return &RESTClient{
|
||||
base: &base,
|
||||
versionedAPIPath: versionedAPIPath,
|
||||
content: config,
|
||||
content: requestClientContentConfigProvider{base: scrubCBORContentConfigIfDisabled(config)},
|
||||
createBackoffMgr: readExpBackoffConfig,
|
||||
rateLimiter: rateLimiter,
|
||||
|
||||
Client: client,
|
||||
Client: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func scrubCBORContentConfigIfDisabled(content ClientContentConfig) ClientContentConfig {
|
||||
if clientfeatures.FeatureGates().Enabled(clientfeatures.ClientsAllowCBOR) {
|
||||
content.Negotiator = clientNegotiatorWithCBORSequenceStreamDecoder{content.Negotiator}
|
||||
return content
|
||||
}
|
||||
|
||||
if mediatype, _, err := mime.ParseMediaType(content.ContentType); err == nil && mediatype == "application/cbor" {
|
||||
content.ContentType = "application/json"
|
||||
}
|
||||
|
||||
clauses := goautoneg.ParseAccept(content.AcceptContentTypes)
|
||||
scrubbed := false
|
||||
for i, clause := range clauses {
|
||||
if clause.Type == "application" && clause.SubType == "cbor" {
|
||||
scrubbed = true
|
||||
clauses[i].SubType = "json"
|
||||
}
|
||||
}
|
||||
if !scrubbed {
|
||||
// No application/cbor in AcceptContentTypes, nothing more to do.
|
||||
return content
|
||||
}
|
||||
|
||||
parts := make([]string, 0, len(clauses))
|
||||
for _, clause := range clauses {
|
||||
// ParseAccept does not store the parameter "q" in Params.
|
||||
params := clause.Params
|
||||
if clause.Q < 1 { // omit q=1, it's the default
|
||||
if params == nil {
|
||||
params = make(map[string]string, 1)
|
||||
}
|
||||
params["q"] = strconv.FormatFloat(clause.Q, 'g', 3, 32)
|
||||
}
|
||||
parts = append(parts, mime.FormatMediaType(fmt.Sprintf("%s/%s", clause.Type, clause.SubType), params))
|
||||
}
|
||||
content.AcceptContentTypes = strings.Join(parts, ",")
|
||||
|
||||
return content
|
||||
}
|
||||
|
||||
// GetRateLimiter returns rate limiter for a given client, or nil if it's called on a nil client
|
||||
func (c *RESTClient) GetRateLimiter() flowcontrol.RateLimiter {
|
||||
if c == nil {
|
||||
@ -198,5 +238,106 @@ func (c *RESTClient) Delete() *Request {
|
||||
|
||||
// APIVersion returns the APIVersion this RESTClient is expected to use.
|
||||
func (c *RESTClient) APIVersion() schema.GroupVersion {
|
||||
return c.content.GroupVersion
|
||||
config, _ := c.content.GetClientContentConfig()
|
||||
return config.GroupVersion
|
||||
}
|
||||
|
||||
// requestClientContentConfigProvider observes HTTP 415 (Unsupported Media Type) responses to detect
|
||||
// that the server does not understand CBOR. Once this has happened, future requests are forced to
|
||||
// use JSON so they can succeed. This is convenient for client users that want to prefer CBOR, but
|
||||
// also need to interoperate with older servers so requests do not permanently fail. The clients
|
||||
// will not default to using CBOR until at least all supported kube-apiservers have enable-CBOR
|
||||
// locked to true, so this path will be rarely taken. Additionally, all generated clients accessing
|
||||
// built-in kube resources are forced to protobuf, so those will not degrade to JSON.
|
||||
type requestClientContentConfigProvider struct {
|
||||
base ClientContentConfig
|
||||
|
||||
// Becomes permanently true if a server responds with HTTP 415 (Unsupported Media Type) to a
|
||||
// request with "Content-Type" header containing the CBOR media type.
|
||||
sawUnsupportedMediaTypeForCBOR atomic.Bool
|
||||
}
|
||||
|
||||
// GetClientContentConfig returns the ClientContentConfig that should be used for new requests by
|
||||
// this client and true if the request ContentType was selected by default.
|
||||
func (p *requestClientContentConfigProvider) GetClientContentConfig() (ClientContentConfig, bool) {
|
||||
config := p.base
|
||||
|
||||
defaulted := config.ContentType == ""
|
||||
if defaulted {
|
||||
config.ContentType = "application/json"
|
||||
}
|
||||
|
||||
if !clientfeatures.FeatureGates().Enabled(clientfeatures.ClientsAllowCBOR) {
|
||||
return config, defaulted
|
||||
}
|
||||
|
||||
if defaulted && clientfeatures.FeatureGates().Enabled(clientfeatures.ClientsPreferCBOR) {
|
||||
config.ContentType = "application/cbor"
|
||||
}
|
||||
|
||||
if sawUnsupportedMediaTypeForCBOR := p.sawUnsupportedMediaTypeForCBOR.Load(); !sawUnsupportedMediaTypeForCBOR {
|
||||
return config, defaulted
|
||||
}
|
||||
|
||||
if mediaType, _, _ := mime.ParseMediaType(config.ContentType); mediaType != runtime.ContentTypeCBOR {
|
||||
return config, defaulted
|
||||
}
|
||||
|
||||
// The effective ContentType is CBOR and the client has previously received an HTTP 415 in
|
||||
// response to a CBOR request. Override ContentType to JSON.
|
||||
config.ContentType = runtime.ContentTypeJSON
|
||||
return config, defaulted
|
||||
}
|
||||
|
||||
// UnsupportedMediaType reports that the server has responded to a request with HTTP 415 Unsupported
|
||||
// Media Type.
|
||||
func (p *requestClientContentConfigProvider) UnsupportedMediaType(requestContentType string) {
|
||||
if !clientfeatures.FeatureGates().Enabled(clientfeatures.ClientsAllowCBOR) {
|
||||
return
|
||||
}
|
||||
|
||||
// This could be extended to consider the Content-Encoding request header, the Accept and
|
||||
// Accept-Encoding response headers, the request method, and URI (as mentioned in
|
||||
// https://www.rfc-editor.org/rfc/rfc9110.html#section-15.5.16). The request Content-Type
|
||||
// header is sufficient to implement a blanket CBOR fallback mechanism.
|
||||
requestContentType, _, _ = mime.ParseMediaType(requestContentType)
|
||||
switch requestContentType {
|
||||
case runtime.ContentTypeCBOR, string(types.ApplyCBORPatchType):
|
||||
p.sawUnsupportedMediaTypeForCBOR.Store(true)
|
||||
}
|
||||
}
|
||||
|
||||
// clientNegotiatorWithCBORSequenceStreamDecoder is a ClientNegotiator that delegates to another
|
||||
// ClientNegotiator to select the appropriate Encoder or Decoder for a given media type. As a
|
||||
// special case, it will resolve "application/cbor-seq" (a CBOR Sequence, the concatenation of zero
|
||||
// or more CBOR data items) as an alias for "application/cbor" (exactly one CBOR data item) when
|
||||
// selecting a stream decoder.
|
||||
type clientNegotiatorWithCBORSequenceStreamDecoder struct {
|
||||
negotiator runtime.ClientNegotiator
|
||||
}
|
||||
|
||||
func (n clientNegotiatorWithCBORSequenceStreamDecoder) Encoder(contentType string, params map[string]string) (runtime.Encoder, error) {
|
||||
return n.negotiator.Encoder(contentType, params)
|
||||
}
|
||||
|
||||
func (n clientNegotiatorWithCBORSequenceStreamDecoder) Decoder(contentType string, params map[string]string) (runtime.Decoder, error) {
|
||||
return n.negotiator.Decoder(contentType, params)
|
||||
}
|
||||
|
||||
func (n clientNegotiatorWithCBORSequenceStreamDecoder) StreamDecoder(contentType string, params map[string]string) (runtime.Decoder, runtime.Serializer, runtime.Framer, error) {
|
||||
if !clientfeatures.FeatureGates().Enabled(clientfeatures.ClientsAllowCBOR) {
|
||||
return n.negotiator.StreamDecoder(contentType, params)
|
||||
}
|
||||
|
||||
switch contentType {
|
||||
case runtime.ContentTypeCBORSequence:
|
||||
return n.negotiator.StreamDecoder(runtime.ContentTypeCBOR, params)
|
||||
case runtime.ContentTypeCBOR:
|
||||
// This media type is only appropriate for exactly one data item, not the zero or
|
||||
// more events of a watch stream.
|
||||
return nil, nil, nil, runtime.NegotiateError{ContentType: contentType, Stream: true}
|
||||
default:
|
||||
return n.negotiator.StreamDecoder(contentType, params)
|
||||
}
|
||||
|
||||
}
|
||||
|
22
vendor/k8s.io/client-go/rest/config.go
generated
vendored
22
vendor/k8s.io/client-go/rest/config.go
generated
vendored
@ -32,6 +32,9 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/cbor"
|
||||
"k8s.io/client-go/features"
|
||||
"k8s.io/client-go/pkg/version"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
"k8s.io/client-go/transport"
|
||||
@ -113,6 +116,9 @@ type Config struct {
|
||||
|
||||
// QPS indicates the maximum QPS to the master from this client.
|
||||
// If it's zero, the created RESTClient will use DefaultQPS: 5
|
||||
//
|
||||
// Setting this to a negative value will disable client-side ratelimiting
|
||||
// unless `Ratelimiter` is also set.
|
||||
QPS float32
|
||||
|
||||
// Maximum burst for throttle.
|
||||
@ -669,3 +675,19 @@ func CopyConfig(config *Config) *Config {
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// CodecFactoryForGeneratedClient returns the provided CodecFactory if there are no enabled client
|
||||
// feature gates affecting serialization. Otherwise, it constructs and returns a new CodecFactory
|
||||
// from the provided Scheme.
|
||||
//
|
||||
// This is supported ONLY for use by clients generated with client-gen. The caller is responsible
|
||||
// for ensuring that the CodecFactory argument was constructed using the Scheme argument.
|
||||
func CodecFactoryForGeneratedClient(scheme *runtime.Scheme, codecs serializer.CodecFactory) serializer.CodecFactory {
|
||||
if !features.FeatureGates().Enabled(features.ClientsAllowCBOR) {
|
||||
// NOTE: This assumes client-gen will not generate CBOR-enabled Codecs as long as
|
||||
// the feature gate exists.
|
||||
return codecs
|
||||
}
|
||||
|
||||
return serializer.NewCodecFactory(scheme, serializer.WithSerializer(cbor.NewSerializerInfo))
|
||||
}
|
||||
|
210
vendor/k8s.io/client-go/rest/request.go
generated
vendored
210
vendor/k8s.io/client-go/rest/request.go
generated
vendored
@ -19,6 +19,7 @@ package rest
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
@ -99,6 +100,9 @@ func defaultRequestRetryFn(maxRetries int) WithRetry {
|
||||
type Request struct {
|
||||
c *RESTClient
|
||||
|
||||
contentConfig ClientContentConfig
|
||||
contentTypeNotSet bool
|
||||
|
||||
warningHandler WarningHandler
|
||||
|
||||
rateLimiter flowcontrol.RateLimiter
|
||||
@ -123,7 +127,7 @@ type Request struct {
|
||||
// output
|
||||
err error
|
||||
|
||||
// only one of body / bodyBytes may be set. requests using body are not retriable.
|
||||
// only one of body / bodyBytes may be set. requests using body are not retryable.
|
||||
body io.Reader
|
||||
bodyBytes []byte
|
||||
|
||||
@ -152,6 +156,11 @@ func NewRequest(c *RESTClient) *Request {
|
||||
timeout = c.Client.Timeout
|
||||
}
|
||||
|
||||
// A request needs to know whether the content type was explicitly configured or selected by
|
||||
// default in order to support the per-request Protobuf override used by clients generated
|
||||
// with --prefers-protobuf.
|
||||
contentConfig, contentTypeDefaulted := c.content.GetClientContentConfig()
|
||||
|
||||
r := &Request{
|
||||
c: c,
|
||||
rateLimiter: c.rateLimiter,
|
||||
@ -161,14 +170,12 @@ func NewRequest(c *RESTClient) *Request {
|
||||
maxRetries: 10,
|
||||
retryFn: defaultRequestRetryFn,
|
||||
warningHandler: c.warningHandler,
|
||||
|
||||
contentConfig: contentConfig,
|
||||
contentTypeNotSet: contentTypeDefaulted,
|
||||
}
|
||||
|
||||
switch {
|
||||
case len(c.content.AcceptContentTypes) > 0:
|
||||
r.SetHeader("Accept", c.content.AcceptContentTypes)
|
||||
case len(c.content.ContentType) > 0:
|
||||
r.SetHeader("Accept", c.content.ContentType+", */*")
|
||||
}
|
||||
r.setAcceptHeader()
|
||||
return r
|
||||
}
|
||||
|
||||
@ -177,11 +184,36 @@ func NewRequestWithClient(base *url.URL, versionedAPIPath string, content Client
|
||||
return NewRequest(&RESTClient{
|
||||
base: base,
|
||||
versionedAPIPath: versionedAPIPath,
|
||||
content: content,
|
||||
content: requestClientContentConfigProvider{base: content},
|
||||
Client: client,
|
||||
})
|
||||
}
|
||||
|
||||
func (r *Request) UseProtobufAsDefaultIfPreferred(prefersProtobuf bool) *Request {
|
||||
if prefersProtobuf {
|
||||
return r.UseProtobufAsDefault()
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Request) UseProtobufAsDefault() *Request {
|
||||
if r.contentTypeNotSet && len(r.contentConfig.AcceptContentTypes) == 0 {
|
||||
r.contentConfig.AcceptContentTypes = "application/vnd.kubernetes.protobuf,application/json"
|
||||
r.contentConfig.ContentType = "application/vnd.kubernetes.protobuf"
|
||||
r.setAcceptHeader()
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Request) setAcceptHeader() {
|
||||
switch {
|
||||
case len(r.contentConfig.AcceptContentTypes) > 0:
|
||||
r.SetHeader("Accept", r.contentConfig.AcceptContentTypes)
|
||||
case len(r.contentConfig.ContentType) > 0:
|
||||
r.SetHeader("Accept", r.contentConfig.ContentType+", */*")
|
||||
}
|
||||
}
|
||||
|
||||
// Verb sets the verb this request will use.
|
||||
func (r *Request) Verb(verb string) *Request {
|
||||
r.verb = verb
|
||||
@ -370,7 +402,7 @@ func (r *Request) Param(paramName, s string) *Request {
|
||||
// VersionedParams will not write query parameters that have omitempty set and are empty. If a
|
||||
// parameter has already been set it is appended to (Params and VersionedParams are additive).
|
||||
func (r *Request) VersionedParams(obj runtime.Object, codec runtime.ParameterCodec) *Request {
|
||||
return r.SpecificallyVersionedParams(obj, codec, r.c.content.GroupVersion)
|
||||
return r.SpecificallyVersionedParams(obj, codec, r.contentConfig.GroupVersion)
|
||||
}
|
||||
|
||||
func (r *Request) SpecificallyVersionedParams(obj runtime.Object, codec runtime.ParameterCodec, version schema.GroupVersion) *Request {
|
||||
@ -450,11 +482,9 @@ func (r *Request) Body(obj interface{}) *Request {
|
||||
r.err = err
|
||||
return r
|
||||
}
|
||||
glogBody("Request Body", data)
|
||||
r.body = nil
|
||||
r.bodyBytes = data
|
||||
case []byte:
|
||||
glogBody("Request Body", t)
|
||||
r.body = nil
|
||||
r.bodyBytes = t
|
||||
case io.Reader:
|
||||
@ -465,7 +495,7 @@ func (r *Request) Body(obj interface{}) *Request {
|
||||
if reflect.ValueOf(t).IsNil() {
|
||||
return r
|
||||
}
|
||||
encoder, err := r.c.content.Negotiator.Encoder(r.c.content.ContentType, nil)
|
||||
encoder, err := r.contentConfig.Negotiator.Encoder(r.contentConfig.ContentType, nil)
|
||||
if err != nil {
|
||||
r.err = err
|
||||
return r
|
||||
@ -475,10 +505,9 @@ func (r *Request) Body(obj interface{}) *Request {
|
||||
r.err = err
|
||||
return r
|
||||
}
|
||||
glogBody("Request Body", data)
|
||||
r.body = nil
|
||||
r.bodyBytes = data
|
||||
r.SetHeader("Content-Type", r.c.content.ContentType)
|
||||
r.SetHeader("Content-Type", r.contentConfig.ContentType)
|
||||
default:
|
||||
r.err = fmt.Errorf("unknown type used for body: %+v", obj)
|
||||
}
|
||||
@ -704,10 +733,19 @@ func (b *throttledLogger) Infof(message string, args ...interface{}) {
|
||||
// Watch attempts to begin watching the requested location.
|
||||
// Returns a watch.Interface, or an error.
|
||||
func (r *Request) Watch(ctx context.Context) (watch.Interface, error) {
|
||||
w, _, e := r.watchInternal(ctx)
|
||||
return w, e
|
||||
}
|
||||
|
||||
func (r *Request) watchInternal(ctx context.Context) (watch.Interface, runtime.Decoder, error) {
|
||||
if r.body == nil {
|
||||
logBody(ctx, 2, "Request Body", r.bodyBytes)
|
||||
}
|
||||
|
||||
// We specifically don't want to rate limit watches, so we
|
||||
// don't use r.rateLimiter here.
|
||||
if r.err != nil {
|
||||
return nil, r.err
|
||||
return nil, nil, r.err
|
||||
}
|
||||
|
||||
client := r.c.Client
|
||||
@ -727,12 +765,12 @@ func (r *Request) Watch(ctx context.Context) (watch.Interface, error) {
|
||||
url := r.URL().String()
|
||||
for {
|
||||
if err := retry.Before(ctx, r); err != nil {
|
||||
return nil, retry.WrapPreviousError(err)
|
||||
return nil, nil, retry.WrapPreviousError(err)
|
||||
}
|
||||
|
||||
req, err := r.newHTTPRequest(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
@ -752,21 +790,22 @@ func (r *Request) Watch(ctx context.Context) (watch.Interface, error) {
|
||||
// the server must have sent us an error in 'err'
|
||||
return true, nil
|
||||
}
|
||||
if result := r.transformResponse(resp, req); result.err != nil {
|
||||
return true, result.err
|
||||
result := r.transformResponse(ctx, resp, req)
|
||||
if err := result.Error(); err != nil {
|
||||
return true, err
|
||||
}
|
||||
return true, fmt.Errorf("for request %s, got status: %v", url, resp.StatusCode)
|
||||
}()
|
||||
if done {
|
||||
if isErrRetryableFunc(req, err) {
|
||||
return watch.NewEmptyWatch(), nil
|
||||
return watch.NewEmptyWatch(), nil, nil
|
||||
}
|
||||
if err == nil {
|
||||
// if the server sent us an HTTP Response object,
|
||||
// we need to return the error object from that.
|
||||
err = transformErr
|
||||
}
|
||||
return nil, retry.WrapPreviousError(err)
|
||||
return nil, nil, retry.WrapPreviousError(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -784,22 +823,35 @@ type WatchListResult struct {
|
||||
// the end of the stream.
|
||||
initialEventsEndBookmarkRV string
|
||||
|
||||
// gv represents the API version
|
||||
// it is used to construct the final list response
|
||||
// normally this information is filled by the server
|
||||
gv schema.GroupVersion
|
||||
// negotiatedObjectDecoder knows how to decode
|
||||
// the initialEventsListBlueprint
|
||||
negotiatedObjectDecoder runtime.Decoder
|
||||
|
||||
// base64EncodedInitialEventsListBlueprint contains an empty,
|
||||
// versioned list encoded in the requested format
|
||||
// (e.g., protobuf, JSON, CBOR) and stored as a base64-encoded string
|
||||
base64EncodedInitialEventsListBlueprint string
|
||||
}
|
||||
|
||||
// Into stores the result into obj. The passed obj parameter must be a pointer to a list type.
|
||||
//
|
||||
// Note:
|
||||
//
|
||||
// Special attention should be given to the type *unstructured.Unstructured,
|
||||
// which represents a list type but does not have an "Items" field.
|
||||
// Users who directly use RESTClient may store the response in such an object.
|
||||
// This particular case is not handled by the current implementation of this function,
|
||||
// but may be considered for future updates.
|
||||
func (r WatchListResult) Into(obj runtime.Object) error {
|
||||
if r.err != nil {
|
||||
return r.err
|
||||
}
|
||||
|
||||
listPtr, err := meta.GetItemsPtr(obj)
|
||||
listItemsPtr, err := meta.GetItemsPtr(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
listVal, err := conversion.EnforcePtr(listPtr)
|
||||
listVal, err := conversion.EnforcePtr(listItemsPtr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -807,6 +859,16 @@ func (r WatchListResult) Into(obj runtime.Object) error {
|
||||
return fmt.Errorf("need a pointer to slice, got %v", listVal.Kind())
|
||||
}
|
||||
|
||||
encodedInitialEventsListBlueprint, err := base64.StdEncoding.DecodeString(r.base64EncodedInitialEventsListBlueprint)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode the received blueprint list, err %w", err)
|
||||
}
|
||||
|
||||
err = runtime.DecodeInto(r.negotiatedObjectDecoder, encodedInitialEventsListBlueprint, obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(r.items) == 0 {
|
||||
listVal.Set(reflect.MakeSlice(listVal.Type(), 0, 0))
|
||||
} else {
|
||||
@ -824,15 +886,6 @@ func (r WatchListResult) Into(obj runtime.Object) error {
|
||||
return err
|
||||
}
|
||||
listMeta.SetResourceVersion(r.initialEventsEndBookmarkRV)
|
||||
|
||||
typeMeta, err := meta.TypeAccessor(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
version := r.gv.String()
|
||||
typeMeta.SetAPIVersion(version)
|
||||
typeMeta.SetKind(reflect.TypeOf(obj).Elem().Name())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -844,6 +897,10 @@ func (r WatchListResult) Into(obj runtime.Object) error {
|
||||
// Check the documentation https://kubernetes.io/docs/reference/using-api/api-concepts/#streaming-lists
|
||||
// to see what parameters are currently required.
|
||||
func (r *Request) WatchList(ctx context.Context) WatchListResult {
|
||||
if r.body == nil {
|
||||
logBody(ctx, 2, "Request Body", r.bodyBytes)
|
||||
}
|
||||
|
||||
if !clientfeatures.FeatureGates().Enabled(clientfeatures.WatchListClient) {
|
||||
return WatchListResult{err: fmt.Errorf("%q feature gate is not enabled", clientfeatures.WatchListClient)}
|
||||
}
|
||||
@ -851,16 +908,16 @@ func (r *Request) WatchList(ctx context.Context) WatchListResult {
|
||||
// Most users use the generated client, which handles the proper setting of parameters.
|
||||
// We don't have validation for other methods (e.g., the Watch)
|
||||
// thus, for symmetry, we haven't added additional checks for the WatchList method.
|
||||
w, err := r.Watch(ctx)
|
||||
w, d, err := r.watchInternal(ctx)
|
||||
if err != nil {
|
||||
return WatchListResult{err: err}
|
||||
}
|
||||
return r.handleWatchList(ctx, w)
|
||||
return r.handleWatchList(ctx, w, d)
|
||||
}
|
||||
|
||||
// handleWatchList holds the actual logic for easier unit testing.
|
||||
// Note that this function will close the passed watch.
|
||||
func (r *Request) handleWatchList(ctx context.Context, w watch.Interface) WatchListResult {
|
||||
func (r *Request) handleWatchList(ctx context.Context, w watch.Interface, negotiatedObjectDecoder runtime.Decoder) WatchListResult {
|
||||
defer w.Stop()
|
||||
var lastKey string
|
||||
var items []runtime.Object
|
||||
@ -894,10 +951,15 @@ func (r *Request) handleWatchList(ctx context.Context, w watch.Interface) WatchL
|
||||
lastKey = key
|
||||
case watch.Bookmark:
|
||||
if meta.GetAnnotations()[metav1.InitialEventsAnnotationKey] == "true" {
|
||||
base64EncodedInitialEventsListBlueprint := meta.GetAnnotations()[metav1.InitialEventsListBlueprintAnnotationKey]
|
||||
if len(base64EncodedInitialEventsListBlueprint) == 0 {
|
||||
return WatchListResult{err: fmt.Errorf("%q annotation is missing content", metav1.InitialEventsListBlueprintAnnotationKey)}
|
||||
}
|
||||
return WatchListResult{
|
||||
items: items,
|
||||
initialEventsEndBookmarkRV: meta.GetResourceVersion(),
|
||||
gv: r.c.content.GroupVersion,
|
||||
items: items,
|
||||
initialEventsEndBookmarkRV: meta.GetResourceVersion(),
|
||||
negotiatedObjectDecoder: negotiatedObjectDecoder,
|
||||
base64EncodedInitialEventsListBlueprint: base64EncodedInitialEventsListBlueprint,
|
||||
}
|
||||
}
|
||||
default:
|
||||
@ -907,15 +969,15 @@ func (r *Request) handleWatchList(ctx context.Context, w watch.Interface) WatchL
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Request) newStreamWatcher(resp *http.Response) (watch.Interface, error) {
|
||||
func (r *Request) newStreamWatcher(resp *http.Response) (watch.Interface, runtime.Decoder, error) {
|
||||
contentType := resp.Header.Get("Content-Type")
|
||||
mediaType, params, err := mime.ParseMediaType(contentType)
|
||||
if err != nil {
|
||||
klog.V(4).Infof("Unexpected content type from the server: %q: %v", contentType, err)
|
||||
}
|
||||
objectDecoder, streamingSerializer, framer, err := r.c.content.Negotiator.StreamDecoder(mediaType, params)
|
||||
objectDecoder, streamingSerializer, framer, err := r.contentConfig.Negotiator.StreamDecoder(mediaType, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
handleWarnings(resp.Header, r.warningHandler)
|
||||
@ -928,7 +990,7 @@ func (r *Request) newStreamWatcher(resp *http.Response) (watch.Interface, error)
|
||||
// use 500 to indicate that the cause of the error is unknown - other error codes
|
||||
// are more specific to HTTP interactions, and set a reason
|
||||
errors.NewClientErrorReporter(http.StatusInternalServerError, r.verb, "ClientWatchDecoding"),
|
||||
), nil
|
||||
), objectDecoder, nil
|
||||
}
|
||||
|
||||
// updateRequestResultMetric increments the RequestResult metric counter,
|
||||
@ -968,6 +1030,10 @@ func sanitize(req *Request, resp *http.Response, err error) (string, string) {
|
||||
// Any non-2xx http status code causes an error. If we get a non-2xx code, we try to convert the body into an APIStatus object.
|
||||
// If we can, we return that as an error. Otherwise, we create an error that lists the http status and the content of the response.
|
||||
func (r *Request) Stream(ctx context.Context) (io.ReadCloser, error) {
|
||||
if r.body == nil {
|
||||
logBody(ctx, 2, "Request Body", r.bodyBytes)
|
||||
}
|
||||
|
||||
if r.err != nil {
|
||||
return nil, r.err
|
||||
}
|
||||
@ -1011,7 +1077,7 @@ func (r *Request) Stream(ctx context.Context) (io.ReadCloser, error) {
|
||||
if retry.IsNextRetry(ctx, r, req, resp, err, neverRetryError) {
|
||||
return false, nil
|
||||
}
|
||||
result := r.transformResponse(resp, req)
|
||||
result := r.transformResponse(ctx, resp, req)
|
||||
if err := result.Error(); err != nil {
|
||||
return true, err
|
||||
}
|
||||
@ -1143,7 +1209,7 @@ func (r *Request) request(ctx context.Context, fn func(*http.Request, *http.Resp
|
||||
return false
|
||||
}
|
||||
// For connection errors and apiserver shutdown errors retry.
|
||||
if net.IsConnectionReset(err) || net.IsProbableEOF(err) {
|
||||
if net.IsConnectionReset(err) || net.IsProbableEOF(err) || net.IsHTTP2ConnectionLost(err) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@ -1165,6 +1231,9 @@ func (r *Request) request(ctx context.Context, fn func(*http.Request, *http.Resp
|
||||
if req.ContentLength >= 0 && !(req.Body != nil && req.ContentLength == 0) {
|
||||
metrics.RequestSize.Observe(ctx, r.verb, r.URL().Host, float64(req.ContentLength))
|
||||
}
|
||||
if resp != nil && resp.StatusCode == http.StatusUnsupportedMediaType {
|
||||
r.c.content.UnsupportedMediaType(resp.Request.Header.Get("Content-Type"))
|
||||
}
|
||||
retry.After(ctx, r, resp, err)
|
||||
|
||||
done := func() bool {
|
||||
@ -1198,9 +1267,13 @@ func (r *Request) request(ctx context.Context, fn func(*http.Request, *http.Resp
|
||||
// - If the server responds with a status: *errors.StatusError or *errors.UnexpectedObjectError
|
||||
// - http.Client.Do errors are returned directly.
|
||||
func (r *Request) Do(ctx context.Context) Result {
|
||||
if r.body == nil {
|
||||
logBody(ctx, 2, "Request Body", r.bodyBytes)
|
||||
}
|
||||
|
||||
var result Result
|
||||
err := r.request(ctx, func(req *http.Request, resp *http.Response) {
|
||||
result = r.transformResponse(resp, req)
|
||||
result = r.transformResponse(ctx, resp, req)
|
||||
})
|
||||
if err != nil {
|
||||
return Result{err: err}
|
||||
@ -1213,10 +1286,14 @@ func (r *Request) Do(ctx context.Context) Result {
|
||||
|
||||
// DoRaw executes the request but does not process the response body.
|
||||
func (r *Request) DoRaw(ctx context.Context) ([]byte, error) {
|
||||
if r.body == nil {
|
||||
logBody(ctx, 2, "Request Body", r.bodyBytes)
|
||||
}
|
||||
|
||||
var result Result
|
||||
err := r.request(ctx, func(req *http.Request, resp *http.Response) {
|
||||
result.body, result.err = io.ReadAll(resp.Body)
|
||||
glogBody("Response Body", result.body)
|
||||
logBody(ctx, 2, "Response Body", result.body)
|
||||
if resp.StatusCode < http.StatusOK || resp.StatusCode > http.StatusPartialContent {
|
||||
result.err = r.transformUnstructuredResponseError(resp, req, result.body)
|
||||
}
|
||||
@ -1231,7 +1308,7 @@ func (r *Request) DoRaw(ctx context.Context) ([]byte, error) {
|
||||
}
|
||||
|
||||
// transformResponse converts an API response into a structured API object
|
||||
func (r *Request) transformResponse(resp *http.Response, req *http.Request) Result {
|
||||
func (r *Request) transformResponse(ctx context.Context, resp *http.Response, req *http.Request) Result {
|
||||
var body []byte
|
||||
if resp.Body != nil {
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
@ -1260,13 +1337,14 @@ func (r *Request) transformResponse(resp *http.Response, req *http.Request) Resu
|
||||
}
|
||||
}
|
||||
|
||||
glogBody("Response Body", body)
|
||||
// Call depth is tricky. This one is okay for Do and DoRaw.
|
||||
logBody(ctx, 7, "Response Body", body)
|
||||
|
||||
// verify the content type is accurate
|
||||
var decoder runtime.Decoder
|
||||
contentType := resp.Header.Get("Content-Type")
|
||||
if len(contentType) == 0 {
|
||||
contentType = r.c.content.ContentType
|
||||
contentType = r.contentConfig.ContentType
|
||||
}
|
||||
if len(contentType) > 0 {
|
||||
var err error
|
||||
@ -1274,7 +1352,7 @@ func (r *Request) transformResponse(resp *http.Response, req *http.Request) Resu
|
||||
if err != nil {
|
||||
return Result{err: errors.NewInternalError(err)}
|
||||
}
|
||||
decoder, err = r.c.content.Negotiator.Decoder(mediaType, params)
|
||||
decoder, err = r.contentConfig.Negotiator.Decoder(mediaType, params)
|
||||
if err != nil {
|
||||
// if we fail to negotiate a decoder, treat this as an unstructured error
|
||||
switch {
|
||||
@ -1320,14 +1398,14 @@ func (r *Request) transformResponse(resp *http.Response, req *http.Request) Resu
|
||||
}
|
||||
|
||||
// truncateBody decides if the body should be truncated, based on the glog Verbosity.
|
||||
func truncateBody(body string) string {
|
||||
func truncateBody(logger klog.Logger, body string) string {
|
||||
max := 0
|
||||
switch {
|
||||
case bool(klog.V(10).Enabled()):
|
||||
case bool(logger.V(10).Enabled()):
|
||||
return body
|
||||
case bool(klog.V(9).Enabled()):
|
||||
case bool(logger.V(9).Enabled()):
|
||||
max = 10240
|
||||
case bool(klog.V(8).Enabled()):
|
||||
case bool(logger.V(8).Enabled()):
|
||||
max = 1024
|
||||
}
|
||||
|
||||
@ -1338,17 +1416,21 @@ func truncateBody(body string) string {
|
||||
return body[:max] + fmt.Sprintf(" [truncated %d chars]", len(body)-max)
|
||||
}
|
||||
|
||||
// glogBody logs a body output that could be either JSON or protobuf. It explicitly guards against
|
||||
// logBody logs a body output that could be either JSON or protobuf. It explicitly guards against
|
||||
// allocating a new string for the body output unless necessary. Uses a simple heuristic to determine
|
||||
// whether the body is printable.
|
||||
func glogBody(prefix string, body []byte) {
|
||||
if klogV := klog.V(8); klogV.Enabled() {
|
||||
//
|
||||
// It needs to be called by all functions which send or receive the data.
|
||||
func logBody(ctx context.Context, callDepth int, prefix string, body []byte) {
|
||||
logger := klog.FromContext(ctx)
|
||||
if loggerV := logger.V(8); loggerV.Enabled() {
|
||||
loggerV := loggerV.WithCallDepth(callDepth)
|
||||
if bytes.IndexFunc(body, func(r rune) bool {
|
||||
return r < 0x0a
|
||||
}) != -1 {
|
||||
klogV.Infof("%s:\n%s", prefix, truncateBody(hex.Dump(body)))
|
||||
loggerV.Info(prefix, "body", truncateBody(logger, hex.Dump(body)))
|
||||
} else {
|
||||
klogV.Infof("%s: %s", prefix, truncateBody(string(body)))
|
||||
loggerV.Info(prefix, "body", truncateBody(logger, string(body)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1397,7 +1479,7 @@ func (r *Request) newUnstructuredResponseError(body []byte, isTextResponse bool,
|
||||
}
|
||||
var groupResource schema.GroupResource
|
||||
if len(r.resource) > 0 {
|
||||
groupResource.Group = r.c.content.GroupVersion.Group
|
||||
groupResource.Group = r.contentConfig.GroupVersion.Group
|
||||
groupResource.Resource = r.resource
|
||||
}
|
||||
return errors.NewGenericServerResponse(
|
||||
|
2
vendor/k8s.io/client-go/rest/url_utils.go
generated
vendored
2
vendor/k8s.io/client-go/rest/url_utils.go
generated
vendored
@ -61,7 +61,7 @@ func DefaultServerURL(host, apiPath string, groupVersion schema.GroupVersion, de
|
||||
return hostURL, versionedAPIPath, nil
|
||||
}
|
||||
|
||||
// DefaultVersionedAPIPathFor constructs the default path for the given group version, assuming the given
|
||||
// DefaultVersionedAPIPath constructs the default path for the given group version, assuming the given
|
||||
// API path, following the standard conventions of the Kubernetes API.
|
||||
func DefaultVersionedAPIPath(apiPath string, groupVersion schema.GroupVersion) string {
|
||||
versionedAPIPath := path.Join("/", apiPath)
|
||||
|
2
vendor/k8s.io/client-go/rest/watch/decoder.go
generated
vendored
2
vendor/k8s.io/client-go/rest/watch/decoder.go
generated
vendored
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package versioned
|
||||
package watch
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
2
vendor/k8s.io/client-go/rest/watch/encoder.go
generated
vendored
2
vendor/k8s.io/client-go/rest/watch/encoder.go
generated
vendored
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package versioned
|
||||
package watch
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
Reference in New Issue
Block a user