Browse code

Enable protobuf for new configurations, json for old

New clusters will get protobuf intracluster, old clusters will not.

Clayton Coleman authored on 2016/07/13 12:42:37
Showing 18 changed files
... ...
@@ -440,6 +440,10 @@ func (o CreateNodeConfigOptions) MakeNodeConfig(serverCertFile, serverKeyFile, n
440 440
 	if err != nil {
441 441
 		return err
442 442
 	}
443
+	config = internal.(*configapi.NodeConfig)
444
+
445
+	// For new configurations, use protobuf.
446
+	configapi.SetProtobufClientDefaults(config.MasterClientConnectionOverrides)
443 447
 
444 448
 	content, err := latestconfigapi.WriteYAML(internal)
445 449
 	if err != nil {
... ...
@@ -289,9 +289,19 @@ func GetNodeFileReferences(config *NodeConfig) []*string {
289 289
 	return refs
290 290
 }
291 291
 
292
+// SetProtobufClientDefaults sets the appropriate content types for defaulting to protobuf
293
+// client communications and increases the default QPS and burst. This is used to override
294
+// defaulted config supporting versions older than 1.3 for new configurations generated in 1.3+.
295
+func SetProtobufClientDefaults(overrides *ClientConnectionOverrides) {
296
+	overrides.AcceptContentTypes = "application/vnd.kubernetes.protobuf,application/json"
297
+	overrides.ContentType = "application/vnd.kubernetes.protobuf"
298
+	overrides.QPS *= 2
299
+	overrides.Burst *= 2
300
+}
301
+
292 302
 // TODO: clients should be copied and instantiated from a common client config, tweaked, then
293 303
 // given to individual controllers and other infrastructure components.
294
-func GetKubeClient(kubeConfigFile string) (*kclient.Client, *restclient.Config, error) {
304
+func GetKubeClient(kubeConfigFile string, overrides *ClientConnectionOverrides) (*kclient.Client, *restclient.Config, error) {
295 305
 	loadingRules := &clientcmd.ClientConfigLoadingRules{}
296 306
 	loadingRules.ExplicitPath = kubeConfigFile
297 307
 	loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})
... ...
@@ -301,10 +311,7 @@ func GetKubeClient(kubeConfigFile string) (*kclient.Client, *restclient.Config,
301 301
 		return nil, nil, err
302 302
 	}
303 303
 
304
-	// This is an internal client which is shared by most controllers, so boost default QPS
305
-	// TODO: this should be configured by the caller, not in this method.
306
-	kubeConfig.QPS = 100.0
307
-	kubeConfig.Burst = 200
304
+	applyClientConnectionOverrides(overrides, kubeConfig)
308 305
 
309 306
 	kubeConfig.WrapTransport = DefaultClientTransport
310 307
 	kubeClient, err := kclient.New(kubeConfig)
... ...
@@ -316,8 +323,9 @@ func GetKubeClient(kubeConfigFile string) (*kclient.Client, *restclient.Config,
316 316
 }
317 317
 
318 318
 // TODO: clients should be copied and instantiated from a common client config, tweaked, then
319
-// given to individual controllers and other infrastructure components.
320
-func GetOpenShiftClient(kubeConfigFile string) (*client.Client, *restclient.Config, error) {
319
+// given to individual controllers and other infrastructure components. Overrides are optional
320
+// and may alter the default configuration.
321
+func GetOpenShiftClient(kubeConfigFile string, overrides *ClientConnectionOverrides) (*client.Client, *restclient.Config, error) {
321 322
 	loadingRules := &clientcmd.ClientConfigLoadingRules{}
322 323
 	loadingRules.ExplicitPath = kubeConfigFile
323 324
 	loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})
... ...
@@ -327,10 +335,7 @@ func GetOpenShiftClient(kubeConfigFile string) (*client.Client, *restclient.Conf
327 327
 		return nil, nil, err
328 328
 	}
329 329
 
330
-	// This is an internal client which is shared by most controllers, so boost default QPS
331
-	// TODO: this should be configured by the caller, not in this method.
332
-	kubeConfig.QPS = 150.0
333
-	kubeConfig.Burst = 300
330
+	applyClientConnectionOverrides(overrides, kubeConfig)
334 331
 
335 332
 	kubeConfig.WrapTransport = DefaultClientTransport
336 333
 	openshiftClient, err := client.New(kubeConfig)
... ...
@@ -341,6 +346,17 @@ func GetOpenShiftClient(kubeConfigFile string) (*client.Client, *restclient.Conf
341 341
 	return openshiftClient, kubeConfig, nil
342 342
 }
343 343
 
344
+// applyClientConnectionOverrides updates a kubeConfig with the overrides from the config.
345
+func applyClientConnectionOverrides(overrides *ClientConnectionOverrides, kubeConfig *restclient.Config) {
346
+	if overrides == nil {
347
+		return
348
+	}
349
+	kubeConfig.QPS = overrides.QPS
350
+	kubeConfig.Burst = int(overrides.Burst)
351
+	kubeConfig.ContentConfig.AcceptContentTypes = overrides.AcceptContentTypes
352
+	kubeConfig.ContentConfig.ContentType = overrides.ContentType
353
+}
354
+
344 355
 // DefaultClientTransport sets defaults for a client Transport that are suitable
345 356
 // for use by infrastructure components.
346 357
 func DefaultClientTransport(rt http.RoundTripper) http.RoundTripper {
... ...
@@ -50,6 +50,35 @@ func fuzzInternalObject(t *testing.T, forVersion unversioned.GroupVersion, item
50 50
 				obj.RoutingConfig.Subdomain = "router.default.svc.cluster.local"
51 51
 			}
52 52
 
53
+			if obj.MasterClients.OpenShiftLoopbackClientConnectionOverrides == nil {
54
+				obj.MasterClients.OpenShiftLoopbackClientConnectionOverrides = &configapi.ClientConnectionOverrides{
55
+					QPS:                2.0,
56
+					Burst:              2,
57
+					AcceptContentTypes: "test/second",
58
+					ContentType:        "test/first",
59
+				}
60
+			}
61
+			if len(obj.MasterClients.OpenShiftLoopbackClientConnectionOverrides.AcceptContentTypes) == 0 {
62
+				obj.MasterClients.OpenShiftLoopbackClientConnectionOverrides.AcceptContentTypes = "test/fourth"
63
+			}
64
+			if len(obj.MasterClients.OpenShiftLoopbackClientConnectionOverrides.ContentType) == 0 {
65
+				obj.MasterClients.OpenShiftLoopbackClientConnectionOverrides.ContentType = "test/fifth"
66
+			}
67
+			if obj.MasterClients.ExternalKubernetesClientConnectionOverrides == nil {
68
+				obj.MasterClients.ExternalKubernetesClientConnectionOverrides = &configapi.ClientConnectionOverrides{
69
+					QPS:                1.0,
70
+					Burst:              1,
71
+					AcceptContentTypes: "test/other",
72
+					ContentType:        "test/third",
73
+				}
74
+			}
75
+			if len(obj.MasterClients.ExternalKubernetesClientConnectionOverrides.AcceptContentTypes) == 0 {
76
+				obj.MasterClients.ExternalKubernetesClientConnectionOverrides.AcceptContentTypes = "test/fourth"
77
+			}
78
+			if len(obj.MasterClients.ExternalKubernetesClientConnectionOverrides.ContentType) == 0 {
79
+				obj.MasterClients.ExternalKubernetesClientConnectionOverrides.ContentType = "test/fifth"
80
+			}
81
+
53 82
 			// Populate the new NetworkConfig.ServiceNetworkCIDR field from the KubernetesMasterConfig.ServicesSubnet field if needed
54 83
 			if len(obj.NetworkConfig.ServiceNetworkCIDR) == 0 {
55 84
 				if obj.KubernetesMasterConfig != nil && len(obj.KubernetesMasterConfig.ServicesSubnet) > 0 {
... ...
@@ -143,6 +172,21 @@ func fuzzInternalObject(t *testing.T, forVersion unversioned.GroupVersion, item
143 143
 				obj.IPTablesSyncPeriod = "5s"
144 144
 			}
145 145
 
146
+			if obj.MasterClientConnectionOverrides == nil {
147
+				obj.MasterClientConnectionOverrides = &configapi.ClientConnectionOverrides{
148
+					QPS:                1.0,
149
+					Burst:              1,
150
+					AcceptContentTypes: "test/other",
151
+					ContentType:        "test/third",
152
+				}
153
+			}
154
+			if len(obj.MasterClientConnectionOverrides.AcceptContentTypes) == 0 {
155
+				obj.MasterClientConnectionOverrides.AcceptContentTypes = "test/fourth"
156
+			}
157
+			if len(obj.MasterClientConnectionOverrides.ContentType) == 0 {
158
+				obj.MasterClientConnectionOverrides.ContentType = "test/fifth"
159
+			}
160
+
146 161
 			// Auth cache defaults
147 162
 			if len(obj.AuthConfig.AuthenticationCacheTTL) == 0 {
148 163
 				obj.AuthConfig.AuthenticationCacheTTL = "5m"
... ...
@@ -100,6 +100,9 @@ type NodeConfig struct {
100 100
 	// MasterKubeConfig is a filename for the .kubeconfig file that describes how to connect this node to the master
101 101
 	MasterKubeConfig string
102 102
 
103
+	// MasterClientConnectionOverrides provides overrides to the client connection used to connect to the master.
104
+	MasterClientConnectionOverrides *ClientConnectionOverrides
105
+
103 106
 	// DNSDomain holds the domain suffix
104 107
 	DNSDomain string
105 108
 
... ...
@@ -539,6 +542,25 @@ type MasterClients struct {
539 539
 	OpenShiftLoopbackKubeConfig string
540 540
 	// ExternalKubernetesKubeConfig is a .kubeconfig filename for proxying to kubernetes
541 541
 	ExternalKubernetesKubeConfig string
542
+
543
+	// OpenShiftLoopbackClientConnectionOverrides specifies client overrides for system components to loop back to this master.
544
+	OpenShiftLoopbackClientConnectionOverrides *ClientConnectionOverrides
545
+	// ExternalKubernetesClientConnectionOverrides specifies client overrides for proxying to Kubernetes.
546
+	ExternalKubernetesClientConnectionOverrides *ClientConnectionOverrides
547
+}
548
+
549
+type ClientConnectionOverrides struct {
550
+	// AcceptContentTypes defines the Accept header sent by clients when connecting to a server, overriding the
551
+	// default value of 'application/json'. This field will control all connections to the server used by a particular
552
+	// client.
553
+	AcceptContentTypes string
554
+	// ContentType is the content type used when sending data to the server from this client.
555
+	ContentType string
556
+
557
+	// QPS controls the number of queries per second allowed for this connection.
558
+	QPS float32
559
+	// Burst allows extra queries to accumulate when a client is exceeding its rate.
560
+	Burst int32
542 561
 }
543 562
 
544 563
 type DNSConfig struct {
... ...
@@ -46,6 +46,23 @@ func addDefaultingFuncs(scheme *runtime.Scheme) {
46 46
 				obj.JenkinsPipelineConfig.Enabled = &v
47 47
 			}
48 48
 
49
+			if obj.MasterClients.OpenShiftLoopbackClientConnectionOverrides == nil {
50
+				obj.MasterClients.OpenShiftLoopbackClientConnectionOverrides = &ClientConnectionOverrides{
51
+					// historical values
52
+					QPS:   150.0,
53
+					Burst: 300,
54
+				}
55
+			}
56
+			setDefault_ClientConnectionOverrides(obj.MasterClients.OpenShiftLoopbackClientConnectionOverrides)
57
+			if obj.MasterClients.ExternalKubernetesClientConnectionOverrides == nil {
58
+				obj.MasterClients.ExternalKubernetesClientConnectionOverrides = &ClientConnectionOverrides{
59
+					// historical values
60
+					QPS:   100.0,
61
+					Burst: 200,
62
+				}
63
+			}
64
+			setDefault_ClientConnectionOverrides(obj.MasterClients.ExternalKubernetesClientConnectionOverrides)
65
+
49 66
 			// Populate the new NetworkConfig.ServiceNetworkCIDR field from the KubernetesMasterConfig.ServicesSubnet field if needed
50 67
 			if len(obj.NetworkConfig.ServiceNetworkCIDR) == 0 {
51 68
 				if obj.KubernetesMasterConfig != nil && len(obj.KubernetesMasterConfig.ServicesSubnet) > 0 {
... ...
@@ -80,6 +97,15 @@ func addDefaultingFuncs(scheme *runtime.Scheme) {
80 80
 			}
81 81
 		},
82 82
 		func(obj *NodeConfig) {
83
+			if obj.MasterClientConnectionOverrides == nil {
84
+				obj.MasterClientConnectionOverrides = &ClientConnectionOverrides{
85
+					// historical values
86
+					QPS:   10.0,
87
+					Burst: 20,
88
+				}
89
+			}
90
+			setDefault_ClientConnectionOverrides(obj.MasterClientConnectionOverrides)
91
+
83 92
 			// Defaults/migrations for NetworkConfig
84 93
 			if len(obj.NetworkConfig.NetworkPluginName) == 0 {
85 94
 				obj.NetworkConfig.NetworkPluginName = obj.DeprecatedNetworkPluginName
... ...
@@ -309,6 +335,17 @@ func convert_runtime_RawExtension_To_runtime_Object(in *runtime.RawExtension, ou
309 309
 	return extension.Convert_runtime_RawExtension_To_runtime_Object(internal.Scheme, in, out, s)
310 310
 }
311 311
 
312
+// setDefault_ClientConnectionOverrides defaults a client connection to the pre-1.3 settings of
313
+// being JSON only. Callers must explicitly opt-in to Protobuf support in 1.3+.
314
+func setDefault_ClientConnectionOverrides(overrides *ClientConnectionOverrides) {
315
+	if len(overrides.AcceptContentTypes) == 0 {
316
+		overrides.AcceptContentTypes = "application/json"
317
+	}
318
+	if len(overrides.ContentType) == 0 {
319
+		overrides.ContentType = "application/json"
320
+	}
321
+}
322
+
312 323
 var _ runtime.NestedObjectDecoder = &MasterConfig{}
313 324
 
314 325
 // DecodeNestedObjects handles encoding RawExtensions on the MasterConfig, ensuring the
... ...
@@ -26,6 +26,9 @@ type NodeConfig struct {
26 26
 	// MasterKubeConfig is a filename for the .kubeconfig file that describes how to connect this node to the master
27 27
 	MasterKubeConfig string `json:"masterKubeConfig"`
28 28
 
29
+	// MasterClientConnectionOverrides provides overrides to the client connection used to connect to the master.
30
+	MasterClientConnectionOverrides *ClientConnectionOverrides `json:"masterClientConnectionOverrides"`
31
+
29 32
 	// DNSDomain holds the domain suffix
30 33
 	DNSDomain string `json:"dnsDomain"`
31 34
 
... ...
@@ -501,8 +504,28 @@ type HTTPServingInfo struct {
501 501
 type MasterClients struct {
502 502
 	// OpenShiftLoopbackKubeConfig is a .kubeconfig filename for system components to loopback to this master
503 503
 	OpenShiftLoopbackKubeConfig string `json:"openshiftLoopbackKubeConfig"`
504
-	// ExternalKubernetesKubeConfig is a .kubeconfig filename for proxying to kubernetes
504
+	// ExternalKubernetesKubeConfig is a .kubeconfig filename for proxying to Kubernetes
505 505
 	ExternalKubernetesKubeConfig string `json:"externalKubernetesKubeConfig"`
506
+
507
+	// OpenShiftLoopbackClientConnectionOverrides specifies client overrides for system components to loop back to this master.
508
+	OpenShiftLoopbackClientConnectionOverrides *ClientConnectionOverrides `json:"openshiftLoopbackClientConnectionOverrides"`
509
+	// ExternalKubernetesClientConnectionOverrides specifies client overrides for proxying to Kubernetes.
510
+	ExternalKubernetesClientConnectionOverrides *ClientConnectionOverrides `json:"externalKubernetesClientConnectionOverrides"`
511
+}
512
+
513
+// ClientConnectionOverrides are a set of overrides to the default client connection settings.
514
+type ClientConnectionOverrides struct {
515
+	// AcceptContentTypes defines the Accept header sent by clients when connecting to a server, overriding the
516
+	// default value of 'application/json'. This field will control all connections to the server used by a particular
517
+	// client.
518
+	AcceptContentTypes string `json:"acceptContentTypes"`
519
+	// ContentType is the content type used when sending data to the server from this client.
520
+	ContentType string `json:"contentType"`
521
+
522
+	// QPS controls the number of queries per second allowed for this connection.
523
+	QPS float32 `json:"qps"`
524
+	// Burst allows extra queries to accumulate when a client is exceeding its rate.
525
+	Burst int32 `json:"burst"`
506 526
 }
507 527
 
508 528
 // DNSConfig holds the necessary configuration options for DNS
... ...
@@ -40,6 +40,7 @@ imageConfig:
40 40
   latest: false
41 41
 iptablesSyncPeriod: ""
42 42
 kind: NodeConfig
43
+masterClientConnectionOverrides: null
43 44
 masterKubeConfig: ""
44 45
 networkConfig:
45 46
   mtu: 0
... ...
@@ -188,7 +189,9 @@ kubernetesMasterConfig:
188 188
   servicesSubnet: ""
189 189
   staticNodeNames: null
190 190
 masterClients:
191
+  externalKubernetesClientConnectionOverrides: null
191 192
   externalKubernetesKubeConfig: ""
193
+  openshiftLoopbackClientConnectionOverrides: null
192 194
   openshiftLoopbackKubeConfig: ""
193 195
 masterPublicURL: ""
194 196
 networkConfig:
... ...
@@ -81,16 +81,16 @@ type NodeConfig struct {
81 81
 }
82 82
 
83 83
 func BuildKubernetesNodeConfig(options configapi.NodeConfig, enableProxy, enableDNS bool) (*NodeConfig, error) {
84
-	originClient, _, err := configapi.GetOpenShiftClient(options.MasterKubeConfig)
84
+	originClient, _, err := configapi.GetOpenShiftClient(options.MasterKubeConfig, options.MasterClientConnectionOverrides)
85 85
 	if err != nil {
86 86
 		return nil, err
87 87
 	}
88
-	kubeClient, _, err := configapi.GetKubeClient(options.MasterKubeConfig)
88
+	kubeClient, _, err := configapi.GetKubeClient(options.MasterKubeConfig, options.MasterClientConnectionOverrides)
89 89
 	if err != nil {
90 90
 		return nil, err
91 91
 	}
92 92
 	// Make a separate client for event reporting, to avoid event QPS blocking node calls
93
-	eventClient, _, err := configapi.GetKubeClient(options.MasterKubeConfig)
93
+	eventClient, _, err := configapi.GetKubeClient(options.MasterKubeConfig, options.MasterClientConnectionOverrides)
94 94
 	if err != nil {
95 95
 		return nil, err
96 96
 	}
... ...
@@ -180,11 +180,11 @@ func BuildMasterConfig(options configapi.MasterConfig) (*MasterConfig, error) {
180 180
 		return nil, err
181 181
 	}
182 182
 
183
-	privilegedLoopbackKubeClient, _, err := configapi.GetKubeClient(options.MasterClients.OpenShiftLoopbackKubeConfig)
183
+	privilegedLoopbackKubeClient, _, err := configapi.GetKubeClient(options.MasterClients.OpenShiftLoopbackKubeConfig, options.MasterClients.OpenShiftLoopbackClientConnectionOverrides)
184 184
 	if err != nil {
185 185
 		return nil, err
186 186
 	}
187
-	privilegedLoopbackOpenShiftClient, privilegedLoopbackClientConfig, err := configapi.GetOpenShiftClient(options.MasterClients.OpenShiftLoopbackKubeConfig)
187
+	privilegedLoopbackOpenShiftClient, privilegedLoopbackClientConfig, err := configapi.GetOpenShiftClient(options.MasterClients.OpenShiftLoopbackKubeConfig, options.MasterClients.OpenShiftLoopbackClientConnectionOverrides)
188 188
 	if err != nil {
189 189
 		return nil, err
190 190
 	}
... ...
@@ -530,7 +530,7 @@ func newServiceAccountTokenGetter(options configapi.MasterConfig, client newetcd
530 530
 	if options.KubernetesMasterConfig == nil {
531 531
 		// When we're running against an external Kubernetes, use the external kubernetes client to validate service account tokens
532 532
 		// This prevents infinite auth loops if the privilegedLoopbackKubeClient authenticates using a service account token
533
-		kubeClient, _, err := configapi.GetKubeClient(options.MasterClients.ExternalKubernetesKubeConfig)
533
+		kubeClient, _, err := configapi.GetKubeClient(options.MasterClients.ExternalKubernetesKubeConfig, options.MasterClients.ExternalKubernetesClientConnectionOverrides)
534 534
 		if err != nil {
535 535
 			return nil, err
536 536
 		}
... ...
@@ -302,7 +302,7 @@ func (c *MasterConfig) RunDeploymentController() {
302 302
 	podInformer := c.Informers.Pods().Informer()
303 303
 	_, kclient := c.DeploymentControllerClients()
304 304
 
305
-	_, kclientConfig, err := configapi.GetKubeClient(c.Options.MasterClients.OpenShiftLoopbackKubeConfig)
305
+	_, kclientConfig, err := configapi.GetKubeClient(c.Options.MasterClients.OpenShiftLoopbackKubeConfig, c.Options.MasterClients.OpenShiftLoopbackClientConnectionOverrides)
306 306
 	if err != nil {
307 307
 		glog.Fatalf("Unable to initialize deployment controller: %v", err)
308 308
 	}
... ...
@@ -318,8 +318,13 @@ func (args MasterArgs) BuildSerializeableMasterConfig() (*configapi.MasterConfig
318 318
 	if err != nil {
319 319
 		return nil, err
320 320
 	}
321
+	config = internal.(*configapi.MasterConfig)
321 322
 
322
-	return internal.(*configapi.MasterConfig), nil
323
+	// When creating a new config, use Protobuf
324
+	configapi.SetProtobufClientDefaults(config.MasterClients.OpenShiftLoopbackClientConnectionOverrides)
325
+	configapi.SetProtobufClientDefaults(config.MasterClients.ExternalKubernetesClientConnectionOverrides)
326
+
327
+	return config, nil
323 328
 }
324 329
 
325 330
 func (args MasterArgs) BuildSerializeableOAuthConfig() (*configapi.OAuthConfig, error) {
... ...
@@ -156,6 +156,7 @@ func ValidateRuntime(config *configapi.NodeConfig, components *utilflags.Compone
156 156
 
157 157
 // BuildSerializeableNodeConfig takes the NodeArgs (partially complete config) and uses them along with defaulting behavior to create the fully specified
158 158
 // config object for starting the node
159
+// TODO: reconcile that this is not used by CreateNodeConfig in all-in-one start.
159 160
 func (args NodeArgs) BuildSerializeableNodeConfig() (*configapi.NodeConfig, error) {
160 161
 	var dnsIP string
161 162
 	if len(args.ClusterDNS) > 0 {
... ...
@@ -198,8 +199,12 @@ func (args NodeArgs) BuildSerializeableNodeConfig() (*configapi.NodeConfig, erro
198 198
 	if err != nil {
199 199
 		return nil, err
200 200
 	}
201
+	config = internal.(*configapi.NodeConfig)
201 202
 
202
-	return internal.(*configapi.NodeConfig), nil
203
+	// When creating a new config, use Protobuf
204
+	configapi.SetProtobufClientDefaults(config.MasterClientConnectionOverrides)
205
+
206
+	return config, nil
203 207
 }
204 208
 
205 209
 // GetServerCertHostnames returns the set of hostnames and IP addresses a serving certificate for node on this host might need to be valid for.
... ...
@@ -497,7 +497,7 @@ func StartAPI(oc *origin.MasterConfig, kc *kubernetes.MasterConfig) error {
497 497
 	if kc != nil {
498 498
 		oc.Run([]origin.APIInstaller{kc}, unprotectedInstallers)
499 499
 	} else {
500
-		_, kubeClientConfig, err := configapi.GetKubeClient(oc.Options.MasterClients.ExternalKubernetesKubeConfig)
500
+		_, kubeClientConfig, err := configapi.GetKubeClient(oc.Options.MasterClients.ExternalKubernetesKubeConfig, oc.Options.MasterClients.ExternalKubernetesClientConnectionOverrides)
501 501
 		if err != nil {
502 502
 			return err
503 503
 		}
... ...
@@ -302,7 +302,7 @@ func StartNode(nodeConfig configapi.NodeConfig, components *utilflags.ComponentF
302 302
 		glog.Infof("Starting node networking %s (%s)", config.KubeletServer.HostnameOverride, version.Get().String())
303 303
 	}
304 304
 
305
-	_, kubeClientConfig, err := configapi.GetKubeClient(nodeConfig.MasterKubeConfig)
305
+	_, kubeClientConfig, err := configapi.GetKubeClient(nodeConfig.MasterKubeConfig, nodeConfig.MasterClientConnectionOverrides)
306 306
 	if err != nil {
307 307
 		return err
308 308
 	}
... ...
@@ -174,7 +174,7 @@ func (c *CLI) Verbose() *CLI {
174 174
 // REST provides an OpenShift REST client for the current user. If the user is not
175 175
 // set, then it provides REST client for the cluster admin user
176 176
 func (c *CLI) REST() *client.Client {
177
-	_, clientConfig, err := configapi.GetKubeClient(c.configPath)
177
+	_, clientConfig, err := configapi.GetKubeClient(c.configPath, nil)
178 178
 	osClient, err := client.New(clientConfig)
179 179
 	if err != nil {
180 180
 		FatalErr(err)
... ...
@@ -184,7 +184,7 @@ func (c *CLI) REST() *client.Client {
184 184
 
185 185
 // AdminREST provides an OpenShift REST client for the cluster admin user.
186 186
 func (c *CLI) AdminREST() *client.Client {
187
-	_, clientConfig, err := configapi.GetKubeClient(c.adminConfigPath)
187
+	_, clientConfig, err := configapi.GetKubeClient(c.adminConfigPath, nil)
188 188
 	osClient, err := client.New(clientConfig)
189 189
 	if err != nil {
190 190
 		FatalErr(err)
... ...
@@ -194,7 +194,7 @@ func (c *CLI) AdminREST() *client.Client {
194 194
 
195 195
 // KubeREST provides a Kubernetes REST client for the current namespace
196 196
 func (c *CLI) KubeREST() *kclient.Client {
197
-	kubeClient, _, err := configapi.GetKubeClient(c.configPath)
197
+	kubeClient, _, err := configapi.GetKubeClient(c.configPath, nil)
198 198
 	if err != nil {
199 199
 		FatalErr(err)
200 200
 	}
... ...
@@ -203,7 +203,7 @@ func (c *CLI) KubeREST() *kclient.Client {
203 203
 
204 204
 // AdminKubeREST provides a Kubernetes REST client for the cluster admin user.
205 205
 func (c *CLI) AdminKubeREST() *kclient.Client {
206
-	kubeClient, _, err := configapi.GetKubeClient(c.adminConfigPath)
206
+	kubeClient, _, err := configapi.GetKubeClient(c.adminConfigPath, nil)
207 207
 	if err != nil {
208 208
 		FatalErr(err)
209 209
 	}
... ...
@@ -174,7 +174,7 @@ func createTestingNS(baseName string, c *kclient.Client, labels map[string]strin
174 174
 
175 175
 		// The intra-pod test requires that the service account have
176 176
 		// permission to retrieve service endpoints.
177
-		osClient, _, err := configapi.GetOpenShiftClient(KubeConfigPath())
177
+		osClient, _, err := configapi.GetOpenShiftClient(KubeConfigPath(), nil)
178 178
 		if err != nil {
179 179
 			return ns, err
180 180
 		}
... ...
@@ -32,7 +32,7 @@ func KubeConfigPath() string {
32 32
 }
33 33
 
34 34
 func GetClusterAdminKubeClient(adminKubeConfigFile string) (*kclient.Client, error) {
35
-	c, _, err := configapi.GetKubeClient(adminKubeConfigFile)
35
+	c, _, err := configapi.GetKubeClient(adminKubeConfigFile, nil)
36 36
 	if err != nil {
37 37
 		return nil, err
38 38
 	}
... ...
@@ -52,7 +52,7 @@ func GetClusterAdminClient(adminKubeConfigFile string) (*client.Client, error) {
52 52
 }
53 53
 
54 54
 func GetClusterAdminClientConfig(adminKubeConfigFile string) (*restclient.Config, error) {
55
-	_, conf, err := configapi.GetKubeClient(adminKubeConfigFile)
55
+	_, conf, err := configapi.GetKubeClient(adminKubeConfigFile, nil)
56 56
 	if err != nil {
57 57
 		return nil, err
58 58
 	}
... ...
@@ -94,7 +94,11 @@ func DumpEtcdOnFailure(t *testing.T) {
94 94
 	pc := make([]uintptr, 10)
95 95
 	goruntime.Callers(2, pc)
96 96
 	f := goruntime.FuncForPC(pc[0])
97
-	name := f.Name()[strings.LastIndex(f.Name(), "Test"):]
97
+	last := strings.LastIndex(f.Name(), "Test")
98
+	if last == -1 {
99
+		last = 0
100
+	}
101
+	name := f.Name()[last:]
98 102
 
99 103
 	client := NewEtcdClient()
100 104
 	etcdResponse, err := client.RawGet("/", false, true)