mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-07-23 19:58:03 +08:00
vendor: initial vendor
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
7
vendor/k8s.io/client-go/transport/OWNERS
generated
vendored
Normal file
7
vendor/k8s.io/client-go/transport/OWNERS
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
reviewers:
|
||||
- smarterclayton
|
||||
- wojtek-t
|
||||
- deads2k
|
||||
- liggitt
|
||||
- krousey
|
||||
- caesarxuchao
|
117
vendor/k8s.io/client-go/transport/cache.go
generated
vendored
Normal file
117
vendor/k8s.io/client-go/transport/cache.go
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
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 transport
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
)
|
||||
|
||||
// TlsTransportCache caches TLS http.RoundTrippers different configurations. The
|
||||
// same RoundTripper will be returned for configs with identical TLS options If
|
||||
// the config has no custom TLS options, http.DefaultTransport is returned.
|
||||
type tlsTransportCache struct {
|
||||
mu sync.Mutex
|
||||
transports map[tlsCacheKey]*http.Transport
|
||||
}
|
||||
|
||||
const idleConnsPerHost = 25
|
||||
|
||||
var tlsCache = &tlsTransportCache{transports: make(map[tlsCacheKey]*http.Transport)}
|
||||
|
||||
type tlsCacheKey struct {
|
||||
insecure bool
|
||||
caData string
|
||||
certData string
|
||||
keyData string
|
||||
getCert string
|
||||
serverName string
|
||||
dial string
|
||||
}
|
||||
|
||||
func (t tlsCacheKey) String() string {
|
||||
keyText := "<none>"
|
||||
if len(t.keyData) > 0 {
|
||||
keyText = "<redacted>"
|
||||
}
|
||||
return fmt.Sprintf("insecure:%v, caData:%#v, certData:%#v, keyData:%s, getCert: %s, serverName:%s, dial:%s", t.insecure, t.caData, t.certData, keyText, t.getCert, t.serverName, t.dial)
|
||||
}
|
||||
|
||||
func (c *tlsTransportCache) get(config *Config) (http.RoundTripper, error) {
|
||||
key, err := tlsConfigKey(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Ensure we only create a single transport for the given TLS options
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
// See if we already have a custom transport for this config
|
||||
if t, ok := c.transports[key]; ok {
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// Get the TLS options for this client config
|
||||
tlsConfig, err := TLSConfigFor(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// The options didn't require a custom TLS config
|
||||
if tlsConfig == nil && config.Dial == nil {
|
||||
return http.DefaultTransport, nil
|
||||
}
|
||||
|
||||
dial := config.Dial
|
||||
if dial == nil {
|
||||
dial = (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).DialContext
|
||||
}
|
||||
// Cache a single transport for these options
|
||||
c.transports[key] = utilnet.SetTransportDefaults(&http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
TLSClientConfig: tlsConfig,
|
||||
MaxIdleConnsPerHost: idleConnsPerHost,
|
||||
DialContext: dial,
|
||||
})
|
||||
return c.transports[key], nil
|
||||
}
|
||||
|
||||
// tlsConfigKey returns a unique key for tls.Config objects returned from TLSConfigFor
|
||||
func tlsConfigKey(c *Config) (tlsCacheKey, error) {
|
||||
// Make sure ca/key/cert content is loaded
|
||||
if err := loadTLSFiles(c); err != nil {
|
||||
return tlsCacheKey{}, err
|
||||
}
|
||||
return tlsCacheKey{
|
||||
insecure: c.TLS.Insecure,
|
||||
caData: string(c.TLS.CAData),
|
||||
certData: string(c.TLS.CertData),
|
||||
keyData: string(c.TLS.KeyData),
|
||||
getCert: fmt.Sprintf("%p", c.TLS.GetCert),
|
||||
serverName: c.TLS.ServerName,
|
||||
dial: fmt.Sprintf("%p", c.Dial),
|
||||
}, nil
|
||||
}
|
110
vendor/k8s.io/client-go/transport/config.go
generated
vendored
Normal file
110
vendor/k8s.io/client-go/transport/config.go
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
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 transport
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Config holds various options for establishing a transport.
|
||||
type Config struct {
|
||||
// UserAgent is an optional field that specifies the caller of this
|
||||
// request.
|
||||
UserAgent string
|
||||
|
||||
// The base TLS configuration for this transport.
|
||||
TLS TLSConfig
|
||||
|
||||
// Username and password for basic authentication
|
||||
Username string
|
||||
Password string
|
||||
|
||||
// Bearer token for authentication
|
||||
BearerToken string
|
||||
|
||||
// Impersonate is the config that this Config will impersonate using
|
||||
Impersonate ImpersonationConfig
|
||||
|
||||
// Transport may be used for custom HTTP behavior. This attribute may
|
||||
// not be specified with the TLS client certificate options. Use
|
||||
// WrapTransport for most client level operations.
|
||||
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.
|
||||
WrapTransport func(rt http.RoundTripper) http.RoundTripper
|
||||
|
||||
// Dial specifies the dial function for creating unencrypted TCP connections.
|
||||
Dial func(ctx context.Context, network, address string) (net.Conn, error)
|
||||
}
|
||||
|
||||
// ImpersonationConfig has all the available impersonation options
|
||||
type ImpersonationConfig struct {
|
||||
// UserName matches user.Info.GetName()
|
||||
UserName string
|
||||
// Groups matches user.Info.GetGroups()
|
||||
Groups []string
|
||||
// Extra matches user.Info.GetExtra()
|
||||
Extra map[string][]string
|
||||
}
|
||||
|
||||
// HasCA returns whether the configuration has a certificate authority or not.
|
||||
func (c *Config) HasCA() bool {
|
||||
return len(c.TLS.CAData) > 0 || len(c.TLS.CAFile) > 0
|
||||
}
|
||||
|
||||
// HasBasicAuth returns whether the configuration has basic authentication or not.
|
||||
func (c *Config) HasBasicAuth() bool {
|
||||
return len(c.Username) != 0
|
||||
}
|
||||
|
||||
// HasTokenAuth returns whether the configuration has token authentication or not.
|
||||
func (c *Config) HasTokenAuth() bool {
|
||||
return len(c.BearerToken) != 0
|
||||
}
|
||||
|
||||
// HasCertAuth returns whether the configuration has certificate authentication or not.
|
||||
func (c *Config) HasCertAuth() bool {
|
||||
return (len(c.TLS.CertData) != 0 || len(c.TLS.CertFile) != 0) && (len(c.TLS.KeyData) != 0 || len(c.TLS.KeyFile) != 0)
|
||||
}
|
||||
|
||||
// HasCertCallbacks returns whether the configuration has certificate callback or not.
|
||||
func (c *Config) HasCertCallback() bool {
|
||||
return c.TLS.GetCert != nil
|
||||
}
|
||||
|
||||
// TLSConfig holds the information needed to set up a TLS transport.
|
||||
type TLSConfig struct {
|
||||
CAFile string // Path of the PEM-encoded server trusted root certificates.
|
||||
CertFile string // Path of the PEM-encoded client certificate.
|
||||
KeyFile string // Path of the PEM-encoded client key.
|
||||
|
||||
Insecure bool // Server should be accessed without verifying the certificate. For testing only.
|
||||
ServerName string // Override for the server name passed to the server for SNI and used to verify certificates.
|
||||
|
||||
CAData []byte // Bytes of the PEM-encoded server trusted root certificates. Supercedes CAFile.
|
||||
CertData []byte // Bytes of the PEM-encoded client certificate. Supercedes CertFile.
|
||||
KeyData []byte // Bytes of the PEM-encoded client key. Supercedes KeyFile.
|
||||
|
||||
GetCert func() (*tls.Certificate, error) // Callback that returns a TLS client certificate. CertData, CertFile, KeyData and KeyFile supercede this field.
|
||||
}
|
424
vendor/k8s.io/client-go/transport/round_trippers.go
generated
vendored
Normal file
424
vendor/k8s.io/client-go/transport/round_trippers.go
generated
vendored
Normal file
@@ -0,0 +1,424 @@
|
||||
/*
|
||||
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 transport
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
)
|
||||
|
||||
// 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 RoundTripper returned from
|
||||
// New.
|
||||
func HTTPWrappersForConfig(config *Config, rt http.RoundTripper) (http.RoundTripper, error) {
|
||||
if config.WrapTransport != nil {
|
||||
rt = config.WrapTransport(rt)
|
||||
}
|
||||
|
||||
rt = DebugWrappers(rt)
|
||||
|
||||
// Set authentication wrappers
|
||||
switch {
|
||||
case config.HasBasicAuth() && config.HasTokenAuth():
|
||||
return nil, fmt.Errorf("username/password or bearer token may be set, but not both")
|
||||
case config.HasTokenAuth():
|
||||
rt = NewBearerAuthRoundTripper(config.BearerToken, rt)
|
||||
case config.HasBasicAuth():
|
||||
rt = NewBasicAuthRoundTripper(config.Username, config.Password, rt)
|
||||
}
|
||||
if len(config.UserAgent) > 0 {
|
||||
rt = NewUserAgentRoundTripper(config.UserAgent, rt)
|
||||
}
|
||||
if len(config.Impersonate.UserName) > 0 ||
|
||||
len(config.Impersonate.Groups) > 0 ||
|
||||
len(config.Impersonate.Extra) > 0 {
|
||||
rt = NewImpersonatingRoundTripper(config.Impersonate, rt)
|
||||
}
|
||||
return rt, nil
|
||||
}
|
||||
|
||||
// DebugWrappers wraps a round tripper and logs based on the current log level.
|
||||
func DebugWrappers(rt http.RoundTripper) http.RoundTripper {
|
||||
switch {
|
||||
case bool(glog.V(9)):
|
||||
rt = newDebuggingRoundTripper(rt, debugCurlCommand, debugURLTiming, debugResponseHeaders)
|
||||
case bool(glog.V(8)):
|
||||
rt = newDebuggingRoundTripper(rt, debugJustURL, debugRequestHeaders, debugResponseStatus, debugResponseHeaders)
|
||||
case bool(glog.V(7)):
|
||||
rt = newDebuggingRoundTripper(rt, debugJustURL, debugRequestHeaders, debugResponseStatus)
|
||||
case bool(glog.V(6)):
|
||||
rt = newDebuggingRoundTripper(rt, debugURLTiming)
|
||||
}
|
||||
|
||||
return rt
|
||||
}
|
||||
|
||||
type requestCanceler interface {
|
||||
CancelRequest(*http.Request)
|
||||
}
|
||||
|
||||
type authProxyRoundTripper struct {
|
||||
username string
|
||||
groups []string
|
||||
extra map[string][]string
|
||||
|
||||
rt http.RoundTripper
|
||||
}
|
||||
|
||||
// NewAuthProxyRoundTripper provides a roundtripper which will add auth proxy fields to requests for
|
||||
// authentication terminating proxy cases
|
||||
// assuming you pull the user from the context:
|
||||
// username is the user.Info.GetName() of the user
|
||||
// groups is the user.Info.GetGroups() of the user
|
||||
// extra is the user.Info.GetExtra() of the user
|
||||
// extra can contain any additional information that the authenticator
|
||||
// thought was interesting, for example authorization scopes.
|
||||
// In order to faithfully round-trip through an impersonation flow, these keys
|
||||
// MUST be lowercase.
|
||||
func NewAuthProxyRoundTripper(username string, groups []string, extra map[string][]string, rt http.RoundTripper) http.RoundTripper {
|
||||
return &authProxyRoundTripper{
|
||||
username: username,
|
||||
groups: groups,
|
||||
extra: extra,
|
||||
rt: rt,
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *authProxyRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
req = utilnet.CloneRequest(req)
|
||||
SetAuthProxyHeaders(req, rt.username, rt.groups, rt.extra)
|
||||
|
||||
return rt.rt.RoundTrip(req)
|
||||
}
|
||||
|
||||
// SetAuthProxyHeaders stomps the auth proxy header fields. It mutates its argument.
|
||||
func SetAuthProxyHeaders(req *http.Request, username string, groups []string, extra map[string][]string) {
|
||||
req.Header.Del("X-Remote-User")
|
||||
req.Header.Del("X-Remote-Group")
|
||||
for key := range req.Header {
|
||||
if strings.HasPrefix(strings.ToLower(key), strings.ToLower("X-Remote-Extra-")) {
|
||||
req.Header.Del(key)
|
||||
}
|
||||
}
|
||||
|
||||
req.Header.Set("X-Remote-User", username)
|
||||
for _, group := range groups {
|
||||
req.Header.Add("X-Remote-Group", group)
|
||||
}
|
||||
for key, values := range extra {
|
||||
for _, value := range values {
|
||||
req.Header.Add("X-Remote-Extra-"+key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *authProxyRoundTripper) CancelRequest(req *http.Request) {
|
||||
if canceler, ok := rt.rt.(requestCanceler); ok {
|
||||
canceler.CancelRequest(req)
|
||||
} else {
|
||||
glog.Errorf("CancelRequest not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *authProxyRoundTripper) WrappedRoundTripper() http.RoundTripper { return rt.rt }
|
||||
|
||||
type userAgentRoundTripper struct {
|
||||
agent string
|
||||
rt http.RoundTripper
|
||||
}
|
||||
|
||||
func NewUserAgentRoundTripper(agent string, rt http.RoundTripper) http.RoundTripper {
|
||||
return &userAgentRoundTripper{agent, rt}
|
||||
}
|
||||
|
||||
func (rt *userAgentRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
if len(req.Header.Get("User-Agent")) != 0 {
|
||||
return rt.rt.RoundTrip(req)
|
||||
}
|
||||
req = utilnet.CloneRequest(req)
|
||||
req.Header.Set("User-Agent", rt.agent)
|
||||
return rt.rt.RoundTrip(req)
|
||||
}
|
||||
|
||||
func (rt *userAgentRoundTripper) CancelRequest(req *http.Request) {
|
||||
if canceler, ok := rt.rt.(requestCanceler); ok {
|
||||
canceler.CancelRequest(req)
|
||||
} else {
|
||||
glog.Errorf("CancelRequest not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *userAgentRoundTripper) WrappedRoundTripper() http.RoundTripper { return rt.rt }
|
||||
|
||||
type basicAuthRoundTripper struct {
|
||||
username string
|
||||
password string
|
||||
rt http.RoundTripper
|
||||
}
|
||||
|
||||
// NewBasicAuthRoundTripper will apply a BASIC auth authorization header to a
|
||||
// request unless it has already been set.
|
||||
func NewBasicAuthRoundTripper(username, password string, rt http.RoundTripper) http.RoundTripper {
|
||||
return &basicAuthRoundTripper{username, password, rt}
|
||||
}
|
||||
|
||||
func (rt *basicAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
if len(req.Header.Get("Authorization")) != 0 {
|
||||
return rt.rt.RoundTrip(req)
|
||||
}
|
||||
req = utilnet.CloneRequest(req)
|
||||
req.SetBasicAuth(rt.username, rt.password)
|
||||
return rt.rt.RoundTrip(req)
|
||||
}
|
||||
|
||||
func (rt *basicAuthRoundTripper) CancelRequest(req *http.Request) {
|
||||
if canceler, ok := rt.rt.(requestCanceler); ok {
|
||||
canceler.CancelRequest(req)
|
||||
} else {
|
||||
glog.Errorf("CancelRequest not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *basicAuthRoundTripper) WrappedRoundTripper() http.RoundTripper { return rt.rt }
|
||||
|
||||
// These correspond to the headers used in pkg/apis/authentication. We don't want the package dependency,
|
||||
// but you must not change the values.
|
||||
const (
|
||||
// ImpersonateUserHeader is used to impersonate a particular user during an API server request
|
||||
ImpersonateUserHeader = "Impersonate-User"
|
||||
|
||||
// ImpersonateGroupHeader is used to impersonate a particular group during an API server request.
|
||||
// It can be repeated multiplied times for multiple groups.
|
||||
ImpersonateGroupHeader = "Impersonate-Group"
|
||||
|
||||
// ImpersonateUserExtraHeaderPrefix is a prefix for a header used to impersonate an entry in the
|
||||
// extra map[string][]string for user.Info. The key for the `extra` map is suffix.
|
||||
// The same key can be repeated multiple times to have multiple elements in the slice under a single key.
|
||||
// For instance:
|
||||
// Impersonate-Extra-Foo: one
|
||||
// Impersonate-Extra-Foo: two
|
||||
// results in extra["Foo"] = []string{"one", "two"}
|
||||
ImpersonateUserExtraHeaderPrefix = "Impersonate-Extra-"
|
||||
)
|
||||
|
||||
type impersonatingRoundTripper struct {
|
||||
impersonate ImpersonationConfig
|
||||
delegate http.RoundTripper
|
||||
}
|
||||
|
||||
// NewImpersonatingRoundTripper will add an Act-As header to a request unless it has already been set.
|
||||
func NewImpersonatingRoundTripper(impersonate ImpersonationConfig, delegate http.RoundTripper) http.RoundTripper {
|
||||
return &impersonatingRoundTripper{impersonate, delegate}
|
||||
}
|
||||
|
||||
func (rt *impersonatingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
// use the user header as marker for the rest.
|
||||
if len(req.Header.Get(ImpersonateUserHeader)) != 0 {
|
||||
return rt.delegate.RoundTrip(req)
|
||||
}
|
||||
req = utilnet.CloneRequest(req)
|
||||
req.Header.Set(ImpersonateUserHeader, rt.impersonate.UserName)
|
||||
|
||||
for _, group := range rt.impersonate.Groups {
|
||||
req.Header.Add(ImpersonateGroupHeader, group)
|
||||
}
|
||||
for k, vv := range rt.impersonate.Extra {
|
||||
for _, v := range vv {
|
||||
req.Header.Add(ImpersonateUserExtraHeaderPrefix+k, v)
|
||||
}
|
||||
}
|
||||
|
||||
return rt.delegate.RoundTrip(req)
|
||||
}
|
||||
|
||||
func (rt *impersonatingRoundTripper) CancelRequest(req *http.Request) {
|
||||
if canceler, ok := rt.delegate.(requestCanceler); ok {
|
||||
canceler.CancelRequest(req)
|
||||
} else {
|
||||
glog.Errorf("CancelRequest not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *impersonatingRoundTripper) WrappedRoundTripper() http.RoundTripper { return rt.delegate }
|
||||
|
||||
type bearerAuthRoundTripper struct {
|
||||
bearer string
|
||||
rt http.RoundTripper
|
||||
}
|
||||
|
||||
// NewBearerAuthRoundTripper adds the provided bearer token to a request
|
||||
// unless the authorization header has already been set.
|
||||
func NewBearerAuthRoundTripper(bearer string, rt http.RoundTripper) http.RoundTripper {
|
||||
return &bearerAuthRoundTripper{bearer, rt}
|
||||
}
|
||||
|
||||
func (rt *bearerAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
if len(req.Header.Get("Authorization")) != 0 {
|
||||
return rt.rt.RoundTrip(req)
|
||||
}
|
||||
|
||||
req = utilnet.CloneRequest(req)
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", rt.bearer))
|
||||
return rt.rt.RoundTrip(req)
|
||||
}
|
||||
|
||||
func (rt *bearerAuthRoundTripper) CancelRequest(req *http.Request) {
|
||||
if canceler, ok := rt.rt.(requestCanceler); ok {
|
||||
canceler.CancelRequest(req)
|
||||
} else {
|
||||
glog.Errorf("CancelRequest not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *bearerAuthRoundTripper) WrappedRoundTripper() http.RoundTripper { return rt.rt }
|
||||
|
||||
// requestInfo keeps track of information about a request/response combination
|
||||
type requestInfo struct {
|
||||
RequestHeaders http.Header
|
||||
RequestVerb string
|
||||
RequestURL string
|
||||
|
||||
ResponseStatus string
|
||||
ResponseHeaders http.Header
|
||||
ResponseErr error
|
||||
|
||||
Duration time.Duration
|
||||
}
|
||||
|
||||
// newRequestInfo creates a new RequestInfo based on an http request
|
||||
func newRequestInfo(req *http.Request) *requestInfo {
|
||||
return &requestInfo{
|
||||
RequestURL: req.URL.String(),
|
||||
RequestVerb: req.Method,
|
||||
RequestHeaders: req.Header,
|
||||
}
|
||||
}
|
||||
|
||||
// complete adds information about the response to the requestInfo
|
||||
func (r *requestInfo) complete(response *http.Response, err error) {
|
||||
if err != nil {
|
||||
r.ResponseErr = err
|
||||
return
|
||||
}
|
||||
r.ResponseStatus = response.Status
|
||||
r.ResponseHeaders = response.Header
|
||||
}
|
||||
|
||||
// toCurl returns a string that can be run as a command in a terminal (minus the body)
|
||||
func (r *requestInfo) toCurl() string {
|
||||
headers := ""
|
||||
for key, values := range r.RequestHeaders {
|
||||
for _, value := range values {
|
||||
headers += fmt.Sprintf(` -H %q`, fmt.Sprintf("%s: %s", key, value))
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("curl -k -v -X%s %s '%s'", r.RequestVerb, headers, r.RequestURL)
|
||||
}
|
||||
|
||||
// debuggingRoundTripper will display information about the requests passing
|
||||
// through it based on what is configured
|
||||
type debuggingRoundTripper struct {
|
||||
delegatedRoundTripper http.RoundTripper
|
||||
|
||||
levels map[debugLevel]bool
|
||||
}
|
||||
|
||||
type debugLevel int
|
||||
|
||||
const (
|
||||
debugJustURL debugLevel = iota
|
||||
debugURLTiming
|
||||
debugCurlCommand
|
||||
debugRequestHeaders
|
||||
debugResponseStatus
|
||||
debugResponseHeaders
|
||||
)
|
||||
|
||||
func newDebuggingRoundTripper(rt http.RoundTripper, levels ...debugLevel) *debuggingRoundTripper {
|
||||
drt := &debuggingRoundTripper{
|
||||
delegatedRoundTripper: rt,
|
||||
levels: make(map[debugLevel]bool, len(levels)),
|
||||
}
|
||||
for _, v := range levels {
|
||||
drt.levels[v] = true
|
||||
}
|
||||
return drt
|
||||
}
|
||||
|
||||
func (rt *debuggingRoundTripper) CancelRequest(req *http.Request) {
|
||||
if canceler, ok := rt.delegatedRoundTripper.(requestCanceler); ok {
|
||||
canceler.CancelRequest(req)
|
||||
} else {
|
||||
glog.Errorf("CancelRequest not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *debuggingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
reqInfo := newRequestInfo(req)
|
||||
|
||||
if rt.levels[debugJustURL] {
|
||||
glog.Infof("%s %s", reqInfo.RequestVerb, reqInfo.RequestURL)
|
||||
}
|
||||
if rt.levels[debugCurlCommand] {
|
||||
glog.Infof("%s", reqInfo.toCurl())
|
||||
|
||||
}
|
||||
if rt.levels[debugRequestHeaders] {
|
||||
glog.Infof("Request Headers:")
|
||||
for key, values := range reqInfo.RequestHeaders {
|
||||
for _, value := range values {
|
||||
glog.Infof(" %s: %s", key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
startTime := time.Now()
|
||||
response, err := rt.delegatedRoundTripper.RoundTrip(req)
|
||||
reqInfo.Duration = time.Since(startTime)
|
||||
|
||||
reqInfo.complete(response, err)
|
||||
|
||||
if rt.levels[debugURLTiming] {
|
||||
glog.Infof("%s %s %s in %d milliseconds", reqInfo.RequestVerb, reqInfo.RequestURL, reqInfo.ResponseStatus, reqInfo.Duration.Nanoseconds()/int64(time.Millisecond))
|
||||
}
|
||||
if rt.levels[debugResponseStatus] {
|
||||
glog.Infof("Response Status: %s in %d milliseconds", reqInfo.ResponseStatus, reqInfo.Duration.Nanoseconds()/int64(time.Millisecond))
|
||||
}
|
||||
if rt.levels[debugResponseHeaders] {
|
||||
glog.Infof("Response Headers:")
|
||||
for key, values := range reqInfo.ResponseHeaders {
|
||||
for _, value := range values {
|
||||
glog.Infof(" %s: %s", key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return response, err
|
||||
}
|
||||
|
||||
func (rt *debuggingRoundTripper) WrappedRoundTripper() http.RoundTripper {
|
||||
return rt.delegatedRoundTripper
|
||||
}
|
169
vendor/k8s.io/client-go/transport/transport.go
generated
vendored
Normal file
169
vendor/k8s.io/client-go/transport/transport.go
generated
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
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 transport
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// New returns an http.RoundTripper that will provide the authentication
|
||||
// or transport level security defined by the provided Config.
|
||||
func New(config *Config) (http.RoundTripper, error) {
|
||||
// Set transport level security
|
||||
if config.Transport != nil && (config.HasCA() || config.HasCertAuth() || config.HasCertCallback() || config.TLS.Insecure) {
|
||||
return nil, fmt.Errorf("using a custom transport with TLS certificate options or the insecure flag is not allowed")
|
||||
}
|
||||
|
||||
var (
|
||||
rt http.RoundTripper
|
||||
err error
|
||||
)
|
||||
|
||||
if config.Transport != nil {
|
||||
rt = config.Transport
|
||||
} else {
|
||||
rt, err = tlsCache.get(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return HTTPWrappersForConfig(config, rt)
|
||||
}
|
||||
|
||||
// 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(c *Config) (*tls.Config, error) {
|
||||
if !(c.HasCA() || c.HasCertAuth() || c.HasCertCallback() || c.TLS.Insecure || len(c.TLS.ServerName) > 0) {
|
||||
return nil, nil
|
||||
}
|
||||
if c.HasCA() && c.TLS.Insecure {
|
||||
return nil, fmt.Errorf("specifying a root certificates file with the insecure flag is not allowed")
|
||||
}
|
||||
if err := loadTLSFiles(c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tlsConfig := &tls.Config{
|
||||
// Can't use SSLv3 because of POODLE and BEAST
|
||||
// Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher
|
||||
// Can't use TLSv1.1 because of RC4 cipher usage
|
||||
MinVersion: tls.VersionTLS12,
|
||||
InsecureSkipVerify: c.TLS.Insecure,
|
||||
ServerName: c.TLS.ServerName,
|
||||
}
|
||||
|
||||
if c.HasCA() {
|
||||
tlsConfig.RootCAs = rootCertPool(c.TLS.CAData)
|
||||
}
|
||||
|
||||
var staticCert *tls.Certificate
|
||||
if c.HasCertAuth() {
|
||||
// If key/cert were provided, verify them before setting up
|
||||
// tlsConfig.GetClientCertificate.
|
||||
cert, err := tls.X509KeyPair(c.TLS.CertData, c.TLS.KeyData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
staticCert = &cert
|
||||
}
|
||||
|
||||
if c.HasCertAuth() || c.HasCertCallback() {
|
||||
tlsConfig.GetClientCertificate = func(*tls.CertificateRequestInfo) (*tls.Certificate, error) {
|
||||
// Note: static key/cert data always take precedence over cert
|
||||
// callback.
|
||||
if staticCert != nil {
|
||||
return staticCert, nil
|
||||
}
|
||||
if c.HasCertCallback() {
|
||||
cert, err := c.TLS.GetCert()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// GetCert may return empty value, meaning no cert.
|
||||
if cert != nil {
|
||||
return cert, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Both c.TLS.CertData/KeyData were unset and GetCert didn't return
|
||||
// anything. Return an empty tls.Certificate, no client cert will
|
||||
// be sent to the server.
|
||||
return &tls.Certificate{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
return tlsConfig, nil
|
||||
}
|
||||
|
||||
// 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.TLS.CAData, err = dataFromSliceOrFile(c.TLS.CAData, c.TLS.CAFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.TLS.CertData, err = dataFromSliceOrFile(c.TLS.CertData, c.TLS.CertFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.TLS.KeyData, err = dataFromSliceOrFile(c.TLS.KeyData, c.TLS.KeyFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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 := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
return fileData, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// rootCertPool returns nil if caData is empty. When passed along, this will mean "use system CAs".
|
||||
// When caData is not empty, it will be the ONLY information used in the CertPool.
|
||||
func rootCertPool(caData []byte) *x509.CertPool {
|
||||
// What we really want is a copy of x509.systemRootsPool, but that isn't exposed. It's difficult to build (see the go
|
||||
// code for a look at the platform specific insanity), so we'll use the fact that RootCAs == nil gives us the system values
|
||||
// It doesn't allow trusting either/or, but hopefully that won't be an issue
|
||||
if len(caData) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// if we have caData, use it
|
||||
certPool := x509.NewCertPool()
|
||||
certPool.AppendCertsFromPEM(caData)
|
||||
return certPool
|
||||
}
|
Reference in New Issue
Block a user