git subrepo clone (merge) https://github.com/kubernetes-incubator/metrics-server.git metrics-server
subrepo:
subdir: "metrics-server"
merged: "92d8412"
upstream:
origin: "https://github.com/kubernetes-incubator/metrics-server.git"
branch: "master"
commit: "92d8412"
git-subrepo:
version: "0.4.0"
origin: "???"
commit: "???"
diff --git a/metrics-server/vendor/k8s.io/client-go/transport/OWNERS b/metrics-server/vendor/k8s.io/client-go/transport/OWNERS
new file mode 100755
index 0000000..bf0ba5b
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/client-go/transport/OWNERS
@@ -0,0 +1,7 @@
+reviewers:
+- smarterclayton
+- wojtek-t
+- deads2k
+- liggitt
+- krousey
+- caesarxuchao
diff --git a/metrics-server/vendor/k8s.io/client-go/transport/cache.go b/metrics-server/vendor/k8s.io/client-go/transport/cache.go
new file mode 100644
index 0000000..7cffe2a
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/client-go/transport/cache.go
@@ -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
+}
diff --git a/metrics-server/vendor/k8s.io/client-go/transport/config.go b/metrics-server/vendor/k8s.io/client-go/transport/config.go
new file mode 100644
index 0000000..4081c23
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/client-go/transport/config.go
@@ -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.
+}
diff --git a/metrics-server/vendor/k8s.io/client-go/transport/round_trippers.go b/metrics-server/vendor/k8s.io/client-go/transport/round_trippers.go
new file mode 100644
index 0000000..316a5c0
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/client-go/transport/round_trippers.go
@@ -0,0 +1,531 @@
+/*
+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-"+headerKeyEscape(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+headerKeyEscape(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
+}
+
+func legalHeaderByte(b byte) bool {
+ return int(b) < len(legalHeaderKeyBytes) && legalHeaderKeyBytes[b]
+}
+
+func shouldEscape(b byte) bool {
+ // url.PathUnescape() returns an error if any '%' is not followed by two
+ // hexadecimal digits, so we'll intentionally encode it.
+ return !legalHeaderByte(b) || b == '%'
+}
+
+func headerKeyEscape(key string) string {
+ buf := strings.Builder{}
+ for i := 0; i < len(key); i++ {
+ b := key[i]
+ if shouldEscape(b) {
+ // %-encode bytes that should be escaped:
+ // https://tools.ietf.org/html/rfc3986#section-2.1
+ fmt.Fprintf(&buf, "%%%02X", b)
+ continue
+ }
+ buf.WriteByte(b)
+ }
+ return buf.String()
+}
+
+// legalHeaderKeyBytes was copied from net/http/lex.go's isTokenTable.
+// See https://httpwg.github.io/specs/rfc7230.html#rule.token.separators
+var legalHeaderKeyBytes = [127]bool{
+ '%': true,
+ '!': true,
+ '#': true,
+ '$': true,
+ '&': true,
+ '\'': true,
+ '*': true,
+ '+': true,
+ '-': true,
+ '.': true,
+ '0': true,
+ '1': true,
+ '2': true,
+ '3': true,
+ '4': true,
+ '5': true,
+ '6': true,
+ '7': true,
+ '8': true,
+ '9': true,
+ 'A': true,
+ 'B': true,
+ 'C': true,
+ 'D': true,
+ 'E': true,
+ 'F': true,
+ 'G': true,
+ 'H': true,
+ 'I': true,
+ 'J': true,
+ 'K': true,
+ 'L': true,
+ 'M': true,
+ 'N': true,
+ 'O': true,
+ 'P': true,
+ 'Q': true,
+ 'R': true,
+ 'S': true,
+ 'T': true,
+ 'U': true,
+ 'W': true,
+ 'V': true,
+ 'X': true,
+ 'Y': true,
+ 'Z': true,
+ '^': true,
+ '_': true,
+ '`': true,
+ 'a': true,
+ 'b': true,
+ 'c': true,
+ 'd': true,
+ 'e': true,
+ 'f': true,
+ 'g': true,
+ 'h': true,
+ 'i': true,
+ 'j': true,
+ 'k': true,
+ 'l': true,
+ 'm': true,
+ 'n': true,
+ 'o': true,
+ 'p': true,
+ 'q': true,
+ 'r': true,
+ 's': true,
+ 't': true,
+ 'u': true,
+ 'v': true,
+ 'w': true,
+ 'x': true,
+ 'y': true,
+ 'z': true,
+ '|': true,
+ '~': true,
+}
diff --git a/metrics-server/vendor/k8s.io/client-go/transport/transport.go b/metrics-server/vendor/k8s.io/client-go/transport/transport.go
new file mode 100644
index 0000000..c19739f
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/client-go/transport/transport.go
@@ -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
+}