Update dependency go modules in client for k8s v1.26.0-rc.0
This commit is contained in:
14
client/vendor/k8s.io/client-go/rest/OWNERS
generated
vendored
Normal file
14
client/vendor/k8s.io/client-go/rest/OWNERS
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# See the OWNERS docs at https://go.k8s.io/owners
|
||||
|
||||
reviewers:
|
||||
- thockin
|
||||
- smarterclayton
|
||||
- caesarxuchao
|
||||
- wojtek-t
|
||||
- deads2k
|
||||
- liggitt
|
||||
- sttts
|
||||
- luxas
|
||||
- dims
|
||||
- cjcullen
|
||||
- lojies
|
203
client/vendor/k8s.io/client-go/rest/client.go
generated
vendored
Normal file
203
client/vendor/k8s.io/client-go/rest/client.go
generated
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
Copyright 2014 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 rest
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/util/flowcontrol"
|
||||
)
|
||||
|
||||
const (
|
||||
// Environment variables: Note that the duration should be long enough that the backoff
|
||||
// persists for some reasonable time (i.e. 120 seconds). The typical base might be "1".
|
||||
envBackoffBase = "KUBE_CLIENT_BACKOFF_BASE"
|
||||
envBackoffDuration = "KUBE_CLIENT_BACKOFF_DURATION"
|
||||
)
|
||||
|
||||
// Interface captures the set of operations for generically interacting with Kubernetes REST apis.
|
||||
type Interface interface {
|
||||
GetRateLimiter() flowcontrol.RateLimiter
|
||||
Verb(verb string) *Request
|
||||
Post() *Request
|
||||
Put() *Request
|
||||
Patch(pt types.PatchType) *Request
|
||||
Get() *Request
|
||||
Delete() *Request
|
||||
APIVersion() schema.GroupVersion
|
||||
}
|
||||
|
||||
// ClientContentConfig controls how RESTClient communicates with the server.
|
||||
//
|
||||
// TODO: ContentConfig will be updated to accept a Negotiator instead of a
|
||||
//
|
||||
// NegotiatedSerializer and NegotiatedSerializer will be removed.
|
||||
type ClientContentConfig struct {
|
||||
// AcceptContentTypes specifies the types the client will accept and is optional.
|
||||
// If not set, ContentType will be used to define the Accept header
|
||||
AcceptContentTypes string
|
||||
// ContentType specifies the wire format used to communicate with the server.
|
||||
// This value will be set as the Accept header on requests made to the server if
|
||||
// AcceptContentTypes is not set, and as the default content type on any object
|
||||
// sent to the server. If not set, "application/json" is used.
|
||||
ContentType string
|
||||
// GroupVersion is the API version to talk to. Must be provided when initializing
|
||||
// a RESTClient directly. When initializing a Client, will be set with the default
|
||||
// code version. This is used as the default group version for VersionedParams.
|
||||
GroupVersion schema.GroupVersion
|
||||
// Negotiator is used for obtaining encoders and decoders for multiple
|
||||
// supported media types.
|
||||
Negotiator runtime.ClientNegotiator
|
||||
}
|
||||
|
||||
// RESTClient imposes common Kubernetes API conventions on a set of resource paths.
|
||||
// The baseURL is expected to point to an HTTP or HTTPS path that is the parent
|
||||
// of one or more resources. The server should return a decodable API resource
|
||||
// object, or an api.Status object which contains information about the reason for
|
||||
// any failure.
|
||||
//
|
||||
// Most consumers should use client.New() to get a Kubernetes API client.
|
||||
type RESTClient struct {
|
||||
// base is the root URL for all invocations of the client
|
||||
base *url.URL
|
||||
// versionedAPIPath is a path segment connecting the base URL to the resource root
|
||||
versionedAPIPath string
|
||||
|
||||
// content describes how a RESTClient encodes and decodes responses.
|
||||
content ClientContentConfig
|
||||
|
||||
// creates BackoffManager that is passed to requests.
|
||||
createBackoffMgr func() BackoffManager
|
||||
|
||||
// rateLimiter is shared among all requests created by this client unless specifically
|
||||
// overridden.
|
||||
rateLimiter flowcontrol.RateLimiter
|
||||
|
||||
// warningHandler is shared among all requests created by this client.
|
||||
// If not set, defaultWarningHandler is used.
|
||||
warningHandler WarningHandler
|
||||
|
||||
// Set specific behavior of the client. If not set http.DefaultClient will be used.
|
||||
Client *http.Client
|
||||
}
|
||||
|
||||
// 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 += "/"
|
||||
}
|
||||
base.RawQuery = ""
|
||||
base.Fragment = ""
|
||||
|
||||
return &RESTClient{
|
||||
base: &base,
|
||||
versionedAPIPath: versionedAPIPath,
|
||||
content: config,
|
||||
createBackoffMgr: readExpBackoffConfig,
|
||||
rateLimiter: rateLimiter,
|
||||
|
||||
Client: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return nil
|
||||
}
|
||||
return c.rateLimiter
|
||||
}
|
||||
|
||||
// readExpBackoffConfig handles the internal logic of determining what the
|
||||
// backoff policy is. By default if no information is available, NoBackoff.
|
||||
// TODO Generalize this see #17727 .
|
||||
func readExpBackoffConfig() BackoffManager {
|
||||
backoffBase := os.Getenv(envBackoffBase)
|
||||
backoffDuration := os.Getenv(envBackoffDuration)
|
||||
|
||||
backoffBaseInt, errBase := strconv.ParseInt(backoffBase, 10, 64)
|
||||
backoffDurationInt, errDuration := strconv.ParseInt(backoffDuration, 10, 64)
|
||||
if errBase != nil || errDuration != nil {
|
||||
return &NoBackoff{}
|
||||
}
|
||||
return &URLBackoff{
|
||||
Backoff: flowcontrol.NewBackOff(
|
||||
time.Duration(backoffBaseInt)*time.Second,
|
||||
time.Duration(backoffDurationInt)*time.Second)}
|
||||
}
|
||||
|
||||
// Verb begins a request with a verb (GET, POST, PUT, DELETE).
|
||||
//
|
||||
// Example usage of RESTClient's request building interface:
|
||||
// c, err := NewRESTClient(...)
|
||||
// if err != nil { ... }
|
||||
// resp, err := c.Verb("GET").
|
||||
//
|
||||
// Path("pods").
|
||||
// SelectorParam("labels", "area=staging").
|
||||
// Timeout(10*time.Second).
|
||||
// Do()
|
||||
//
|
||||
// if err != nil { ... }
|
||||
// list, ok := resp.(*api.PodList)
|
||||
func (c *RESTClient) Verb(verb string) *Request {
|
||||
return NewRequest(c).Verb(verb)
|
||||
}
|
||||
|
||||
// Post begins a POST request. Short for c.Verb("POST").
|
||||
func (c *RESTClient) Post() *Request {
|
||||
return c.Verb("POST")
|
||||
}
|
||||
|
||||
// Put begins a PUT request. Short for c.Verb("PUT").
|
||||
func (c *RESTClient) Put() *Request {
|
||||
return c.Verb("PUT")
|
||||
}
|
||||
|
||||
// Patch begins a PATCH request. Short for c.Verb("Patch").
|
||||
func (c *RESTClient) Patch(pt types.PatchType) *Request {
|
||||
return c.Verb("PATCH").SetHeader("Content-Type", string(pt))
|
||||
}
|
||||
|
||||
// Get begins a GET request. Short for c.Verb("GET").
|
||||
func (c *RESTClient) Get() *Request {
|
||||
return c.Verb("GET")
|
||||
}
|
||||
|
||||
// Delete begins a DELETE request. Short for c.Verb("DELETE").
|
||||
func (c *RESTClient) Delete() *Request {
|
||||
return c.Verb("DELETE")
|
||||
}
|
||||
|
||||
// APIVersion returns the APIVersion this RESTClient is expected to use.
|
||||
func (c *RESTClient) APIVersion() schema.GroupVersion {
|
||||
return c.content.GroupVersion
|
||||
}
|
671
client/vendor/k8s.io/client-go/rest/config.go
generated
vendored
Normal file
671
client/vendor/k8s.io/client-go/rest/config.go
generated
vendored
Normal file
@@ -0,0 +1,671 @@
|
||||
/*
|
||||
Copyright 2016 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 rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
gruntime "runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/pkg/version"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
"k8s.io/client-go/transport"
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
"k8s.io/client-go/util/flowcontrol"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultQPS float32 = 5.0
|
||||
DefaultBurst int = 10
|
||||
)
|
||||
|
||||
var ErrNotInCluster = errors.New("unable to load in-cluster configuration, KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT must be defined")
|
||||
|
||||
// Config holds the common attributes that can be passed to a Kubernetes client on
|
||||
// initialization.
|
||||
type Config struct {
|
||||
// Host must be a host string, a host:port pair, or a URL to the base of the apiserver.
|
||||
// If a URL is given then the (optional) Path of that URL represents a prefix that must
|
||||
// be appended to all request URIs used to access the apiserver. This allows a frontend
|
||||
// proxy to easily relocate all of the apiserver endpoints.
|
||||
Host string
|
||||
// APIPath is a sub-path that points to an API root.
|
||||
APIPath string
|
||||
|
||||
// ContentConfig contains settings that affect how objects are transformed when
|
||||
// sent to the server.
|
||||
ContentConfig
|
||||
|
||||
// Server requires Basic authentication
|
||||
Username string
|
||||
Password string `datapolicy:"password"`
|
||||
|
||||
// Server requires Bearer authentication. This client will not attempt to use
|
||||
// refresh tokens for an OAuth2 flow.
|
||||
// TODO: demonstrate an OAuth2 compatible client.
|
||||
BearerToken string `datapolicy:"token"`
|
||||
|
||||
// Path to a file containing a BearerToken.
|
||||
// If set, the contents are periodically read.
|
||||
// The last successfully read value takes precedence over BearerToken.
|
||||
BearerTokenFile string
|
||||
|
||||
// Impersonate is the configuration that RESTClient will use for impersonation.
|
||||
Impersonate ImpersonationConfig
|
||||
|
||||
// Server requires plugin-specified authentication.
|
||||
AuthProvider *clientcmdapi.AuthProviderConfig
|
||||
|
||||
// Callback to persist config for AuthProvider.
|
||||
AuthConfigPersister AuthProviderConfigPersister
|
||||
|
||||
// Exec-based authentication provider.
|
||||
ExecProvider *clientcmdapi.ExecConfig
|
||||
|
||||
// TLSClientConfig contains settings to enable transport layer security
|
||||
TLSClientConfig
|
||||
|
||||
// UserAgent is an optional field that specifies the caller of this request.
|
||||
UserAgent string
|
||||
|
||||
// DisableCompression bypasses automatic GZip compression requests to the
|
||||
// server.
|
||||
DisableCompression bool
|
||||
|
||||
// Transport may be used for custom HTTP behavior. This attribute may not
|
||||
// be specified with the TLS client certificate options. Use WrapTransport
|
||||
// to provide additional per-server middleware behavior.
|
||||
Transport http.RoundTripper
|
||||
// WrapTransport will be invoked for custom HTTP behavior after the underlying
|
||||
// transport is initialized (either the transport created from TLSClientConfig,
|
||||
// Transport, or http.DefaultTransport). The config may layer other RoundTrippers
|
||||
// on top of the returned RoundTripper.
|
||||
//
|
||||
// A future release will change this field to an array. Use config.Wrap()
|
||||
// instead of setting this value directly.
|
||||
WrapTransport transport.WrapperFunc
|
||||
|
||||
// QPS indicates the maximum QPS to the master from this client.
|
||||
// If it's zero, the created RESTClient will use DefaultQPS: 5
|
||||
QPS float32
|
||||
|
||||
// Maximum burst for throttle.
|
||||
// If it's zero, the created RESTClient will use DefaultBurst: 10.
|
||||
Burst int
|
||||
|
||||
// Rate limiter for limiting connections to the master from this client. If present overwrites QPS/Burst
|
||||
RateLimiter flowcontrol.RateLimiter
|
||||
|
||||
// WarningHandler handles warnings in server responses.
|
||||
// If not set, the default warning handler is used.
|
||||
// See documentation for SetDefaultWarningHandler() for details.
|
||||
WarningHandler WarningHandler
|
||||
|
||||
// The maximum length of time to wait before giving up on a server request. A value of zero means no timeout.
|
||||
Timeout time.Duration
|
||||
|
||||
// Dial specifies the dial function for creating unencrypted TCP connections.
|
||||
Dial func(ctx context.Context, network, address string) (net.Conn, error)
|
||||
|
||||
// Proxy is the proxy func to be used for all requests made by this
|
||||
// transport. If Proxy is nil, http.ProxyFromEnvironment is used. If Proxy
|
||||
// returns a nil *URL, no proxy is used.
|
||||
//
|
||||
// socks5 proxying does not currently support spdy streaming endpoints.
|
||||
Proxy func(*http.Request) (*url.URL, error)
|
||||
|
||||
// Version forces a specific version to be used (if registered)
|
||||
// Do we need this?
|
||||
// Version string
|
||||
}
|
||||
|
||||
var _ fmt.Stringer = new(Config)
|
||||
var _ fmt.GoStringer = new(Config)
|
||||
|
||||
type sanitizedConfig *Config
|
||||
|
||||
type sanitizedAuthConfigPersister struct{ AuthProviderConfigPersister }
|
||||
|
||||
func (sanitizedAuthConfigPersister) GoString() string {
|
||||
return "rest.AuthProviderConfigPersister(--- REDACTED ---)"
|
||||
}
|
||||
func (sanitizedAuthConfigPersister) String() string {
|
||||
return "rest.AuthProviderConfigPersister(--- REDACTED ---)"
|
||||
}
|
||||
|
||||
type sanitizedObject struct{ runtime.Object }
|
||||
|
||||
func (sanitizedObject) GoString() string {
|
||||
return "runtime.Object(--- REDACTED ---)"
|
||||
}
|
||||
func (sanitizedObject) String() string {
|
||||
return "runtime.Object(--- REDACTED ---)"
|
||||
}
|
||||
|
||||
// GoString implements fmt.GoStringer and sanitizes sensitive fields of Config
|
||||
// to prevent accidental leaking via logs.
|
||||
func (c *Config) GoString() string {
|
||||
return c.String()
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer and sanitizes sensitive fields of Config to
|
||||
// prevent accidental leaking via logs.
|
||||
func (c *Config) String() string {
|
||||
if c == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
cc := sanitizedConfig(CopyConfig(c))
|
||||
// Explicitly mark non-empty credential fields as redacted.
|
||||
if cc.Password != "" {
|
||||
cc.Password = "--- REDACTED ---"
|
||||
}
|
||||
if cc.BearerToken != "" {
|
||||
cc.BearerToken = "--- REDACTED ---"
|
||||
}
|
||||
if cc.AuthConfigPersister != nil {
|
||||
cc.AuthConfigPersister = sanitizedAuthConfigPersister{cc.AuthConfigPersister}
|
||||
}
|
||||
if cc.ExecProvider != nil && cc.ExecProvider.Config != nil {
|
||||
cc.ExecProvider.Config = sanitizedObject{Object: cc.ExecProvider.Config}
|
||||
}
|
||||
return fmt.Sprintf("%#v", cc)
|
||||
}
|
||||
|
||||
// ImpersonationConfig has all the available impersonation options
|
||||
type ImpersonationConfig struct {
|
||||
// UserName is the username to impersonate on each request.
|
||||
UserName string
|
||||
// UID is a unique value that identifies the user.
|
||||
UID string
|
||||
// Groups are the groups to impersonate on each request.
|
||||
Groups []string
|
||||
// Extra is a free-form field which can be used to link some authentication information
|
||||
// to authorization information. This field allows you to impersonate it.
|
||||
Extra map[string][]string
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
// TLSClientConfig contains settings to enable transport layer security
|
||||
type TLSClientConfig struct {
|
||||
// Server should be accessed without verifying the TLS certificate. For testing only.
|
||||
Insecure bool
|
||||
// ServerName is passed to the server for SNI and is used in the client to check server
|
||||
// certificates against. If ServerName is empty, the hostname used to contact the
|
||||
// server is used.
|
||||
ServerName string
|
||||
|
||||
// Server requires TLS client certificate authentication
|
||||
CertFile string
|
||||
// Server requires TLS client certificate authentication
|
||||
KeyFile string
|
||||
// Trusted root certificates for server
|
||||
CAFile string
|
||||
|
||||
// CertData holds PEM-encoded bytes (typically read from a client certificate file).
|
||||
// CertData takes precedence over CertFile
|
||||
CertData []byte
|
||||
// KeyData holds PEM-encoded bytes (typically read from a client certificate key file).
|
||||
// KeyData takes precedence over KeyFile
|
||||
KeyData []byte `datapolicy:"security-key"`
|
||||
// CAData holds PEM-encoded bytes (typically read from a root certificates bundle).
|
||||
// CAData takes precedence over CAFile
|
||||
CAData []byte
|
||||
|
||||
// NextProtos is a list of supported application level protocols, in order of preference.
|
||||
// Used to populate tls.Config.NextProtos.
|
||||
// To indicate to the server http/1.1 is preferred over http/2, set to ["http/1.1", "h2"] (though the server is free to ignore that preference).
|
||||
// To use only http/1.1, set to ["http/1.1"].
|
||||
NextProtos []string
|
||||
}
|
||||
|
||||
var _ fmt.Stringer = TLSClientConfig{}
|
||||
var _ fmt.GoStringer = TLSClientConfig{}
|
||||
|
||||
type sanitizedTLSClientConfig TLSClientConfig
|
||||
|
||||
// GoString implements fmt.GoStringer and sanitizes sensitive fields of
|
||||
// TLSClientConfig to prevent accidental leaking via logs.
|
||||
func (c TLSClientConfig) GoString() string {
|
||||
return c.String()
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer and sanitizes sensitive fields of
|
||||
// TLSClientConfig to prevent accidental leaking via logs.
|
||||
func (c TLSClientConfig) String() string {
|
||||
cc := sanitizedTLSClientConfig{
|
||||
Insecure: c.Insecure,
|
||||
ServerName: c.ServerName,
|
||||
CertFile: c.CertFile,
|
||||
KeyFile: c.KeyFile,
|
||||
CAFile: c.CAFile,
|
||||
CertData: c.CertData,
|
||||
KeyData: c.KeyData,
|
||||
CAData: c.CAData,
|
||||
NextProtos: c.NextProtos,
|
||||
}
|
||||
// Explicitly mark non-empty credential fields as redacted.
|
||||
if len(cc.CertData) != 0 {
|
||||
cc.CertData = []byte("--- TRUNCATED ---")
|
||||
}
|
||||
if len(cc.KeyData) != 0 {
|
||||
cc.KeyData = []byte("--- REDACTED ---")
|
||||
}
|
||||
return fmt.Sprintf("%#v", cc)
|
||||
}
|
||||
|
||||
type ContentConfig struct {
|
||||
// AcceptContentTypes specifies the types the client will accept and is optional.
|
||||
// If not set, ContentType will be used to define the Accept header
|
||||
AcceptContentTypes string
|
||||
// ContentType specifies the wire format used to communicate with the server.
|
||||
// This value will be set as the Accept header on requests made to the server, and
|
||||
// as the default content type on any object sent to the server. If not set,
|
||||
// "application/json" is used.
|
||||
ContentType string
|
||||
// GroupVersion is the API version to talk to. Must be provided when initializing
|
||||
// a RESTClient directly. When initializing a Client, will be set with the default
|
||||
// code version.
|
||||
GroupVersion *schema.GroupVersion
|
||||
// NegotiatedSerializer is used for obtaining encoders and decoders for multiple
|
||||
// supported media types.
|
||||
//
|
||||
// TODO: NegotiatedSerializer will be phased out as internal clients are removed
|
||||
// from Kubernetes.
|
||||
NegotiatedSerializer runtime.NegotiatedSerializer
|
||||
}
|
||||
|
||||
// RESTClientFor returns a RESTClient that satisfies the requested attributes on a client Config
|
||||
// object. Note that a RESTClient may require fields that are optional when initializing a Client.
|
||||
// A RESTClient created by this method is generic - it expects to operate on an API that follows
|
||||
// the Kubernetes conventions, but may not be the Kubernetes API.
|
||||
// RESTClientFor is equivalent to calling RESTClientForConfigAndClient(config, httpClient),
|
||||
// where httpClient was generated with HTTPClientFor(config).
|
||||
func RESTClientFor(config *Config) (*RESTClient, error) {
|
||||
if config.GroupVersion == nil {
|
||||
return nil, fmt.Errorf("GroupVersion is required when initializing a RESTClient")
|
||||
}
|
||||
if config.NegotiatedSerializer == nil {
|
||||
return nil, fmt.Errorf("NegotiatedSerializer is required when initializing a RESTClient")
|
||||
}
|
||||
|
||||
// Validate config.Host before constructing the transport/client so we can fail fast.
|
||||
// ServerURL will be obtained later in RESTClientForConfigAndClient()
|
||||
_, _, err := defaultServerUrlFor(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
httpClient, err := HTTPClientFor(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return RESTClientForConfigAndClient(config, httpClient)
|
||||
}
|
||||
|
||||
// RESTClientForConfigAndClient returns a RESTClient that satisfies the requested attributes on a
|
||||
// client Config object.
|
||||
// Unlike RESTClientFor, RESTClientForConfigAndClient allows to pass an http.Client that is shared
|
||||
// between all the API Groups and Versions.
|
||||
// Note that the http client takes precedence over the transport values configured.
|
||||
// The http client defaults to the `http.DefaultClient` if nil.
|
||||
func RESTClientForConfigAndClient(config *Config, httpClient *http.Client) (*RESTClient, error) {
|
||||
if config.GroupVersion == nil {
|
||||
return nil, fmt.Errorf("GroupVersion is required when initializing a RESTClient")
|
||||
}
|
||||
if config.NegotiatedSerializer == nil {
|
||||
return nil, fmt.Errorf("NegotiatedSerializer is required when initializing a RESTClient")
|
||||
}
|
||||
|
||||
baseURL, versionedAPIPath, err := defaultServerUrlFor(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rateLimiter := config.RateLimiter
|
||||
if rateLimiter == nil {
|
||||
qps := config.QPS
|
||||
if config.QPS == 0.0 {
|
||||
qps = DefaultQPS
|
||||
}
|
||||
burst := config.Burst
|
||||
if config.Burst == 0 {
|
||||
burst = DefaultBurst
|
||||
}
|
||||
if qps > 0 {
|
||||
rateLimiter = flowcontrol.NewTokenBucketRateLimiter(qps, burst)
|
||||
}
|
||||
}
|
||||
|
||||
var gv schema.GroupVersion
|
||||
if config.GroupVersion != nil {
|
||||
gv = *config.GroupVersion
|
||||
}
|
||||
clientContent := ClientContentConfig{
|
||||
AcceptContentTypes: config.AcceptContentTypes,
|
||||
ContentType: config.ContentType,
|
||||
GroupVersion: gv,
|
||||
Negotiator: runtime.NewClientNegotiator(config.NegotiatedSerializer, gv),
|
||||
}
|
||||
|
||||
restClient, err := NewRESTClient(baseURL, versionedAPIPath, clientContent, rateLimiter, httpClient)
|
||||
if err == nil && config.WarningHandler != nil {
|
||||
restClient.warningHandler = config.WarningHandler
|
||||
}
|
||||
return restClient, err
|
||||
}
|
||||
|
||||
// UnversionedRESTClientFor is the same as RESTClientFor, except that it allows
|
||||
// the config.Version to be empty.
|
||||
func UnversionedRESTClientFor(config *Config) (*RESTClient, error) {
|
||||
if config.NegotiatedSerializer == nil {
|
||||
return nil, fmt.Errorf("NegotiatedSerializer is required when initializing a RESTClient")
|
||||
}
|
||||
|
||||
// Validate config.Host before constructing the transport/client so we can fail fast.
|
||||
// ServerURL will be obtained later in UnversionedRESTClientForConfigAndClient()
|
||||
_, _, err := defaultServerUrlFor(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
httpClient, err := HTTPClientFor(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return UnversionedRESTClientForConfigAndClient(config, httpClient)
|
||||
}
|
||||
|
||||
// UnversionedRESTClientForConfigAndClient is the same as RESTClientForConfigAndClient,
|
||||
// except that it allows the config.Version to be empty.
|
||||
func UnversionedRESTClientForConfigAndClient(config *Config, httpClient *http.Client) (*RESTClient, error) {
|
||||
if config.NegotiatedSerializer == nil {
|
||||
return nil, fmt.Errorf("NegotiatedSerializer is required when initializing a RESTClient")
|
||||
}
|
||||
|
||||
baseURL, versionedAPIPath, err := defaultServerUrlFor(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rateLimiter := config.RateLimiter
|
||||
if rateLimiter == nil {
|
||||
qps := config.QPS
|
||||
if config.QPS == 0.0 {
|
||||
qps = DefaultQPS
|
||||
}
|
||||
burst := config.Burst
|
||||
if config.Burst == 0 {
|
||||
burst = DefaultBurst
|
||||
}
|
||||
if qps > 0 {
|
||||
rateLimiter = flowcontrol.NewTokenBucketRateLimiter(qps, burst)
|
||||
}
|
||||
}
|
||||
|
||||
gv := metav1.SchemeGroupVersion
|
||||
if config.GroupVersion != nil {
|
||||
gv = *config.GroupVersion
|
||||
}
|
||||
clientContent := ClientContentConfig{
|
||||
AcceptContentTypes: config.AcceptContentTypes,
|
||||
ContentType: config.ContentType,
|
||||
GroupVersion: gv,
|
||||
Negotiator: runtime.NewClientNegotiator(config.NegotiatedSerializer, gv),
|
||||
}
|
||||
|
||||
restClient, err := NewRESTClient(baseURL, versionedAPIPath, clientContent, rateLimiter, httpClient)
|
||||
if err == nil && config.WarningHandler != nil {
|
||||
restClient.warningHandler = config.WarningHandler
|
||||
}
|
||||
return restClient, err
|
||||
}
|
||||
|
||||
// SetKubernetesDefaults sets default values on the provided client config for accessing the
|
||||
// Kubernetes API or returns an error if any of the defaults are impossible or invalid.
|
||||
func SetKubernetesDefaults(config *Config) error {
|
||||
if len(config.UserAgent) == 0 {
|
||||
config.UserAgent = DefaultKubernetesUserAgent()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// adjustCommit returns sufficient significant figures of the commit's git hash.
|
||||
func adjustCommit(c string) string {
|
||||
if len(c) == 0 {
|
||||
return "unknown"
|
||||
}
|
||||
if len(c) > 7 {
|
||||
return c[:7]
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// adjustVersion strips "alpha", "beta", etc. from version in form
|
||||
// major.minor.patch-[alpha|beta|etc].
|
||||
func adjustVersion(v string) string {
|
||||
if len(v) == 0 {
|
||||
return "unknown"
|
||||
}
|
||||
seg := strings.SplitN(v, "-", 2)
|
||||
return seg[0]
|
||||
}
|
||||
|
||||
// adjustCommand returns the last component of the
|
||||
// OS-specific command path for use in User-Agent.
|
||||
func adjustCommand(p string) string {
|
||||
// Unlikely, but better than returning "".
|
||||
if len(p) == 0 {
|
||||
return "unknown"
|
||||
}
|
||||
return filepath.Base(p)
|
||||
}
|
||||
|
||||
// buildUserAgent builds a User-Agent string from given args.
|
||||
func buildUserAgent(command, version, os, arch, commit string) string {
|
||||
return fmt.Sprintf(
|
||||
"%s/%s (%s/%s) kubernetes/%s", command, version, os, arch, commit)
|
||||
}
|
||||
|
||||
// DefaultKubernetesUserAgent returns a User-Agent string built from static global vars.
|
||||
func DefaultKubernetesUserAgent() string {
|
||||
return buildUserAgent(
|
||||
adjustCommand(os.Args[0]),
|
||||
adjustVersion(version.Get().GitVersion),
|
||||
gruntime.GOOS,
|
||||
gruntime.GOARCH,
|
||||
adjustCommit(version.Get().GitCommit))
|
||||
}
|
||||
|
||||
// InClusterConfig returns a config object which uses the service account
|
||||
// kubernetes gives to pods. It's intended for clients that expect to be
|
||||
// running inside a pod running on kubernetes. It will return ErrNotInCluster
|
||||
// if called from a process not running in a kubernetes environment.
|
||||
func InClusterConfig() (*Config, error) {
|
||||
const (
|
||||
tokenFile = "/var/run/secrets/kubernetes.io/serviceaccount/token"
|
||||
rootCAFile = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
|
||||
)
|
||||
host, port := os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT")
|
||||
if len(host) == 0 || len(port) == 0 {
|
||||
return nil, ErrNotInCluster
|
||||
}
|
||||
|
||||
token, err := os.ReadFile(tokenFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tlsClientConfig := TLSClientConfig{}
|
||||
|
||||
if _, err := certutil.NewPool(rootCAFile); err != nil {
|
||||
klog.Errorf("Expected to load root CA config from %s, but got err: %v", rootCAFile, err)
|
||||
} else {
|
||||
tlsClientConfig.CAFile = rootCAFile
|
||||
}
|
||||
|
||||
return &Config{
|
||||
// TODO: switch to using cluster DNS.
|
||||
Host: "https://" + net.JoinHostPort(host, port),
|
||||
TLSClientConfig: tlsClientConfig,
|
||||
BearerToken: string(token),
|
||||
BearerTokenFile: tokenFile,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// IsConfigTransportTLS returns true if and only if the provided
|
||||
// config will result in a protected connection to the server when it
|
||||
// is passed to restclient.RESTClientFor(). Use to determine when to
|
||||
// send credentials over the wire.
|
||||
//
|
||||
// Note: the Insecure flag is ignored when testing for this value, so MITM attacks are
|
||||
// still possible.
|
||||
func IsConfigTransportTLS(config Config) bool {
|
||||
baseURL, _, err := defaultServerUrlFor(&config)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return baseURL.Scheme == "https"
|
||||
}
|
||||
|
||||
// LoadTLSFiles copies the data from the CertFile, KeyFile, and CAFile fields into the CertData,
|
||||
// KeyData, and CAFile fields, or returns an error. If no error is returned, all three fields are
|
||||
// either populated or were empty to start.
|
||||
func LoadTLSFiles(c *Config) error {
|
||||
var err error
|
||||
c.CAData, err = dataFromSliceOrFile(c.CAData, c.CAFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.CertData, err = dataFromSliceOrFile(c.CertData, c.CertFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.KeyData, err = dataFromSliceOrFile(c.KeyData, c.KeyFile)
|
||||
return err
|
||||
}
|
||||
|
||||
// dataFromSliceOrFile returns data from the slice (if non-empty), or from the file,
|
||||
// or an error if an error occurred reading the file
|
||||
func dataFromSliceOrFile(data []byte, file string) ([]byte, error) {
|
||||
if len(data) > 0 {
|
||||
return data, nil
|
||||
}
|
||||
if len(file) > 0 {
|
||||
fileData, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
return fileData, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func AddUserAgent(config *Config, userAgent string) *Config {
|
||||
fullUserAgent := DefaultKubernetesUserAgent() + "/" + userAgent
|
||||
config.UserAgent = fullUserAgent
|
||||
return config
|
||||
}
|
||||
|
||||
// AnonymousClientConfig returns a copy of the given config with all user credentials (cert/key, bearer token, and username/password) and custom transports (WrapTransport, Transport) removed
|
||||
func AnonymousClientConfig(config *Config) *Config {
|
||||
// copy only known safe fields
|
||||
return &Config{
|
||||
Host: config.Host,
|
||||
APIPath: config.APIPath,
|
||||
ContentConfig: config.ContentConfig,
|
||||
TLSClientConfig: TLSClientConfig{
|
||||
Insecure: config.Insecure,
|
||||
ServerName: config.ServerName,
|
||||
CAFile: config.TLSClientConfig.CAFile,
|
||||
CAData: config.TLSClientConfig.CAData,
|
||||
NextProtos: config.TLSClientConfig.NextProtos,
|
||||
},
|
||||
RateLimiter: config.RateLimiter,
|
||||
WarningHandler: config.WarningHandler,
|
||||
UserAgent: config.UserAgent,
|
||||
DisableCompression: config.DisableCompression,
|
||||
QPS: config.QPS,
|
||||
Burst: config.Burst,
|
||||
Timeout: config.Timeout,
|
||||
Dial: config.Dial,
|
||||
Proxy: config.Proxy,
|
||||
}
|
||||
}
|
||||
|
||||
// CopyConfig returns a copy of the given config
|
||||
func CopyConfig(config *Config) *Config {
|
||||
c := &Config{
|
||||
Host: config.Host,
|
||||
APIPath: config.APIPath,
|
||||
ContentConfig: config.ContentConfig,
|
||||
Username: config.Username,
|
||||
Password: config.Password,
|
||||
BearerToken: config.BearerToken,
|
||||
BearerTokenFile: config.BearerTokenFile,
|
||||
Impersonate: ImpersonationConfig{
|
||||
UserName: config.Impersonate.UserName,
|
||||
UID: config.Impersonate.UID,
|
||||
Groups: config.Impersonate.Groups,
|
||||
Extra: config.Impersonate.Extra,
|
||||
},
|
||||
AuthProvider: config.AuthProvider,
|
||||
AuthConfigPersister: config.AuthConfigPersister,
|
||||
ExecProvider: config.ExecProvider,
|
||||
TLSClientConfig: TLSClientConfig{
|
||||
Insecure: config.TLSClientConfig.Insecure,
|
||||
ServerName: config.TLSClientConfig.ServerName,
|
||||
CertFile: config.TLSClientConfig.CertFile,
|
||||
KeyFile: config.TLSClientConfig.KeyFile,
|
||||
CAFile: config.TLSClientConfig.CAFile,
|
||||
CertData: config.TLSClientConfig.CertData,
|
||||
KeyData: config.TLSClientConfig.KeyData,
|
||||
CAData: config.TLSClientConfig.CAData,
|
||||
NextProtos: config.TLSClientConfig.NextProtos,
|
||||
},
|
||||
UserAgent: config.UserAgent,
|
||||
DisableCompression: config.DisableCompression,
|
||||
Transport: config.Transport,
|
||||
WrapTransport: config.WrapTransport,
|
||||
QPS: config.QPS,
|
||||
Burst: config.Burst,
|
||||
RateLimiter: config.RateLimiter,
|
||||
WarningHandler: config.WarningHandler,
|
||||
Timeout: config.Timeout,
|
||||
Dial: config.Dial,
|
||||
Proxy: config.Proxy,
|
||||
}
|
||||
if config.ExecProvider != nil && config.ExecProvider.Config != nil {
|
||||
c.ExecProvider.Config = config.ExecProvider.Config.DeepCopyObject()
|
||||
}
|
||||
return c
|
||||
}
|
86
client/vendor/k8s.io/client-go/rest/exec.go
generated
vendored
Normal file
86
client/vendor/k8s.io/client-go/rest/exec.go
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
Copyright 2020 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 rest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
clientauthenticationapi "k8s.io/client-go/pkg/apis/clientauthentication"
|
||||
)
|
||||
|
||||
// This file contains Config logic related to exec credential plugins.
|
||||
|
||||
// ConfigToExecCluster creates a clientauthenticationapi.Cluster with the corresponding fields from
|
||||
// the provided Config.
|
||||
func ConfigToExecCluster(config *Config) (*clientauthenticationapi.Cluster, error) {
|
||||
caData, err := dataFromSliceOrFile(config.CAData, config.CAFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load CA bundle for execProvider: %v", err)
|
||||
}
|
||||
|
||||
var proxyURL string
|
||||
if config.Proxy != nil {
|
||||
req, err := http.NewRequest("", config.Host, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create proxy URL request for execProvider: %w", err)
|
||||
}
|
||||
url, err := config.Proxy(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get proxy URL for execProvider: %w", err)
|
||||
}
|
||||
if url != nil {
|
||||
proxyURL = url.String()
|
||||
}
|
||||
}
|
||||
|
||||
return &clientauthenticationapi.Cluster{
|
||||
Server: config.Host,
|
||||
TLSServerName: config.ServerName,
|
||||
InsecureSkipTLSVerify: config.Insecure,
|
||||
CertificateAuthorityData: caData,
|
||||
ProxyURL: proxyURL,
|
||||
DisableCompression: config.DisableCompression,
|
||||
Config: config.ExecProvider.Config,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ExecClusterToConfig creates a Config with the corresponding fields from the provided
|
||||
// clientauthenticationapi.Cluster. The returned Config will be anonymous (i.e., it will not have
|
||||
// any authentication-related fields set).
|
||||
func ExecClusterToConfig(cluster *clientauthenticationapi.Cluster) (*Config, error) {
|
||||
var proxy func(*http.Request) (*url.URL, error)
|
||||
if cluster.ProxyURL != "" {
|
||||
proxyURL, err := url.Parse(cluster.ProxyURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse proxy URL: %w", err)
|
||||
}
|
||||
proxy = http.ProxyURL(proxyURL)
|
||||
}
|
||||
|
||||
return &Config{
|
||||
Host: cluster.Server,
|
||||
TLSClientConfig: TLSClientConfig{
|
||||
Insecure: cluster.InsecureSkipTLSVerify,
|
||||
ServerName: cluster.TLSServerName,
|
||||
CAData: cluster.CertificateAuthorityData,
|
||||
},
|
||||
Proxy: proxy,
|
||||
DisableCompression: cluster.DisableCompression,
|
||||
}, nil
|
||||
}
|
84
client/vendor/k8s.io/client-go/rest/plugin.go
generated
vendored
Normal file
84
client/vendor/k8s.io/client-go/rest/plugin.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
Copyright 2016 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 rest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
)
|
||||
|
||||
type AuthProvider interface {
|
||||
// WrapTransport allows the plugin to create a modified RoundTripper that
|
||||
// attaches authorization headers (or other info) to requests.
|
||||
WrapTransport(http.RoundTripper) http.RoundTripper
|
||||
// Login allows the plugin to initialize its configuration. It must not
|
||||
// require direct user interaction.
|
||||
Login() error
|
||||
}
|
||||
|
||||
// Factory generates an AuthProvider plugin.
|
||||
//
|
||||
// clusterAddress is the address of the current cluster.
|
||||
// config is the initial configuration for this plugin.
|
||||
// persister allows the plugin to save updated configuration.
|
||||
type Factory func(clusterAddress string, config map[string]string, persister AuthProviderConfigPersister) (AuthProvider, error)
|
||||
|
||||
// AuthProviderConfigPersister allows a plugin to persist configuration info
|
||||
// for just itself.
|
||||
type AuthProviderConfigPersister interface {
|
||||
Persist(map[string]string) error
|
||||
}
|
||||
|
||||
type noopPersister struct{}
|
||||
|
||||
func (n *noopPersister) Persist(_ map[string]string) error {
|
||||
// no operation persister
|
||||
return nil
|
||||
}
|
||||
|
||||
// All registered auth provider plugins.
|
||||
var pluginsLock sync.Mutex
|
||||
var plugins = make(map[string]Factory)
|
||||
|
||||
func RegisterAuthProviderPlugin(name string, plugin Factory) error {
|
||||
pluginsLock.Lock()
|
||||
defer pluginsLock.Unlock()
|
||||
if _, found := plugins[name]; found {
|
||||
return fmt.Errorf("auth Provider Plugin %q was registered twice", name)
|
||||
}
|
||||
klog.V(4).Infof("Registered Auth Provider Plugin %q", name)
|
||||
plugins[name] = plugin
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetAuthProvider(clusterAddress string, apc *clientcmdapi.AuthProviderConfig, persister AuthProviderConfigPersister) (AuthProvider, error) {
|
||||
pluginsLock.Lock()
|
||||
defer pluginsLock.Unlock()
|
||||
p, ok := plugins[apc.Name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no Auth Provider found for name %q", apc.Name)
|
||||
}
|
||||
if persister == nil {
|
||||
persister = &noopPersister{}
|
||||
}
|
||||
return p(clusterAddress, apc.Config, persister)
|
||||
}
|
1414
client/vendor/k8s.io/client-go/rest/request.go
generated
vendored
Normal file
1414
client/vendor/k8s.io/client-go/rest/request.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
155
client/vendor/k8s.io/client-go/rest/transport.go
generated
vendored
Normal file
155
client/vendor/k8s.io/client-go/rest/transport.go
generated
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
Copyright 2014 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 rest
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"k8s.io/client-go/pkg/apis/clientauthentication"
|
||||
"k8s.io/client-go/plugin/pkg/client/auth/exec"
|
||||
"k8s.io/client-go/transport"
|
||||
)
|
||||
|
||||
// HTTPClientFor returns an http.Client that will provide the authentication
|
||||
// or transport level security defined by the provided Config. Will return the
|
||||
// default http.DefaultClient if no special case behavior is needed.
|
||||
func HTTPClientFor(config *Config) (*http.Client, error) {
|
||||
transport, err := TransportFor(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var httpClient *http.Client
|
||||
if transport != http.DefaultTransport || config.Timeout > 0 {
|
||||
httpClient = &http.Client{
|
||||
Transport: transport,
|
||||
Timeout: config.Timeout,
|
||||
}
|
||||
} else {
|
||||
httpClient = http.DefaultClient
|
||||
}
|
||||
|
||||
return httpClient, nil
|
||||
}
|
||||
|
||||
// TLSConfigFor returns a tls.Config that will provide the transport level security defined
|
||||
// by the provided Config. Will return nil if no transport level security is requested.
|
||||
func TLSConfigFor(config *Config) (*tls.Config, error) {
|
||||
cfg, err := config.TransportConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transport.TLSConfigFor(cfg)
|
||||
}
|
||||
|
||||
// TransportFor returns an http.RoundTripper that will provide the authentication
|
||||
// or transport level security defined by the provided Config. Will return the
|
||||
// default http.DefaultTransport if no special case behavior is needed.
|
||||
func TransportFor(config *Config) (http.RoundTripper, error) {
|
||||
cfg, err := config.TransportConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transport.New(cfg)
|
||||
}
|
||||
|
||||
// HTTPWrappersForConfig wraps a round tripper with any relevant layered behavior from the
|
||||
// config. Exposed to allow more clients that need HTTP-like behavior but then must hijack
|
||||
// the underlying connection (like WebSocket or HTTP2 clients). Pure HTTP clients should use
|
||||
// the higher level TransportFor or RESTClientFor methods.
|
||||
func HTTPWrappersForConfig(config *Config, rt http.RoundTripper) (http.RoundTripper, error) {
|
||||
cfg, err := config.TransportConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transport.HTTPWrappersForConfig(cfg, rt)
|
||||
}
|
||||
|
||||
// TransportConfig converts a client config to an appropriate transport config.
|
||||
func (c *Config) TransportConfig() (*transport.Config, error) {
|
||||
conf := &transport.Config{
|
||||
UserAgent: c.UserAgent,
|
||||
Transport: c.Transport,
|
||||
WrapTransport: c.WrapTransport,
|
||||
DisableCompression: c.DisableCompression,
|
||||
TLS: transport.TLSConfig{
|
||||
Insecure: c.Insecure,
|
||||
ServerName: c.ServerName,
|
||||
CAFile: c.CAFile,
|
||||
CAData: c.CAData,
|
||||
CertFile: c.CertFile,
|
||||
CertData: c.CertData,
|
||||
KeyFile: c.KeyFile,
|
||||
KeyData: c.KeyData,
|
||||
NextProtos: c.NextProtos,
|
||||
},
|
||||
Username: c.Username,
|
||||
Password: c.Password,
|
||||
BearerToken: c.BearerToken,
|
||||
BearerTokenFile: c.BearerTokenFile,
|
||||
Impersonate: transport.ImpersonationConfig{
|
||||
UserName: c.Impersonate.UserName,
|
||||
UID: c.Impersonate.UID,
|
||||
Groups: c.Impersonate.Groups,
|
||||
Extra: c.Impersonate.Extra,
|
||||
},
|
||||
Proxy: c.Proxy,
|
||||
}
|
||||
|
||||
if c.Dial != nil {
|
||||
conf.DialHolder = &transport.DialHolder{Dial: c.Dial}
|
||||
}
|
||||
|
||||
if c.ExecProvider != nil && c.AuthProvider != nil {
|
||||
return nil, errors.New("execProvider and authProvider cannot be used in combination")
|
||||
}
|
||||
|
||||
if c.ExecProvider != nil {
|
||||
var cluster *clientauthentication.Cluster
|
||||
if c.ExecProvider.ProvideClusterInfo {
|
||||
var err error
|
||||
cluster, err = ConfigToExecCluster(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
provider, err := exec.GetAuthenticator(c.ExecProvider, cluster)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := provider.UpdateTransportConfig(conf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if c.AuthProvider != nil {
|
||||
provider, err := GetAuthProvider(c.Host, c.AuthProvider, c.AuthConfigPersister)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conf.Wrap(provider.WrapTransport)
|
||||
}
|
||||
return conf, nil
|
||||
}
|
||||
|
||||
// Wrap adds a transport middleware function that will give the caller
|
||||
// an opportunity to wrap the underlying http.RoundTripper prior to the
|
||||
// first API call being made. The provided function is invoked after any
|
||||
// existing transport wrappers are invoked.
|
||||
func (c *Config) Wrap(fn transport.WrapperFunc) {
|
||||
c.WrapTransport = transport.Wrappers(c.WrapTransport, fn)
|
||||
}
|
97
client/vendor/k8s.io/client-go/rest/url_utils.go
generated
vendored
Normal file
97
client/vendor/k8s.io/client-go/rest/url_utils.go
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
Copyright 2016 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 rest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"path"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// DefaultServerURL converts a host, host:port, or URL string to the default base server API path
|
||||
// to use with a Client at a given API version following the standard conventions for a
|
||||
// Kubernetes API.
|
||||
func DefaultServerURL(host, apiPath string, groupVersion schema.GroupVersion, defaultTLS bool) (*url.URL, string, error) {
|
||||
if host == "" {
|
||||
return nil, "", fmt.Errorf("host must be a URL or a host:port pair")
|
||||
}
|
||||
base := host
|
||||
hostURL, err := url.Parse(base)
|
||||
if err != nil || hostURL.Scheme == "" || hostURL.Host == "" {
|
||||
scheme := "http://"
|
||||
if defaultTLS {
|
||||
scheme = "https://"
|
||||
}
|
||||
hostURL, err = url.Parse(scheme + base)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if hostURL.Path != "" && hostURL.Path != "/" {
|
||||
return nil, "", fmt.Errorf("host must be a URL or a host:port pair: %q", base)
|
||||
}
|
||||
}
|
||||
|
||||
// hostURL.Path is optional; a non-empty Path is treated as a prefix that is to be applied to
|
||||
// all URIs used to access the host. this is useful when there's a proxy in front of the
|
||||
// apiserver that has relocated the apiserver endpoints, forwarding all requests from, for
|
||||
// example, /a/b/c to the apiserver. in this case the Path should be /a/b/c.
|
||||
//
|
||||
// if running without a frontend proxy (that changes the location of the apiserver), then
|
||||
// hostURL.Path should be blank.
|
||||
//
|
||||
// versionedAPIPath, a path relative to baseURL.Path, points to a versioned API base
|
||||
versionedAPIPath := DefaultVersionedAPIPath(apiPath, groupVersion)
|
||||
|
||||
return hostURL, versionedAPIPath, nil
|
||||
}
|
||||
|
||||
// DefaultVersionedAPIPathFor 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)
|
||||
|
||||
// Add the version to the end of the path
|
||||
if len(groupVersion.Group) > 0 {
|
||||
versionedAPIPath = path.Join(versionedAPIPath, groupVersion.Group, groupVersion.Version)
|
||||
|
||||
} else {
|
||||
versionedAPIPath = path.Join(versionedAPIPath, groupVersion.Version)
|
||||
}
|
||||
|
||||
return versionedAPIPath
|
||||
}
|
||||
|
||||
// defaultServerUrlFor is shared between IsConfigTransportTLS and RESTClientFor. It
|
||||
// requires Host and Version to be set prior to being called.
|
||||
func defaultServerUrlFor(config *Config) (*url.URL, string, error) {
|
||||
// TODO: move the default to secure when the apiserver supports TLS by default
|
||||
// config.Insecure is taken to mean "I want HTTPS but don't bother checking the certs against a CA."
|
||||
hasCA := len(config.CAFile) != 0 || len(config.CAData) != 0
|
||||
hasCert := len(config.CertFile) != 0 || len(config.CertData) != 0
|
||||
defaultTLS := hasCA || hasCert || config.Insecure
|
||||
host := config.Host
|
||||
if host == "" {
|
||||
host = "localhost"
|
||||
}
|
||||
|
||||
if config.GroupVersion != nil {
|
||||
return DefaultServerURL(host, config.APIPath, *config.GroupVersion, defaultTLS)
|
||||
}
|
||||
return DefaultServerURL(host, config.APIPath, schema.GroupVersion{}, defaultTLS)
|
||||
}
|
107
client/vendor/k8s.io/client-go/rest/urlbackoff.go
generated
vendored
Normal file
107
client/vendor/k8s.io/client-go/rest/urlbackoff.go
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
Copyright 2015 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 rest
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/client-go/util/flowcontrol"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// Set of resp. Codes that we backoff for.
|
||||
// In general these should be errors that indicate a server is overloaded.
|
||||
// These shouldn't be configured by any user, we set them based on conventions
|
||||
// described in
|
||||
var serverIsOverloadedSet = sets.NewInt(429)
|
||||
var maxResponseCode = 499
|
||||
|
||||
type BackoffManager interface {
|
||||
UpdateBackoff(actualUrl *url.URL, err error, responseCode int)
|
||||
CalculateBackoff(actualUrl *url.URL) time.Duration
|
||||
Sleep(d time.Duration)
|
||||
}
|
||||
|
||||
// URLBackoff struct implements the semantics on top of Backoff which
|
||||
// we need for URL specific exponential backoff.
|
||||
type URLBackoff struct {
|
||||
// Uses backoff as underlying implementation.
|
||||
Backoff *flowcontrol.Backoff
|
||||
}
|
||||
|
||||
// NoBackoff is a stub implementation, can be used for mocking or else as a default.
|
||||
type NoBackoff struct {
|
||||
}
|
||||
|
||||
func (n *NoBackoff) UpdateBackoff(actualUrl *url.URL, err error, responseCode int) {
|
||||
// do nothing.
|
||||
}
|
||||
|
||||
func (n *NoBackoff) CalculateBackoff(actualUrl *url.URL) time.Duration {
|
||||
return 0 * time.Second
|
||||
}
|
||||
|
||||
func (n *NoBackoff) Sleep(d time.Duration) {
|
||||
time.Sleep(d)
|
||||
}
|
||||
|
||||
// Disable makes the backoff trivial, i.e., sets it to zero. This might be used
|
||||
// by tests which want to run 1000s of mock requests without slowing down.
|
||||
func (b *URLBackoff) Disable() {
|
||||
klog.V(4).Infof("Disabling backoff strategy")
|
||||
b.Backoff = flowcontrol.NewBackOff(0*time.Second, 0*time.Second)
|
||||
}
|
||||
|
||||
// baseUrlKey returns the key which urls will be mapped to.
|
||||
// For example, 127.0.0.1:8080/api/v2/abcde -> 127.0.0.1:8080.
|
||||
func (b *URLBackoff) baseUrlKey(rawurl *url.URL) string {
|
||||
// Simple implementation for now, just the host.
|
||||
// We may backoff specific paths (i.e. "pods") differentially
|
||||
// in the future.
|
||||
host, err := url.Parse(rawurl.String())
|
||||
if err != nil {
|
||||
klog.V(4).Infof("Error extracting url: %v", rawurl)
|
||||
panic("bad url!")
|
||||
}
|
||||
return host.Host
|
||||
}
|
||||
|
||||
// UpdateBackoff updates backoff metadata
|
||||
func (b *URLBackoff) UpdateBackoff(actualUrl *url.URL, err error, responseCode int) {
|
||||
// range for retry counts that we store is [0,13]
|
||||
if responseCode > maxResponseCode || serverIsOverloadedSet.Has(responseCode) {
|
||||
b.Backoff.Next(b.baseUrlKey(actualUrl), b.Backoff.Clock.Now())
|
||||
return
|
||||
} else if responseCode >= 300 || err != nil {
|
||||
klog.V(4).Infof("Client is returning errors: code %v, error %v", responseCode, err)
|
||||
}
|
||||
|
||||
//If we got this far, there is no backoff required for this URL anymore.
|
||||
b.Backoff.Reset(b.baseUrlKey(actualUrl))
|
||||
}
|
||||
|
||||
// CalculateBackoff takes a url and back's off exponentially,
|
||||
// based on its knowledge of existing failures.
|
||||
func (b *URLBackoff) CalculateBackoff(actualUrl *url.URL) time.Duration {
|
||||
return b.Backoff.Get(b.baseUrlKey(actualUrl))
|
||||
}
|
||||
|
||||
func (b *URLBackoff) Sleep(d time.Duration) {
|
||||
b.Backoff.Clock.Sleep(d)
|
||||
}
|
147
client/vendor/k8s.io/client-go/rest/warnings.go
generated
vendored
Normal file
147
client/vendor/k8s.io/client-go/rest/warnings.go
generated
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
Copyright 2020 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 rest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/net"
|
||||
)
|
||||
|
||||
// WarningHandler is an interface for handling warning headers
|
||||
type WarningHandler interface {
|
||||
// HandleWarningHeader is called with the warn code, agent, and text when a warning header is countered.
|
||||
HandleWarningHeader(code int, agent string, text string)
|
||||
}
|
||||
|
||||
var (
|
||||
defaultWarningHandler WarningHandler = WarningLogger{}
|
||||
defaultWarningHandlerLock sync.RWMutex
|
||||
)
|
||||
|
||||
// SetDefaultWarningHandler sets the default handler clients use when warning headers are encountered.
|
||||
// By default, warnings are logged. Several built-in implementations are provided:
|
||||
// - NoWarnings suppresses warnings.
|
||||
// - WarningLogger logs warnings.
|
||||
// - NewWarningWriter() outputs warnings to the provided writer.
|
||||
func SetDefaultWarningHandler(l WarningHandler) {
|
||||
defaultWarningHandlerLock.Lock()
|
||||
defer defaultWarningHandlerLock.Unlock()
|
||||
defaultWarningHandler = l
|
||||
}
|
||||
func getDefaultWarningHandler() WarningHandler {
|
||||
defaultWarningHandlerLock.RLock()
|
||||
defer defaultWarningHandlerLock.RUnlock()
|
||||
l := defaultWarningHandler
|
||||
return l
|
||||
}
|
||||
|
||||
// NoWarnings is an implementation of WarningHandler that suppresses warnings.
|
||||
type NoWarnings struct{}
|
||||
|
||||
func (NoWarnings) HandleWarningHeader(code int, agent string, message string) {}
|
||||
|
||||
// WarningLogger is an implementation of WarningHandler that logs code 299 warnings
|
||||
type WarningLogger struct{}
|
||||
|
||||
func (WarningLogger) HandleWarningHeader(code int, agent string, message string) {
|
||||
if code != 299 || len(message) == 0 {
|
||||
return
|
||||
}
|
||||
klog.Warning(message)
|
||||
}
|
||||
|
||||
type warningWriter struct {
|
||||
// out is the writer to output warnings to
|
||||
out io.Writer
|
||||
// opts contains options controlling warning output
|
||||
opts WarningWriterOptions
|
||||
// writtenLock guards written and writtenCount
|
||||
writtenLock sync.Mutex
|
||||
writtenCount int
|
||||
written map[string]struct{}
|
||||
}
|
||||
|
||||
// WarningWriterOptions controls the behavior of a WarningHandler constructed using NewWarningWriter()
|
||||
type WarningWriterOptions struct {
|
||||
// Deduplicate indicates a given warning message should only be written once.
|
||||
// Setting this to true in a long-running process handling many warnings can result in increased memory use.
|
||||
Deduplicate bool
|
||||
// Color indicates that warning output can include ANSI color codes
|
||||
Color bool
|
||||
}
|
||||
|
||||
// NewWarningWriter returns an implementation of WarningHandler that outputs code 299 warnings to the specified writer.
|
||||
func NewWarningWriter(out io.Writer, opts WarningWriterOptions) *warningWriter {
|
||||
h := &warningWriter{out: out, opts: opts}
|
||||
if opts.Deduplicate {
|
||||
h.written = map[string]struct{}{}
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
const (
|
||||
yellowColor = "\u001b[33;1m"
|
||||
resetColor = "\u001b[0m"
|
||||
)
|
||||
|
||||
// HandleWarningHeader prints warnings with code=299 to the configured writer.
|
||||
func (w *warningWriter) HandleWarningHeader(code int, agent string, message string) {
|
||||
if code != 299 || len(message) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
w.writtenLock.Lock()
|
||||
defer w.writtenLock.Unlock()
|
||||
|
||||
if w.opts.Deduplicate {
|
||||
if _, alreadyWritten := w.written[message]; alreadyWritten {
|
||||
return
|
||||
}
|
||||
w.written[message] = struct{}{}
|
||||
}
|
||||
w.writtenCount++
|
||||
|
||||
if w.opts.Color {
|
||||
fmt.Fprintf(w.out, "%sWarning:%s %s\n", yellowColor, resetColor, message)
|
||||
} else {
|
||||
fmt.Fprintf(w.out, "Warning: %s\n", message)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *warningWriter) WarningCount() int {
|
||||
w.writtenLock.Lock()
|
||||
defer w.writtenLock.Unlock()
|
||||
return w.writtenCount
|
||||
}
|
||||
|
||||
func handleWarnings(headers http.Header, handler WarningHandler) []net.WarningHeader {
|
||||
if handler == nil {
|
||||
handler = getDefaultWarningHandler()
|
||||
}
|
||||
|
||||
warnings, _ := net.ParseWarningHeaders(headers["Warning"])
|
||||
for _, warning := range warnings {
|
||||
handler.HandleWarningHeader(warning.Code, warning.Agent, warning.Text)
|
||||
}
|
||||
return warnings
|
||||
}
|
72
client/vendor/k8s.io/client-go/rest/watch/decoder.go
generated
vendored
Normal file
72
client/vendor/k8s.io/client-go/rest/watch/decoder.go
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
Copyright 2014 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 versioned
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
)
|
||||
|
||||
// Decoder implements the watch.Decoder interface for io.ReadClosers that
|
||||
// have contents which consist of a series of watchEvent objects encoded
|
||||
// with the given streaming decoder. The internal objects will be then
|
||||
// decoded by the embedded decoder.
|
||||
type Decoder struct {
|
||||
decoder streaming.Decoder
|
||||
embeddedDecoder runtime.Decoder
|
||||
}
|
||||
|
||||
// NewDecoder creates an Decoder for the given writer and codec.
|
||||
func NewDecoder(decoder streaming.Decoder, embeddedDecoder runtime.Decoder) *Decoder {
|
||||
return &Decoder{
|
||||
decoder: decoder,
|
||||
embeddedDecoder: embeddedDecoder,
|
||||
}
|
||||
}
|
||||
|
||||
// Decode blocks until it can return the next object in the reader. Returns an error
|
||||
// if the reader is closed or an object can't be decoded.
|
||||
func (d *Decoder) Decode() (watch.EventType, runtime.Object, error) {
|
||||
var got metav1.WatchEvent
|
||||
res, _, err := d.decoder.Decode(nil, &got)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if res != &got {
|
||||
return "", nil, fmt.Errorf("unable to decode to metav1.Event")
|
||||
}
|
||||
switch got.Type {
|
||||
case string(watch.Added), string(watch.Modified), string(watch.Deleted), string(watch.Error), string(watch.Bookmark):
|
||||
default:
|
||||
return "", nil, fmt.Errorf("got invalid watch event type: %v", got.Type)
|
||||
}
|
||||
|
||||
obj, err := runtime.Decode(d.embeddedDecoder, got.Object.Raw)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("unable to decode watch event: %v", err)
|
||||
}
|
||||
return watch.EventType(got.Type), obj, nil
|
||||
}
|
||||
|
||||
// Close closes the underlying r.
|
||||
func (d *Decoder) Close() {
|
||||
d.decoder.Close()
|
||||
}
|
56
client/vendor/k8s.io/client-go/rest/watch/encoder.go
generated
vendored
Normal file
56
client/vendor/k8s.io/client-go/rest/watch/encoder.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
Copyright 2014 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 versioned
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
)
|
||||
|
||||
// Encoder serializes watch.Events into io.Writer. The internal objects
|
||||
// are encoded using embedded encoder, and the outer Event is serialized
|
||||
// using encoder.
|
||||
// TODO: this type is only used by tests
|
||||
type Encoder struct {
|
||||
encoder streaming.Encoder
|
||||
embeddedEncoder runtime.Encoder
|
||||
}
|
||||
|
||||
func NewEncoder(encoder streaming.Encoder, embeddedEncoder runtime.Encoder) *Encoder {
|
||||
return &Encoder{
|
||||
encoder: encoder,
|
||||
embeddedEncoder: embeddedEncoder,
|
||||
}
|
||||
}
|
||||
|
||||
// Encode writes an event to the writer. Returns an error
|
||||
// if the writer is closed or an object can't be encoded.
|
||||
func (e *Encoder) Encode(event *watch.Event) error {
|
||||
data, err := runtime.Encode(e.embeddedEncoder, event.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// FIXME: get rid of json.RawMessage.
|
||||
return e.encoder.Encode(&metav1.WatchEvent{
|
||||
Type: string(event.Type),
|
||||
Object: runtime.RawExtension{Raw: json.RawMessage(data)},
|
||||
})
|
||||
}
|
360
client/vendor/k8s.io/client-go/rest/with_retry.go
generated
vendored
Normal file
360
client/vendor/k8s.io/client-go/rest/with_retry.go
generated
vendored
Normal file
@@ -0,0 +1,360 @@
|
||||
/*
|
||||
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 rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// IsRetryableErrorFunc allows the client to provide its own function
|
||||
// that determines whether the specified err from the server is retryable.
|
||||
//
|
||||
// request: the original request sent to the server
|
||||
// err: the server sent this error to us
|
||||
//
|
||||
// The function returns true if the error is retryable and the request
|
||||
// can be retried, otherwise it returns false.
|
||||
// We have four mode of communications - 'Stream', 'Watch', 'Do' and 'DoRaw', this
|
||||
// function allows us to customize the retryability aspect of each.
|
||||
type IsRetryableErrorFunc func(request *http.Request, err error) bool
|
||||
|
||||
func (r IsRetryableErrorFunc) IsErrorRetryable(request *http.Request, err error) bool {
|
||||
return r(request, err)
|
||||
}
|
||||
|
||||
var neverRetryError = IsRetryableErrorFunc(func(_ *http.Request, _ error) bool {
|
||||
return false
|
||||
})
|
||||
|
||||
// WithRetry allows the client to retry a request up to a certain number of times
|
||||
// Note that WithRetry is not safe for concurrent use by multiple
|
||||
// goroutines without additional locking or coordination.
|
||||
type WithRetry interface {
|
||||
// IsNextRetry advances the retry counter appropriately
|
||||
// and returns true if the request should be retried,
|
||||
// otherwise it returns false, if:
|
||||
// - we have already reached the maximum retry threshold.
|
||||
// - the error does not fall into the retryable category.
|
||||
// - the server has not sent us a 429, or 5xx status code and the
|
||||
// 'Retry-After' response header is not set with a value.
|
||||
// - we need to seek to the beginning of the request body before we
|
||||
// initiate the next retry, the function should log an error and
|
||||
// return false if it fails to do so.
|
||||
//
|
||||
// restReq: the associated rest.Request
|
||||
// httpReq: the HTTP Request sent to the server
|
||||
// resp: the response sent from the server, it is set if err is nil
|
||||
// err: the server sent this error to us, if err is set then resp is nil.
|
||||
// f: a IsRetryableErrorFunc function provided by the client that determines
|
||||
// if the err sent by the server is retryable.
|
||||
IsNextRetry(ctx context.Context, restReq *Request, httpReq *http.Request, resp *http.Response, err error, f IsRetryableErrorFunc) bool
|
||||
|
||||
// Before should be invoked prior to each attempt, including
|
||||
// the first one. If an error is returned, the request should
|
||||
// be aborted immediately.
|
||||
//
|
||||
// Before may also be additionally responsible for preparing
|
||||
// the request for the next retry, namely in terms of resetting
|
||||
// the request body in case it has been read.
|
||||
Before(ctx context.Context, r *Request) error
|
||||
|
||||
// After should be invoked immediately after an attempt is made.
|
||||
After(ctx context.Context, r *Request, resp *http.Response, err error)
|
||||
|
||||
// WrapPreviousError wraps the error from any previous attempt into
|
||||
// the final error specified in 'finalErr', so the user has more
|
||||
// context why the request failed.
|
||||
// For example, if a request times out after multiple retries then
|
||||
// we see a generic context.Canceled or context.DeadlineExceeded
|
||||
// error which is not very useful in debugging. This function can
|
||||
// wrap any error from previous attempt(s) to provide more context to
|
||||
// the user. The error returned in 'err' must satisfy the
|
||||
// following conditions:
|
||||
// a: errors.Unwrap(err) = errors.Unwrap(finalErr) if finalErr
|
||||
// implements Unwrap
|
||||
// b: errors.Unwrap(err) = finalErr if finalErr does not
|
||||
// implements Unwrap
|
||||
// c: errors.Is(err, otherErr) = errors.Is(finalErr, otherErr)
|
||||
WrapPreviousError(finalErr error) (err error)
|
||||
}
|
||||
|
||||
// RetryAfter holds information associated with the next retry.
|
||||
type RetryAfter struct {
|
||||
// Wait is the duration the server has asked us to wait before
|
||||
// the next retry is initiated.
|
||||
// This is the value of the 'Retry-After' response header in seconds.
|
||||
Wait time.Duration
|
||||
|
||||
// Attempt is the Nth attempt after which we have received a retryable
|
||||
// error or a 'Retry-After' response header from the server.
|
||||
Attempt int
|
||||
|
||||
// Reason describes why we are retrying the request
|
||||
Reason string
|
||||
}
|
||||
|
||||
type withRetry struct {
|
||||
maxRetries int
|
||||
attempts int
|
||||
|
||||
// retry after parameters that pertain to the attempt that is to
|
||||
// be made soon, so as to enable 'Before' and 'After' to refer
|
||||
// to the retry parameters.
|
||||
// - for the first attempt, it will always be nil
|
||||
// - for consecutive attempts, it is non nil and holds the
|
||||
// retry after parameters for the next attempt to be made.
|
||||
retryAfter *RetryAfter
|
||||
|
||||
// we keep track of two most recent errors, if the most
|
||||
// recent attempt is labeled as 'N' then:
|
||||
// - currentErr represents the error returned by attempt N, it
|
||||
// can be nil if attempt N did not return an error.
|
||||
// - previousErr represents an error from an attempt 'M' which
|
||||
// precedes attempt 'N' (N - M >= 1), it is non nil only when:
|
||||
// - for a sequence of attempt(s) 1..n (n>1), there
|
||||
// is an attempt k (k<n) that returned an error.
|
||||
previousErr, currentErr error
|
||||
}
|
||||
|
||||
func (r *withRetry) trackPreviousError(err error) {
|
||||
// keep track of two most recent errors
|
||||
if r.currentErr != nil {
|
||||
r.previousErr = r.currentErr
|
||||
}
|
||||
r.currentErr = err
|
||||
}
|
||||
|
||||
func (r *withRetry) IsNextRetry(ctx context.Context, restReq *Request, httpReq *http.Request, resp *http.Response, err error, f IsRetryableErrorFunc) bool {
|
||||
defer r.trackPreviousError(err)
|
||||
|
||||
if httpReq == nil || (resp == nil && err == nil) {
|
||||
// bad input, we do nothing.
|
||||
return false
|
||||
}
|
||||
|
||||
r.attempts++
|
||||
r.retryAfter = &RetryAfter{Attempt: r.attempts}
|
||||
if r.attempts > r.maxRetries {
|
||||
return false
|
||||
}
|
||||
|
||||
// if the server returned an error, it takes precedence over the http response.
|
||||
var errIsRetryable bool
|
||||
if f != nil && err != nil && f.IsErrorRetryable(httpReq, err) {
|
||||
errIsRetryable = true
|
||||
// we have a retryable error, for which we will create an
|
||||
// artificial "Retry-After" response.
|
||||
resp = retryAfterResponse()
|
||||
}
|
||||
if err != nil && !errIsRetryable {
|
||||
return false
|
||||
}
|
||||
|
||||
// if we are here, we have either a or b:
|
||||
// a: we have a retryable error, for which we already
|
||||
// have an artificial "Retry-After" response.
|
||||
// b: we have a response from the server for which we
|
||||
// need to check if it is retryable
|
||||
seconds, wait := checkWait(resp)
|
||||
if !wait {
|
||||
return false
|
||||
}
|
||||
|
||||
r.retryAfter.Wait = time.Duration(seconds) * time.Second
|
||||
r.retryAfter.Reason = getRetryReason(r.attempts, seconds, resp, err)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (r *withRetry) Before(ctx context.Context, request *Request) error {
|
||||
// If the request context is already canceled there
|
||||
// is no need to retry.
|
||||
if ctx.Err() != nil {
|
||||
r.trackPreviousError(ctx.Err())
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
url := request.URL()
|
||||
// r.retryAfter represents the retry after parameters calculated
|
||||
// from the (response, err) tuple from the last attempt, so 'Before'
|
||||
// can apply these retry after parameters prior to the next attempt.
|
||||
// 'r.retryAfter == nil' indicates that this is the very first attempt.
|
||||
if r.retryAfter == nil {
|
||||
// we do a backoff sleep before the first attempt is made,
|
||||
// (preserving current behavior).
|
||||
if request.backoff != nil {
|
||||
request.backoff.Sleep(request.backoff.CalculateBackoff(url))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// At this point we've made atleast one attempt, post which the response
|
||||
// body should have been fully read and closed in order for it to be safe
|
||||
// to reset the request body before we reconnect, in order for us to reuse
|
||||
// the same TCP connection.
|
||||
if seeker, ok := request.body.(io.Seeker); ok && request.body != nil {
|
||||
if _, err := seeker.Seek(0, io.SeekStart); err != nil {
|
||||
err = fmt.Errorf("failed to reset the request body while retrying a request: %v", err)
|
||||
r.trackPreviousError(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// if we are here, we have made attempt(s) at least once before.
|
||||
if request.backoff != nil {
|
||||
delay := request.backoff.CalculateBackoff(url)
|
||||
if r.retryAfter.Wait > delay {
|
||||
delay = r.retryAfter.Wait
|
||||
}
|
||||
request.backoff.Sleep(delay)
|
||||
}
|
||||
|
||||
// We are retrying the request that we already send to
|
||||
// apiserver at least once before. This request should
|
||||
// also be throttled with the client-internal rate limiter.
|
||||
if err := request.tryThrottleWithInfo(ctx, r.retryAfter.Reason); err != nil {
|
||||
r.trackPreviousError(ctx.Err())
|
||||
return err
|
||||
}
|
||||
|
||||
klog.V(4).Infof("Got a Retry-After %s response for attempt %d to %v", r.retryAfter.Wait, r.retryAfter.Attempt, request.URL().String())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *withRetry) After(ctx context.Context, request *Request, resp *http.Response, err error) {
|
||||
// 'After' is invoked immediately after an attempt is made, let's label
|
||||
// the attempt we have just made as attempt 'N'.
|
||||
// the current value of r.retryAfter represents the retry after
|
||||
// parameters calculated from the (response, err) tuple from
|
||||
// attempt N-1, so r.retryAfter is outdated and should not be
|
||||
// referred to here.
|
||||
r.retryAfter = nil
|
||||
|
||||
if request.c.base != nil {
|
||||
if err != nil {
|
||||
request.backoff.UpdateBackoff(request.URL(), err, 0)
|
||||
} else {
|
||||
request.backoff.UpdateBackoff(request.URL(), err, resp.StatusCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *withRetry) WrapPreviousError(currentErr error) error {
|
||||
if currentErr == nil || r.previousErr == nil {
|
||||
return currentErr
|
||||
}
|
||||
|
||||
// if both previous and current error objects represent the error,
|
||||
// then there is no need to wrap the previous error.
|
||||
if currentErr.Error() == r.previousErr.Error() {
|
||||
return currentErr
|
||||
}
|
||||
|
||||
previousErr := r.previousErr
|
||||
// net/http wraps the underlying error with an url.Error, if the
|
||||
// previous err object is an instance of url.Error, then we can
|
||||
// unwrap it to get to the inner error object, this is so we can
|
||||
// avoid error message like:
|
||||
// Error: Get "http://foo.bar/api/v1": context deadline exceeded - error \
|
||||
// from a previous attempt: Error: Get "http://foo.bar/api/v1": EOF
|
||||
if urlErr, ok := r.previousErr.(*url.Error); ok && urlErr != nil {
|
||||
if urlErr.Unwrap() != nil {
|
||||
previousErr = urlErr.Unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
return &wrapPreviousError{
|
||||
currentErr: currentErr,
|
||||
previousError: previousErr,
|
||||
}
|
||||
}
|
||||
|
||||
type wrapPreviousError struct {
|
||||
currentErr, previousError error
|
||||
}
|
||||
|
||||
func (w *wrapPreviousError) Unwrap() error { return w.currentErr }
|
||||
func (w *wrapPreviousError) Error() string {
|
||||
return fmt.Sprintf("%s - error from a previous attempt: %s", w.currentErr.Error(), w.previousError.Error())
|
||||
}
|
||||
|
||||
// checkWait returns true along with a number of seconds if
|
||||
// the server instructed us to wait before retrying.
|
||||
func checkWait(resp *http.Response) (int, bool) {
|
||||
switch r := resp.StatusCode; {
|
||||
// any 500 error code and 429 can trigger a wait
|
||||
case r == http.StatusTooManyRequests, r >= 500:
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
i, ok := retryAfterSeconds(resp)
|
||||
return i, ok
|
||||
}
|
||||
|
||||
func getRetryReason(retries, seconds int, resp *http.Response, err error) string {
|
||||
// priority and fairness sets the UID of the FlowSchema
|
||||
// associated with a request in the following response Header.
|
||||
const responseHeaderMatchedFlowSchemaUID = "X-Kubernetes-PF-FlowSchema-UID"
|
||||
|
||||
message := fmt.Sprintf("retries: %d, retry-after: %ds", retries, seconds)
|
||||
|
||||
switch {
|
||||
case resp.StatusCode == http.StatusTooManyRequests:
|
||||
// it is server-side throttling from priority and fairness
|
||||
flowSchemaUID := resp.Header.Get(responseHeaderMatchedFlowSchemaUID)
|
||||
return fmt.Sprintf("%s - retry-reason: due to server-side throttling, FlowSchema UID: %q", message, flowSchemaUID)
|
||||
case err != nil:
|
||||
// it's a retryable error
|
||||
return fmt.Sprintf("%s - retry-reason: due to retryable error, error: %v", message, err)
|
||||
default:
|
||||
return fmt.Sprintf("%s - retry-reason: %d", message, resp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func readAndCloseResponseBody(resp *http.Response) {
|
||||
if resp == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Ensure the response body is fully read and closed
|
||||
// before we reconnect, so that we reuse the same TCP
|
||||
// connection.
|
||||
const maxBodySlurpSize = 2 << 10
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.ContentLength <= maxBodySlurpSize {
|
||||
io.Copy(io.Discard, &io.LimitedReader{R: resp.Body, N: maxBodySlurpSize})
|
||||
}
|
||||
}
|
||||
|
||||
func retryAfterResponse() *http.Response {
|
||||
return retryAfterResponseWithDelay("1")
|
||||
}
|
||||
|
||||
func retryAfterResponseWithDelay(delay string) *http.Response {
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
Header: http.Header{"Retry-After": []string{delay}},
|
||||
}
|
||||
}
|
58
client/vendor/k8s.io/client-go/rest/zz_generated.deepcopy.go
generated
vendored
Normal file
58
client/vendor/k8s.io/client-go/rest/zz_generated.deepcopy.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
//go:build !ignore_autogenerated
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||
|
||||
package rest
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TLSClientConfig) DeepCopyInto(out *TLSClientConfig) {
|
||||
*out = *in
|
||||
if in.CertData != nil {
|
||||
in, out := &in.CertData, &out.CertData
|
||||
*out = make([]byte, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.KeyData != nil {
|
||||
in, out := &in.KeyData, &out.KeyData
|
||||
*out = make([]byte, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.CAData != nil {
|
||||
in, out := &in.CAData, &out.CAData
|
||||
*out = make([]byte, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.NextProtos != nil {
|
||||
in, out := &in.NextProtos, &out.NextProtos
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSClientConfig.
|
||||
func (in *TLSClientConfig) DeepCopy() *TLSClientConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TLSClientConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
Reference in New Issue
Block a user