Update k8s client-go to v6.0.0 (#1340)

* Update k8s client-go to v6.0.0

This fix updates k8s client-go to v6.0.0 as CoreDNS is supported
in 1.9 and v6.0.0 is the recommended version.

There are quite some massive changes that need to be made:
1. k8s.io/client-go/pkg/api/v1 has been changed to k8s.io/api/v1 (repo changed from `client-go` to `api`)
2. kubernetes.Clientset adds one extra layer, so that `kubernetes.Clientset.Services()` and like has been changed to `kubernetes.Clientset.CoreV1().Services()`

Also, we have to stick with specific commits of `k8s.io/apimachinery` and the newly introduced `k8s.io/api`
because go dep still could not figure out the right version to fetch.

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>

* Update vendor with `dep ensure --update` and `dep prune`

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
This commit is contained in:
Yong Tang
2018-01-03 19:11:28 +08:00
committed by Miek Gieben
parent bce7f5fbec
commit 7fe5b0bb1f
1278 changed files with 123970 additions and 277876 deletions

35
vendor/k8s.io/client-go/rest/BUILD generated vendored
View File

@@ -1,7 +1,5 @@
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
@@ -18,15 +16,17 @@ go_test(
"url_utils_test.go",
"urlbackoff_test.go",
],
importpath = "k8s.io/client-go/rest",
library = ":go_default_library",
tags = ["automanaged"],
deps = [
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/github.com/google/gofuzz:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
@@ -38,8 +38,6 @@ go_test(
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/scheme:go_default_library",
"//vendor/k8s.io/client-go/pkg/api/v1:go_default_library",
"//vendor/k8s.io/client-go/pkg/apis/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/client-go/rest/watch:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd/api:go_default_library",
"//vendor/k8s.io/client-go/util/flowcontrol:go_default_library",
@@ -58,14 +56,15 @@ go_library(
"url_utils.go",
"urlbackoff.go",
"versions.go",
"zz_generated.deepcopy.go",
],
tags = ["automanaged"],
importpath = "k8s.io/client-go/rest",
deps = [
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/golang.org/x/net/http2:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/streaming:go_default_library",
@@ -73,7 +72,6 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
"//vendor/k8s.io/client-go/pkg/api/v1:go_default_library",
"//vendor/k8s.io/client-go/pkg/version:go_default_library",
"//vendor/k8s.io/client-go/rest/watch:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd/api:go_default_library",
@@ -83,3 +81,20 @@ go_library(
"//vendor/k8s.io/client-go/util/flowcontrol:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//staging/src/k8s.io/client-go/rest/fake:all-srcs",
"//staging/src/k8s.io/client-go/rest/watch:all-srcs",
],
tags = ["automanaged"],
)

View File

@@ -27,6 +27,8 @@ import (
"fmt"
"k8s.io/api/core/v1"
v1beta1 "k8s.io/api/extensions/v1beta1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
@@ -34,8 +36,6 @@ import (
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/diff"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/pkg/api/v1"
v1beta1 "k8s.io/client-go/pkg/apis/extensions/v1beta1"
utiltesting "k8s.io/client-go/util/testing"
)

View File

@@ -29,10 +29,10 @@ import (
"github.com/golang/glog"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/pkg/version"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
certutil "k8s.io/client-go/util/cert"
@@ -71,6 +71,10 @@ type Config struct {
// TODO: demonstrate an OAuth2 compatible client.
BearerToken string
// CacheDir is the directory where we'll store HTTP cached responses.
// If set to empty string, no caching mechanism will be used.
CacheDir string
// Impersonate is the configuration that RESTClient will use for impersonation.
Impersonate ImpersonationConfig
@@ -110,6 +114,9 @@ type Config struct {
// 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(network, addr string) (net.Conn, error)
// Version forces a specific version to be used (if registered)
// Do we need this?
// Version string
@@ -126,6 +133,7 @@ type ImpersonationConfig struct {
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.
@@ -412,5 +420,45 @@ func AnonymousClientConfig(config *Config) *Config {
QPS: config.QPS,
Burst: config.Burst,
Timeout: config.Timeout,
Dial: config.Dial,
}
}
// CopyConfig returns a copy of the given config
func CopyConfig(config *Config) *Config {
return &Config{
Host: config.Host,
APIPath: config.APIPath,
Prefix: config.Prefix,
ContentConfig: config.ContentConfig,
Username: config.Username,
Password: config.Password,
BearerToken: config.BearerToken,
CacheDir: config.CacheDir,
Impersonate: ImpersonationConfig{
Groups: config.Impersonate.Groups,
Extra: config.Impersonate.Extra,
UserName: config.Impersonate.UserName,
},
AuthProvider: config.AuthProvider,
AuthConfigPersister: config.AuthConfigPersister,
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,
},
UserAgent: config.UserAgent,
Transport: config.Transport,
WrapTransport: config.WrapTransport,
QPS: config.QPS,
Burst: config.Burst,
RateLimiter: config.RateLimiter,
Timeout: config.Timeout,
Dial: config.Dial,
}
}

View File

@@ -18,6 +18,7 @@ package rest
import (
"io"
"net"
"net/http"
"path/filepath"
"reflect"
@@ -26,14 +27,16 @@ import (
fuzz "github.com/google/gofuzz"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/diff"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/pkg/api/v1"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/client-go/util/flowcontrol"
"errors"
"github.com/stretchr/testify/assert"
)
@@ -205,6 +208,19 @@ func (n *fakeNegotiatedSerializer) DecoderToVersion(serializer runtime.Decoder,
return &fakeCodec{}
}
var fakeDialFunc = func(network, addr string) (net.Conn, error) {
return nil, fakeDialerError
}
var fakeDialerError = errors.New("fakedialer")
type fakeAuthProviderConfigPersister struct{}
func (fakeAuthProviderConfigPersister) Persist(map[string]string) error {
return fakeAuthProviderConfigPersisterError
}
var fakeAuthProviderConfigPersisterError = errors.New("fakeAuthProviderConfigPersisterError")
func TestAnonymousConfig(t *testing.T) {
f := fuzz.New().NilChance(0.0).NumElements(1, 1)
f.Funcs(
@@ -236,6 +252,8 @@ func TestAnonymousConfig(t *testing.T) {
func(r *clientcmdapi.AuthProviderConfig, f fuzz.Continue) {
r.Config = map[string]string{}
},
// Dial does not require fuzzer
func(r *func(network, addr string) (net.Conn, error), f fuzz.Continue) {},
)
for i := 0; i < 20; i++ {
original := &Config{}
@@ -249,6 +267,7 @@ func TestAnonymousConfig(t *testing.T) {
expected.BearerToken = ""
expected.Username = ""
expected.Password = ""
expected.CacheDir = ""
expected.AuthProvider = nil
expected.AuthConfigPersister = nil
expected.TLSClientConfig.CertData = nil
@@ -264,9 +283,94 @@ func TestAnonymousConfig(t *testing.T) {
actual.WrapTransport = nil
expected.WrapTransport = nil
}
if actual.Dial != nil {
_, actualError := actual.Dial("", "")
_, expectedError := actual.Dial("", "")
if !reflect.DeepEqual(expectedError, actualError) {
t.Fatalf("CopyConfig dropped the Dial field")
}
} else {
actual.Dial = nil
expected.Dial = nil
}
if !reflect.DeepEqual(*actual, expected) {
t.Fatalf("AnonymousClientConfig dropped unexpected fields, identify whether they are security related or not: %s", diff.ObjectGoPrintDiff(expected, actual))
}
}
}
func TestCopyConfig(t *testing.T) {
f := fuzz.New().NilChance(0.0).NumElements(1, 1)
f.Funcs(
func(r *runtime.Codec, f fuzz.Continue) {
codec := &fakeCodec{}
f.Fuzz(codec)
*r = codec
},
func(r *http.RoundTripper, f fuzz.Continue) {
roundTripper := &fakeRoundTripper{}
f.Fuzz(roundTripper)
*r = roundTripper
},
func(fn *func(http.RoundTripper) http.RoundTripper, f fuzz.Continue) {
*fn = fakeWrapperFunc
},
func(r *runtime.NegotiatedSerializer, f fuzz.Continue) {
serializer := &fakeNegotiatedSerializer{}
f.Fuzz(serializer)
*r = serializer
},
func(r *flowcontrol.RateLimiter, f fuzz.Continue) {
limiter := &fakeLimiter{}
f.Fuzz(limiter)
*r = limiter
},
func(r *AuthProviderConfigPersister, f fuzz.Continue) {
*r = fakeAuthProviderConfigPersister{}
},
func(r *func(network, addr string) (net.Conn, error), f fuzz.Continue) {
*r = fakeDialFunc
},
)
for i := 0; i < 20; i++ {
original := &Config{}
f.Fuzz(original)
actual := CopyConfig(original)
expected := *original
// this is the list of known risky fields, add to this list if a new field
// is added to Config, update CopyConfig to preserve the field otherwise.
// The DeepEqual cannot handle the func comparison, so we just verify if the
// function return the expected object.
if actual.WrapTransport == nil || !reflect.DeepEqual(expected.WrapTransport(nil), &fakeRoundTripper{}) {
t.Fatalf("CopyConfig dropped the WrapTransport field")
} else {
actual.WrapTransport = nil
expected.WrapTransport = nil
}
if actual.Dial != nil {
_, actualError := actual.Dial("", "")
_, expectedError := actual.Dial("", "")
if !reflect.DeepEqual(expectedError, actualError) {
t.Fatalf("CopyConfig dropped the Dial field")
}
}
actual.Dial = nil
expected.Dial = nil
if actual.AuthConfigPersister != nil {
actualError := actual.AuthConfigPersister.Persist(nil)
expectedError := actual.AuthConfigPersister.Persist(nil)
if !reflect.DeepEqual(expectedError, actualError) {
t.Fatalf("CopyConfig dropped the Dial field")
}
}
actual.AuthConfigPersister = nil
expected.AuthConfigPersister = nil
if !reflect.DeepEqual(*actual, expected) {
t.Fatalf("CopyConfig dropped unexpected fields, identify whether they are security related or not: %s", diff.ObjectReflectDiff(expected, *actual))
}
}
}

View File

@@ -33,27 +33,20 @@ import (
"time"
"github.com/golang/glog"
"golang.org/x/net/http2"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
"k8s.io/apimachinery/pkg/util/net"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/pkg/api/v1"
restclientwatch "k8s.io/client-go/rest/watch"
"k8s.io/client-go/tools/metrics"
"k8s.io/client-go/util/flowcontrol"
)
var (
// specialParams lists parameters that are handled specially and which users of Request
// are therefore not allowed to set manually.
specialParams = sets.NewString("timeout")
// longThrottleLatency defines threshold for logging requests. All requests being
// throttle for more than longThrottleLatency will be logged.
longThrottleLatency = 50 * time.Millisecond
@@ -186,6 +179,24 @@ func (r *Request) Resource(resource string) *Request {
return r
}
// BackOff sets the request's backoff manager to the one specified,
// or defaults to the stub implementation if nil is provided
func (r *Request) BackOff(manager BackoffManager) *Request {
if manager == nil {
r.backoffMgr = &NoBackoff{}
return r
}
r.backoffMgr = manager
return r
}
// Throttle receives a rate-limiter and sets or replaces an existing request limiter
func (r *Request) Throttle(limiter flowcontrol.RateLimiter) *Request {
r.throttle = limiter
return r
}
// SubResource sets a sub-resource path which can be multiple segments segment after the resource
// name but before the suffix.
func (r *Request) SubResource(subresources ...string) *Request {
@@ -269,7 +280,7 @@ func (r *Request) AbsPath(segments ...string) *Request {
}
// RequestURI overwrites existing path and parameters with the value of the provided server relative
// URI. Some parameters (those in specialParameters) cannot be overwritten.
// URI.
func (r *Request) RequestURI(uri string) *Request {
if r.err != nil {
return r
@@ -291,143 +302,6 @@ func (r *Request) RequestURI(uri string) *Request {
return r
}
const (
// A constant that clients can use to refer in a field selector to the object name field.
// Will be automatically emitted as the correct name for the API version.
nodeUnschedulable = "spec.unschedulable"
objectNameField = "metadata.name"
podHost = "spec.nodeName"
podStatus = "status.phase"
secretType = "type"
eventReason = "reason"
eventSource = "source"
eventType = "type"
eventInvolvedKind = "involvedObject.kind"
eventInvolvedNamespace = "involvedObject.namespace"
eventInvolvedName = "involvedObject.name"
eventInvolvedUID = "involvedObject.uid"
eventInvolvedAPIVersion = "involvedObject.apiVersion"
eventInvolvedResourceVersion = "involvedObject.resourceVersion"
eventInvolvedFieldPath = "involvedObject.fieldPath"
)
type clientFieldNameToAPIVersionFieldName map[string]string
func (c clientFieldNameToAPIVersionFieldName) filterField(field, value string) (newField, newValue string, err error) {
newFieldName, ok := c[field]
if !ok {
return "", "", fmt.Errorf("%v - %v - no field mapping defined", field, value)
}
return newFieldName, value, nil
}
type resourceTypeToFieldMapping map[string]clientFieldNameToAPIVersionFieldName
func (r resourceTypeToFieldMapping) filterField(resourceType, field, value string) (newField, newValue string, err error) {
fMapping, ok := r[resourceType]
if !ok {
return "", "", fmt.Errorf("%v - %v - %v - no field mapping defined", resourceType, field, value)
}
return fMapping.filterField(field, value)
}
type versionToResourceToFieldMapping map[schema.GroupVersion]resourceTypeToFieldMapping
// filterField transforms the given field/value selector for the given groupVersion and resource
func (v versionToResourceToFieldMapping) filterField(groupVersion *schema.GroupVersion, resourceType, field, value string) (newField, newValue string, err error) {
rMapping, ok := v[*groupVersion]
if !ok {
// no groupVersion overrides registered, default to identity mapping
return field, value, nil
}
newField, newValue, err = rMapping.filterField(resourceType, field, value)
if err != nil {
// no groupVersionResource overrides registered, default to identity mapping
return field, value, nil
}
return newField, newValue, nil
}
var fieldMappings = versionToResourceToFieldMapping{
v1.SchemeGroupVersion: resourceTypeToFieldMapping{
"nodes": clientFieldNameToAPIVersionFieldName{
objectNameField: objectNameField,
nodeUnschedulable: nodeUnschedulable,
},
"pods": clientFieldNameToAPIVersionFieldName{
objectNameField: objectNameField,
podHost: podHost,
podStatus: podStatus,
},
"secrets": clientFieldNameToAPIVersionFieldName{
secretType: secretType,
},
"serviceAccounts": clientFieldNameToAPIVersionFieldName{
objectNameField: objectNameField,
},
"endpoints": clientFieldNameToAPIVersionFieldName{
objectNameField: objectNameField,
},
"events": clientFieldNameToAPIVersionFieldName{
objectNameField: objectNameField,
eventReason: eventReason,
eventSource: eventSource,
eventType: eventType,
eventInvolvedKind: eventInvolvedKind,
eventInvolvedNamespace: eventInvolvedNamespace,
eventInvolvedName: eventInvolvedName,
eventInvolvedUID: eventInvolvedUID,
eventInvolvedAPIVersion: eventInvolvedAPIVersion,
eventInvolvedResourceVersion: eventInvolvedResourceVersion,
eventInvolvedFieldPath: eventInvolvedFieldPath,
},
},
}
// FieldsSelectorParam adds the given selector as a query parameter with the name paramName.
func (r *Request) FieldsSelectorParam(s fields.Selector) *Request {
if r.err != nil {
return r
}
if s == nil {
return r
}
if s.Empty() {
return r
}
s2, err := s.Transform(func(field, value string) (newField, newValue string, err error) {
return fieldMappings.filterField(r.content.GroupVersion, r.resource, field, value)
})
if err != nil {
r.err = err
return r
}
return r.setParam(metav1.FieldSelectorQueryParam(r.content.GroupVersion.String()), s2.String())
}
// LabelsSelectorParam adds the given selector as a query parameter
func (r *Request) LabelsSelectorParam(s labels.Selector) *Request {
if r.err != nil {
return r
}
if s == nil {
return r
}
if s.Empty() {
return r
}
return r.setParam(metav1.LabelSelectorQueryParam(r.content.GroupVersion.String()), s.String())
}
// UintParam creates a query parameter with the given value.
func (r *Request) UintParam(paramName string, u uint64) *Request {
if r.err != nil {
return r
}
return r.setParam(paramName, strconv.FormatUint(u, 10))
}
// Param creates a query parameter with the given string value.
func (r *Request) Param(paramName, s string) *Request {
if r.err != nil {
@@ -439,6 +313,8 @@ func (r *Request) Param(paramName, s string) *Request {
// VersionedParams will take the provided object, serialize it to a map[string][]string using the
// implicit RESTClient API version and the default parameter codec, and then add those as parameters
// to the request. Use this to provide versioned query parameters from client libraries.
// VersionedParams will not write query parameters that have omitempty set and are empty. If a
// parameter has already been set it is appended to (Params and VersionedParams are additive).
func (r *Request) VersionedParams(obj runtime.Object, codec runtime.ParameterCodec) *Request {
if r.err != nil {
return r
@@ -449,52 +325,15 @@ func (r *Request) VersionedParams(obj runtime.Object, codec runtime.ParameterCod
return r
}
for k, v := range params {
for _, value := range v {
// TODO: Move it to setParam method, once we get rid of
// FieldSelectorParam & LabelSelectorParam methods.
if k == metav1.LabelSelectorQueryParam(r.content.GroupVersion.String()) && value == "" {
// Don't set an empty selector for backward compatibility.
// Since there is no way to get the difference between empty
// and unspecified string, we don't set it to avoid having
// labelSelector= param in every request.
continue
}
if k == metav1.FieldSelectorQueryParam(r.content.GroupVersion.String()) {
if len(value) == 0 {
// Don't set an empty selector for backward compatibility.
// Since there is no way to get the difference between empty
// and unspecified string, we don't set it to avoid having
// fieldSelector= param in every request.
continue
}
// TODO: Filtering should be handled somewhere else.
selector, err := fields.ParseSelector(value)
if err != nil {
r.err = fmt.Errorf("unparsable field selector: %v", err)
return r
}
filteredSelector, err := selector.Transform(
func(field, value string) (newField, newValue string, err error) {
return fieldMappings.filterField(r.content.GroupVersion, r.resource, field, value)
})
if err != nil {
r.err = fmt.Errorf("untransformable field selector: %v", err)
return r
}
value = filteredSelector.String()
}
r.setParam(k, value)
if r.params == nil {
r.params = make(url.Values)
}
r.params[k] = append(r.params[k], v...)
}
return r
}
func (r *Request) setParam(paramName, value string) *Request {
if specialParams.Has(paramName) {
r.err = fmt.Errorf("must set %v through the corresponding function, not directly.", paramName)
return r
}
if r.params == nil {
r.params = make(url.Values)
}
@@ -502,11 +341,14 @@ func (r *Request) setParam(paramName, value string) *Request {
return r
}
func (r *Request) SetHeader(key, value string) *Request {
func (r *Request) SetHeader(key string, values ...string) *Request {
if r.headers == nil {
r.headers = http.Header{}
}
r.headers.Set(key, value)
r.headers.Del(key)
for _, value := range values {
r.headers.Add(key, value)
}
return r
}
@@ -609,7 +451,7 @@ func (r *Request) URL() *url.URL {
// finalURLTemplate is similar to URL(), but will make all specific parameter values equal
// - instead of name or namespace, "{name}" and "{namespace}" will be used, and all query
// parameters will be reset. This creates a copy of the request so as not to change the
// underyling object. This means some useful request info (like the types of field
// underlying object. This means some useful request info (like the types of field
// selectors in use) will be lost.
// TODO: preserve field selector keys
func (r Request) finalURLTemplate() url.URL {
@@ -921,8 +763,29 @@ func (r *Request) DoRaw() ([]byte, error) {
func (r *Request) transformResponse(resp *http.Response, req *http.Request) Result {
var body []byte
if resp.Body != nil {
if data, err := ioutil.ReadAll(resp.Body); err == nil {
data, err := ioutil.ReadAll(resp.Body)
switch err.(type) {
case nil:
body = data
case http2.StreamError:
// This is trying to catch the scenario that the server may close the connection when sending the
// response body. This can be caused by server timeout due to a slow network connection.
// TODO: Add test for this. Steps may be:
// 1. client-go (or kubectl) sends a GET request.
// 2. Apiserver sends back the headers and then part of the body
// 3. Apiserver closes connection.
// 4. client-go should catch this and return an error.
glog.V(2).Infof("Stream error %#v when reading response body, may be caused by closed connection.", err)
streamErr := fmt.Errorf("Stream error %#v when reading response body, may be caused by closed connection. Please retry.", err)
return Result{
err: streamErr,
}
default:
glog.Errorf("Unexpected error when reading response body: %#v", err)
unexpectedErr := fmt.Errorf("Unexpected error %#v when reading response body. Please retry.", err)
return Result{
err: unexpectedErr,
}
}
}
@@ -978,6 +841,25 @@ func (r *Request) transformResponse(resp *http.Response, req *http.Request) Resu
}
}
// truncateBody decides if the body should be truncated, based on the glog Verbosity.
func truncateBody(body string) string {
max := 0
switch {
case bool(glog.V(10)):
return body
case bool(glog.V(9)):
max = 10240
case bool(glog.V(8)):
max = 1024
}
if len(body) <= max {
return body
}
return body[:max] + fmt.Sprintf(" [truncated %d chars]", len(body)-max)
}
// glogBody logs a body output that could be either JSON or protobuf. It explicitly guards against
// allocating a new string for the body output unless necessary. Uses a simple heuristic to determine
// whether the body is printable.
@@ -986,9 +868,9 @@ func glogBody(prefix string, body []byte) {
if bytes.IndexFunc(body, func(r rune) bool {
return r < 0x0a
}) != -1 {
glog.Infof("%s:\n%s", prefix, hex.Dump(body))
glog.Infof("%s:\n%s", prefix, truncateBody(hex.Dump(body)))
} else {
glog.Infof("%s: %s", prefix, string(body))
glog.Infof("%s: %s", prefix, truncateBody(string(body)))
}
}
}
@@ -1069,7 +951,7 @@ func isTextResponse(resp *http.Response) bool {
func checkWait(resp *http.Response) (int, bool) {
switch r := resp.StatusCode; {
// any 500 error code and 429 can trigger a wait
case r == errors.StatusTooManyRequests, r >= 500:
case r == http.StatusTooManyRequests, r >= 500:
default:
return 0, false
}

View File

@@ -20,6 +20,7 @@ import (
"bytes"
"context"
"errors"
"flag"
"fmt"
"io"
"io/ioutil"
@@ -34,10 +35,12 @@ import (
"testing"
"time"
"github.com/golang/glog"
"k8s.io/api/core/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
@@ -48,7 +51,6 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/pkg/api/v1"
restclientwatch "k8s.io/client-go/rest/watch"
"k8s.io/client-go/util/flowcontrol"
utiltesting "k8s.io/client-go/util/testing"
@@ -100,8 +102,6 @@ func TestRequestWithErrorWontChange(t *testing.T) {
}
r := original
changed := r.Param("foo", "bar").
LabelsSelectorParam(labels.Set{"a": "b"}.AsSelector()).
UintParam("uint", 1).
AbsPath("/abs").
Prefix("test").
Suffix("testing").
@@ -257,7 +257,7 @@ func TestRequestVersionedParamsFromListOptions(t *testing.T) {
"resourceVersion": []string{"1", "2"},
"timeoutSeconds": []string{"10"},
}) {
t.Errorf("should have set a param: %#v", r)
t.Errorf("should have set a param: %#v %v", r.params, r.err)
}
}
@@ -1133,7 +1133,7 @@ func TestCheckRetryClosesBody(t *testing.T) {
return
}
w.Header().Set("Retry-After", "1")
http.Error(w, "Too many requests, please try again later.", apierrors.StatusTooManyRequests)
http.Error(w, "Too many requests, please try again later.", http.StatusTooManyRequests)
}))
defer testServer.Close()
@@ -1207,7 +1207,7 @@ func TestCheckRetryHandles429And5xx(t *testing.T) {
return
}
w.Header().Set("Retry-After", "0")
w.WriteHeader([]int{apierrors.StatusTooManyRequests, 500, 501, 504}[count])
w.WriteHeader([]int{http.StatusTooManyRequests, 500, 501, 504}[count])
count++
}))
defer testServer.Close()
@@ -1237,7 +1237,7 @@ func BenchmarkCheckRetryClosesBody(b *testing.B) {
return
}
w.Header().Set("Retry-After", "0")
w.WriteHeader(apierrors.StatusTooManyRequests)
w.WriteHeader(http.StatusTooManyRequests)
}))
defer testServer.Close()
@@ -1276,7 +1276,6 @@ func TestDoRequestNewWayReader(t *testing.T) {
Resource("bar").
Name("baz").
Prefix("foo").
LabelsSelectorParam(labels.Set{"name": "foo"}.AsSelector()).
Timeout(time.Second).
Body(bytes.NewBuffer(reqBodyExpected)).
Do().Get()
@@ -1291,7 +1290,7 @@ func TestDoRequestNewWayReader(t *testing.T) {
}
tmpStr := string(reqBodyExpected)
requestURL := defaultResourcePathWithPrefix("foo", "bar", "", "baz")
requestURL += "?" + metav1.LabelSelectorQueryParam(v1.SchemeGroupVersion.String()) + "=name%3Dfoo&timeout=1s"
requestURL += "?timeout=1s"
fakeHandler.ValidateRequest(t, requestURL, "POST", &tmpStr)
}
@@ -1316,7 +1315,6 @@ func TestDoRequestNewWayObj(t *testing.T) {
Suffix("baz").
Name("bar").
Resource("foo").
LabelsSelectorParam(labels.Set{"name": "foo"}.AsSelector()).
Timeout(time.Second).
Body(reqObj).
Do().Get()
@@ -1331,7 +1329,7 @@ func TestDoRequestNewWayObj(t *testing.T) {
}
tmpStr := string(reqBodyExpected)
requestURL := defaultResourcePathWithPrefix("", "foo", "", "bar/baz")
requestURL += "?" + metav1.LabelSelectorQueryParam(v1.SchemeGroupVersion.String()) + "=name%3Dfoo&timeout=1s"
requestURL += "?timeout=1s"
fakeHandler.ValidateRequest(t, requestURL, "POST", &tmpStr)
}
@@ -1489,33 +1487,14 @@ func TestAbsPath(t *testing.T) {
}
}
func TestUintParam(t *testing.T) {
table := []struct {
name string
testVal uint64
expectStr string
}{
{"foo", 31415, "http://localhost?foo=31415"},
{"bar", 42, "http://localhost?bar=42"},
{"baz", 0, "http://localhost?baz=0"},
}
for _, item := range table {
u, _ := url.Parse("http://localhost")
r := NewRequest(nil, "GET", u, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil).AbsPath("").UintParam(item.name, item.testVal)
if e, a := item.expectStr, r.URL().String(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
}
}
func TestUnacceptableParamNames(t *testing.T) {
table := []struct {
name string
testVal string
expectSuccess bool
}{
{"timeout", "42", false},
// timeout is no longer "protected"
{"timeout", "42", true},
}
for _, item := range table {
@@ -1720,6 +1699,74 @@ func TestDoContext(t *testing.T) {
}
}
func buildString(length int) string {
s := make([]byte, length)
for i := range s {
s[i] = 'a'
}
return string(s)
}
func TestTruncateBody(t *testing.T) {
tests := []struct {
body string
want string
level string
}{
// Anything below 8 is completely truncated
{
body: "Completely truncated below 8",
want: " [truncated 28 chars]",
level: "0",
},
// Small strings are not truncated by high levels
{
body: "Small body never gets truncated",
want: "Small body never gets truncated",
level: "10",
},
{
body: "Small body never gets truncated",
want: "Small body never gets truncated",
level: "8",
},
// Strings are truncated to 1024 if level is less than 9.
{
body: buildString(2000),
level: "8",
want: fmt.Sprintf("%s [truncated 976 chars]", buildString(1024)),
},
// Strings are truncated to 10240 if level is 9.
{
body: buildString(20000),
level: "9",
want: fmt.Sprintf("%s [truncated 9760 chars]", buildString(10240)),
},
// Strings are not truncated if level is 10 or higher
{
body: buildString(20000),
level: "10",
want: buildString(20000),
},
// Strings are not truncated if level is 10 or higher
{
body: buildString(20000),
level: "11",
want: buildString(20000),
},
}
l := flag.Lookup("v").Value.(flag.Getter).Get().(glog.Level)
for _, test := range tests {
flag.Set("v", test.level)
got := truncateBody(test.body)
if got != test.want {
t.Errorf("truncateBody(%v) = %v, want %v", test.body, got, test.want)
}
}
flag.Set("v", l.String())
}
func defaultResourcePathWithPrefix(prefix, resource, namespace, name string) string {
var path string
path = "/api/" + v1.SchemeGroupVersion.Version

View File

@@ -89,11 +89,13 @@ func (c *Config) TransportConfig() (*transport.Config, error) {
},
Username: c.Username,
Password: c.Password,
CacheDir: c.CacheDir,
BearerToken: c.BearerToken,
Impersonate: transport.ImpersonationConfig{
UserName: c.Impersonate.UserName,
Groups: c.Impersonate.Groups,
Extra: c.Impersonate.Extra,
},
Dial: c.Dial,
}, nil
}

View File

@@ -56,6 +56,14 @@ func DefaultServerURL(host, apiPath string, groupVersion schema.GroupVersion, de
// 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
@@ -64,10 +72,9 @@ func DefaultServerURL(host, apiPath string, groupVersion schema.GroupVersion, de
} else {
versionedAPIPath = path.Join(versionedAPIPath, groupVersion.Version)
}
return hostURL, versionedAPIPath, nil
return versionedAPIPath
}
// defaultServerUrlFor is shared between IsConfigTransportTLS and RESTClientFor. It

View File

@@ -20,7 +20,7 @@ import (
"path"
"testing"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/api/core/v1"
)
func TestValidatesHostParameter(t *testing.T) {

View File

@@ -1,7 +1,5 @@
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
@@ -14,7 +12,7 @@ go_library(
"decoder.go",
"encoder.go",
],
tags = ["automanaged"],
importpath = "k8s.io/client-go/rest/watch",
deps = [
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
@@ -29,8 +27,9 @@ go_test(
"decoder_test.go",
"encoder_test.go",
],
tags = ["automanaged"],
importpath = "k8s.io/client-go/rest/watch_test",
deps = [
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
@@ -40,7 +39,19 @@ go_test(
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/scheme:go_default_library",
"//vendor/k8s.io/client-go/pkg/api/v1:go_default_library",
"//vendor/k8s.io/client-go/rest/watch:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@@ -22,6 +22,7 @@ import (
"testing"
"time"
"k8s.io/api/core/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
@@ -31,7 +32,6 @@ import (
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/pkg/api/v1"
restclientwatch "k8s.io/client-go/rest/watch"
)

View File

@@ -21,6 +21,7 @@ import (
"io/ioutil"
"testing"
"k8s.io/api/core/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
@@ -29,7 +30,6 @@ import (
"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/pkg/api/v1"
restclientwatch "k8s.io/client-go/rest/watch"
)

52
vendor/k8s.io/client-go/rest/zz_generated.deepcopy.go generated vendored Normal file
View File

@@ -0,0 +1,52 @@
// +build !ignore_autogenerated
/*
Copyright 2017 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.
*/
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
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)
}
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
}