mirror of
https://github.com/kubernetes/client-go.git
synced 2025-09-06 09:30:56 +00:00
rest.Config: support configuring an explict proxy URL
With support of http, https, and socks5 proxy support. We already support configuring this via environmnet variables, but this approach becomes inconvenient dealing with multiple clusters on different networks, that require different proxies to connect to. Most solutions require wrapping clients (like kubectl) in bash scripts. Part of: https://github.com/kubernetes/client-go/issues/351 Kubernetes-commit: f3f666d5f1f6f74a8c948a5c64af993696178244
This commit is contained in:
committed by
Kubernetes Publisher
parent
06f6a9f888
commit
0caa50056a
@@ -23,6 +23,7 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
@@ -32,12 +33,12 @@ import (
|
||||
v1 "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"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
"k8s.io/client-go/transport"
|
||||
"k8s.io/client-go/util/flowcontrol"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
fuzz "github.com/google/gofuzz"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -274,8 +275,13 @@ func (n *fakeNegotiatedSerializer) DecoderToVersion(serializer runtime.Decoder,
|
||||
var fakeDialFunc = func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return nil, fakeDialerError
|
||||
}
|
||||
|
||||
var fakeDialerError = errors.New("fakedialer")
|
||||
|
||||
func fakeProxyFunc(*http.Request) (*url.URL, error) {
|
||||
return nil, errors.New("fakeproxy")
|
||||
}
|
||||
|
||||
type fakeAuthProviderConfigPersister struct{}
|
||||
|
||||
func (fakeAuthProviderConfigPersister) Persist(map[string]string) error {
|
||||
@@ -318,8 +324,12 @@ 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(ctx context.Context, network, addr string) (net.Conn, error), f fuzz.Continue) {},
|
||||
func(r *func(ctx context.Context, network, addr string) (net.Conn, error), f fuzz.Continue) {
|
||||
*r = fakeDialFunc
|
||||
},
|
||||
func(r *func(*http.Request) (*url.URL, error), f fuzz.Continue) {
|
||||
*r = fakeProxyFunc
|
||||
},
|
||||
)
|
||||
for i := 0; i < 20; i++ {
|
||||
original := &Config{}
|
||||
@@ -350,13 +360,22 @@ func TestAnonymousConfig(t *testing.T) {
|
||||
if !reflect.DeepEqual(expectedError, actualError) {
|
||||
t.Fatalf("AnonymousClientConfig dropped the Dial field")
|
||||
}
|
||||
} else {
|
||||
actual.Dial = nil
|
||||
expected.Dial = nil
|
||||
}
|
||||
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))
|
||||
if actual.Proxy != nil {
|
||||
_, actualError := actual.Proxy(nil)
|
||||
_, expectedError := expected.Proxy(nil)
|
||||
if !reflect.DeepEqual(expectedError, actualError) {
|
||||
t.Fatalf("AnonymousClientConfig dropped the Proxy field")
|
||||
}
|
||||
}
|
||||
actual.Proxy = nil
|
||||
expected.Proxy = nil
|
||||
|
||||
if diff := cmp.Diff(*actual, expected); diff != "" {
|
||||
t.Fatalf("AnonymousClientConfig dropped unexpected fields, identify whether they are security related or not (-got, +want): %s", diff)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -396,6 +415,9 @@ func TestCopyConfig(t *testing.T) {
|
||||
func(r *func(ctx context.Context, network, addr string) (net.Conn, error), f fuzz.Continue) {
|
||||
*r = fakeDialFunc
|
||||
},
|
||||
func(r *func(*http.Request) (*url.URL, error), f fuzz.Continue) {
|
||||
*r = fakeProxyFunc
|
||||
},
|
||||
)
|
||||
for i := 0; i < 20; i++ {
|
||||
original := &Config{}
|
||||
@@ -410,10 +432,10 @@ func TestCopyConfig(t *testing.T) {
|
||||
// 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
|
||||
}
|
||||
actual.WrapTransport = nil
|
||||
expected.WrapTransport = nil
|
||||
|
||||
if actual.Dial != nil {
|
||||
_, actualError := actual.Dial(context.Background(), "", "")
|
||||
_, expectedError := expected.Dial(context.Background(), "", "")
|
||||
@@ -423,6 +445,7 @@ func TestCopyConfig(t *testing.T) {
|
||||
}
|
||||
actual.Dial = nil
|
||||
expected.Dial = nil
|
||||
|
||||
if actual.AuthConfigPersister != nil {
|
||||
actualError := actual.AuthConfigPersister.Persist(nil)
|
||||
expectedError := expected.AuthConfigPersister.Persist(nil)
|
||||
@@ -433,8 +456,18 @@ func TestCopyConfig(t *testing.T) {
|
||||
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))
|
||||
if actual.Proxy != nil {
|
||||
_, actualError := actual.Proxy(nil)
|
||||
_, expectedError := expected.Proxy(nil)
|
||||
if !reflect.DeepEqual(expectedError, actualError) {
|
||||
t.Fatalf("CopyConfig dropped the Proxy field")
|
||||
}
|
||||
}
|
||||
actual.Proxy = nil
|
||||
expected.Proxy = nil
|
||||
|
||||
if diff := cmp.Diff(*actual, expected); diff != "" {
|
||||
t.Fatalf("CopyConfig dropped unexpected fields, identify whether they are security related or not (-got, +want): %s", diff)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -564,10 +597,11 @@ func TestConfigSprint(t *testing.T) {
|
||||
RateLimiter: &fakeLimiter{},
|
||||
Timeout: 3 * time.Second,
|
||||
Dial: fakeDialFunc,
|
||||
Proxy: fakeProxyFunc,
|
||||
}
|
||||
want := fmt.Sprintf(
|
||||
`&rest.Config{Host:"localhost:8080", APIPath:"v1", ContentConfig:rest.ContentConfig{AcceptContentTypes:"application/json", ContentType:"application/json", GroupVersion:(*schema.GroupVersion)(nil), NegotiatedSerializer:runtime.NegotiatedSerializer(nil)}, Username:"gopher", Password:"--- REDACTED ---", BearerToken:"--- REDACTED ---", BearerTokenFile:"", Impersonate:rest.ImpersonationConfig{UserName:"gopher2", Groups:[]string(nil), Extra:map[string][]string(nil)}, AuthProvider:api.AuthProviderConfig{Name: "gopher", Config: map[string]string{--- REDACTED ---}}, AuthConfigPersister:rest.AuthProviderConfigPersister(--- REDACTED ---), ExecProvider:api.AuthProviderConfig{Command: "sudo", Args: []string{"--- REDACTED ---"}, Env: []ExecEnvVar{--- REDACTED ---}, APIVersion: ""}, TLSClientConfig:rest.sanitizedTLSClientConfig{Insecure:false, ServerName:"", CertFile:"a.crt", KeyFile:"a.key", CAFile:"", CertData:[]uint8{0x2d, 0x2d, 0x2d, 0x20, 0x54, 0x52, 0x55, 0x4e, 0x43, 0x41, 0x54, 0x45, 0x44, 0x20, 0x2d, 0x2d, 0x2d}, KeyData:[]uint8{0x2d, 0x2d, 0x2d, 0x20, 0x52, 0x45, 0x44, 0x41, 0x43, 0x54, 0x45, 0x44, 0x20, 0x2d, 0x2d, 0x2d}, CAData:[]uint8(nil), NextProtos:[]string{"h2", "http/1.1"}}, UserAgent:"gobot", DisableCompression:false, Transport:(*rest.fakeRoundTripper)(%p), WrapTransport:(transport.WrapperFunc)(%p), QPS:1, Burst:2, RateLimiter:(*rest.fakeLimiter)(%p), Timeout:3000000000, Dial:(func(context.Context, string, string) (net.Conn, error))(%p)}`,
|
||||
c.Transport, fakeWrapperFunc, c.RateLimiter, fakeDialFunc,
|
||||
`&rest.Config{Host:"localhost:8080", APIPath:"v1", ContentConfig:rest.ContentConfig{AcceptContentTypes:"application/json", ContentType:"application/json", GroupVersion:(*schema.GroupVersion)(nil), NegotiatedSerializer:runtime.NegotiatedSerializer(nil)}, Username:"gopher", Password:"--- REDACTED ---", BearerToken:"--- REDACTED ---", BearerTokenFile:"", Impersonate:rest.ImpersonationConfig{UserName:"gopher2", Groups:[]string(nil), Extra:map[string][]string(nil)}, AuthProvider:api.AuthProviderConfig{Name: "gopher", Config: map[string]string{--- REDACTED ---}}, AuthConfigPersister:rest.AuthProviderConfigPersister(--- REDACTED ---), ExecProvider:api.AuthProviderConfig{Command: "sudo", Args: []string{"--- REDACTED ---"}, Env: []ExecEnvVar{--- REDACTED ---}, APIVersion: ""}, TLSClientConfig:rest.sanitizedTLSClientConfig{Insecure:false, ServerName:"", CertFile:"a.crt", KeyFile:"a.key", CAFile:"", CertData:[]uint8{0x2d, 0x2d, 0x2d, 0x20, 0x54, 0x52, 0x55, 0x4e, 0x43, 0x41, 0x54, 0x45, 0x44, 0x20, 0x2d, 0x2d, 0x2d}, KeyData:[]uint8{0x2d, 0x2d, 0x2d, 0x20, 0x52, 0x45, 0x44, 0x41, 0x43, 0x54, 0x45, 0x44, 0x20, 0x2d, 0x2d, 0x2d}, CAData:[]uint8(nil), NextProtos:[]string{"h2", "http/1.1"}}, UserAgent:"gobot", DisableCompression:false, Transport:(*rest.fakeRoundTripper)(%p), WrapTransport:(transport.WrapperFunc)(%p), QPS:1, Burst:2, RateLimiter:(*rest.fakeLimiter)(%p), Timeout:3000000000, Dial:(func(context.Context, string, string) (net.Conn, error))(%p), Proxy:(func(*http.Request) (*url.URL, error))(%p)}`,
|
||||
c.Transport, fakeWrapperFunc, c.RateLimiter, fakeDialFunc, fakeProxyFunc,
|
||||
)
|
||||
|
||||
for _, f := range []string{"%s", "%v", "%+v", "%#v"} {
|
||||
|
Reference in New Issue
Block a user