Skip to content

Commit e424441

Browse files
committed
make *http.Client configurable
Signed-off-by: Tim Ramlot <[email protected]>
1 parent e1fd8e7 commit e424441

18 files changed

+167
-49
lines changed

pkg/cache/cache.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package cache
1919
import (
2020
"context"
2121
"fmt"
22+
"net/http"
2223
"reflect"
2324
"time"
2425

@@ -108,6 +109,9 @@ type SelectorsByObject map[client.Object]ObjectSelector
108109

109110
// Options are the optional arguments for creating a new InformersMap object.
110111
type Options struct {
112+
// HTTPClient is the http client to use for the REST client
113+
HTTPClient *http.Client
114+
111115
// Scheme is the scheme to use for mapping objects to GroupVersionKinds
112116
Scheme *runtime.Scheme
113117

@@ -184,6 +188,7 @@ func New(config *rest.Config, opts Options) (Cache, error) {
184188
return &informerCache{
185189
scheme: opts.Scheme,
186190
Informers: internal.NewInformers(config, &internal.InformersOpts{
191+
HTTPClient: opts.HTTPClient,
187192
Scheme: opts.Scheme,
188193
Mapper: opts.Mapper,
189194
ResyncPeriod: *opts.Resync,
@@ -414,6 +419,16 @@ func combineTransform(inherited, current toolscache.TransformFunc) toolscache.Tr
414419
}
415420

416421
func defaultOpts(config *rest.Config, opts Options) (Options, error) {
422+
// Use the rest HTTP client for the provided config if unset
423+
if opts.HTTPClient == nil {
424+
var err error
425+
opts.HTTPClient, err = rest.HTTPClientFor(config)
426+
if err != nil {
427+
log.WithName("setup").Error(err, "Failed to get HTTP client")
428+
return opts, fmt.Errorf("could not create HTTP client from config")
429+
}
430+
}
431+
417432
// Use the default Kubernetes Scheme if unset
418433
if opts.Scheme == nil {
419434
opts.Scheme = scheme.Scheme
@@ -422,7 +437,7 @@ func defaultOpts(config *rest.Config, opts Options) (Options, error) {
422437
// Construct a new Mapper if unset
423438
if opts.Mapper == nil {
424439
var err error
425-
opts.Mapper, err = apiutil.NewDiscoveryRESTMapper(config)
440+
opts.Mapper, err = apiutil.NewDiscoveryRESTMapper(config, opts.HTTPClient)
426441
if err != nil {
427442
log.WithName("setup").Error(err, "Failed to get API Group-Resources")
428443
return opts, fmt.Errorf("could not create RESTMapper from config")

pkg/cache/informer_cache_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ var _ = Describe("informerCache", func() {
3131
It("should not require LeaderElection", func() {
3232
cfg := &rest.Config{}
3333

34-
mapper, err := apiutil.NewDynamicRESTMapper(cfg, apiutil.WithLazyDiscovery)
34+
mapper, err := apiutil.NewDynamicRESTMapper(cfg, nil, apiutil.WithLazyDiscovery)
3535
Expect(err).ToNot(HaveOccurred())
3636

3737
c, err := cache.New(cfg, cache.Options{Mapper: mapper})

pkg/cache/internal/informers.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"context"
2121
"fmt"
2222
"math/rand"
23+
"net/http"
2324
"sync"
2425
"time"
2526

@@ -44,6 +45,7 @@ func init() {
4445

4546
// InformersOpts configures an InformerMap.
4647
type InformersOpts struct {
48+
HTTPClient *http.Client
4749
Scheme *runtime.Scheme
4850
Mapper meta.RESTMapper
4951
ResyncPeriod time.Duration
@@ -62,9 +64,10 @@ type InformersOptsByGVK struct {
6264
// NewInformers creates a new InformersMap that can create informers under the hood.
6365
func NewInformers(config *rest.Config, options *InformersOpts) *Informers {
6466
return &Informers{
65-
config: config,
66-
scheme: options.Scheme,
67-
mapper: options.Mapper,
67+
config: config,
68+
httpClient: options.HTTPClient,
69+
scheme: options.Scheme,
70+
mapper: options.Mapper,
6871
tracker: tracker{
6972
Structured: make(map[schema.GroupVersionKind]*Cache),
7073
Unstructured: make(map[schema.GroupVersionKind]*Cache),
@@ -99,6 +102,9 @@ type tracker struct {
99102
// Informers create and caches Informers for (runtime.Object, schema.GroupVersionKind) pairs.
100103
// It uses a standard parameter codec constructed based on the given generated Scheme.
101104
type Informers struct {
105+
// httpClient is used to create a new REST client
106+
httpClient *http.Client
107+
102108
// scheme maps runtime.Objects to GroupVersionKinds
103109
scheme *runtime.Scheme
104110

@@ -364,7 +370,7 @@ func (ip *Informers) makeListWatcher(gvk schema.GroupVersionKind, obj runtime.Ob
364370
// we should remove it and use the one that the dynamic client sets for us.
365371
cfg := rest.CopyConfig(ip.config)
366372
cfg.NegotiatedSerializer = nil
367-
dynamicClient, err := dynamic.NewForConfig(cfg)
373+
dynamicClient, err := dynamic.NewForConfigAndClient(cfg, ip.httpClient)
368374
if err != nil {
369375
return nil, err
370376
}
@@ -394,7 +400,7 @@ func (ip *Informers) makeListWatcher(gvk schema.GroupVersionKind, obj runtime.Ob
394400
cfg.NegotiatedSerializer = nil
395401

396402
// Grab the metadata metadataClient.
397-
metadataClient, err := metadata.NewForConfig(cfg)
403+
metadataClient, err := metadata.NewForConfigAndClient(cfg, ip.httpClient)
398404
if err != nil {
399405
return nil, err
400406
}
@@ -435,7 +441,7 @@ func (ip *Informers) makeListWatcher(gvk schema.GroupVersionKind, obj runtime.Ob
435441
// Structured.
436442
//
437443
default:
438-
client, err := apiutil.RESTClientForGVK(gvk, false, ip.config, ip.codecs)
444+
client, err := apiutil.RESTClientForGVK(gvk, false, ip.config, ip.codecs, ip.httpClient)
439445
if err != nil {
440446
return nil, err
441447
}

pkg/client/apiutil/apimachinery.go

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ package apiutil
2121

2222
import (
2323
"fmt"
24+
"net/http"
2425
"reflect"
2526
"sync"
2627

@@ -59,9 +60,13 @@ func AddToProtobufScheme(addToScheme func(*runtime.Scheme) error) error {
5960

6061
// NewDiscoveryRESTMapper constructs a new RESTMapper based on discovery
6162
// information fetched by a new client with the given config.
62-
func NewDiscoveryRESTMapper(c *rest.Config) (meta.RESTMapper, error) {
63+
func NewDiscoveryRESTMapper(c *rest.Config, httpClient *http.Client) (meta.RESTMapper, error) {
64+
if err := DefaultHTTPClient(c, &httpClient); err != nil {
65+
return nil, err
66+
}
67+
6368
// Get a mapper
64-
dc, err := discovery.NewDiscoveryClientForConfig(c)
69+
dc, err := discovery.NewDiscoveryClientForConfigAndClient(c, httpClient)
6570
if err != nil {
6671
return nil, err
6772
}
@@ -115,11 +120,29 @@ func GVKForObject(obj runtime.Object, scheme *runtime.Scheme) (schema.GroupVersi
115120
return gvks[0], nil
116121
}
117122

123+
// DefaultHTTPClient is a helper function that sets the HTTP client based on a rest config if it is not already set.
124+
func DefaultHTTPClient(config *rest.Config, httpClient **http.Client) error {
125+
if httpClient == nil {
126+
panic("httpClient must not be nil")
127+
}
128+
129+
if *httpClient != nil {
130+
return nil
131+
}
132+
133+
var err error
134+
*httpClient, err = rest.HTTPClientFor(config)
135+
return err
136+
}
137+
118138
// RESTClientForGVK constructs a new rest.Interface capable of accessing the resource associated
119139
// with the given GroupVersionKind. The REST client will be configured to use the negotiated serializer from
120140
// baseConfig, if set, otherwise a default serializer will be set.
121-
func RESTClientForGVK(gvk schema.GroupVersionKind, isUnstructured bool, baseConfig *rest.Config, codecs serializer.CodecFactory) (rest.Interface, error) {
122-
return rest.RESTClientFor(createRestConfig(gvk, isUnstructured, baseConfig, codecs))
141+
func RESTClientForGVK(gvk schema.GroupVersionKind, isUnstructured bool, baseConfig *rest.Config, codecs serializer.CodecFactory, httpClient *http.Client) (rest.Interface, error) {
142+
if err := DefaultHTTPClient(baseConfig, &httpClient); err != nil {
143+
return nil, err
144+
}
145+
return rest.RESTClientForConfigAndClient(createRestConfig(gvk, isUnstructured, baseConfig, codecs), httpClient)
123146
}
124147

125148
// serializerWithDecodedGVK is a CodecFactory that overrides the DecoderToVersion of a WithoutConversionCodecFactory

pkg/client/apiutil/dynamicrestmapper.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package apiutil
1818

1919
import (
20+
"net/http"
2021
"sync"
2122
"sync/atomic"
2223

@@ -75,8 +76,12 @@ func WithCustomMapper(newMapper func() (meta.RESTMapper, error)) DynamicRESTMapp
7576
// NewDynamicRESTMapper returns a dynamic RESTMapper for cfg. The dynamic
7677
// RESTMapper dynamically discovers resource types at runtime. opts
7778
// configure the RESTMapper.
78-
func NewDynamicRESTMapper(cfg *rest.Config, opts ...DynamicRESTMapperOption) (meta.RESTMapper, error) {
79-
client, err := discovery.NewDiscoveryClientForConfig(cfg)
79+
func NewDynamicRESTMapper(cfg *rest.Config, httpClient *http.Client, opts ...DynamicRESTMapperOption) (meta.RESTMapper, error) {
80+
if err := DefaultHTTPClient(cfg, &httpClient); err != nil {
81+
return nil, err
82+
}
83+
84+
client, err := discovery.NewDiscoveryClientForConfigAndClient(cfg, httpClient)
8085
if err != nil {
8186
return nil, err
8287
}

pkg/client/apiutil/dynamicrestmapper_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ var _ = Describe("Dynamic REST Mapper", func() {
5151
}
5252

5353
lim = rate.NewLimiter(rate.Limit(5), 5)
54-
mapper, err = NewDynamicRESTMapper(cfg, WithLimiter(lim), WithCustomMapper(func() (meta.RESTMapper, error) {
54+
mapper, err = NewDynamicRESTMapper(cfg, nil, WithLimiter(lim), WithCustomMapper(func() (meta.RESTMapper, error) {
5555
baseMapper := meta.NewDefaultRESTMapper(nil)
5656
addToMapper(baseMapper)
5757

@@ -150,7 +150,7 @@ var _ = Describe("Dynamic REST Mapper", func() {
150150
var err error
151151
var failedOnce bool
152152
mockErr := fmt.Errorf("mock failed once")
153-
mapper, err = NewDynamicRESTMapper(cfg, WithLazyDiscovery, WithCustomMapper(func() (meta.RESTMapper, error) {
153+
mapper, err = NewDynamicRESTMapper(cfg, nil, WithLazyDiscovery, WithCustomMapper(func() (meta.RESTMapper, error) {
154154
// Make newMapper fail once
155155
if !failedOnce {
156156
failedOnce = true

pkg/client/client.go

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"context"
2121
"errors"
2222
"fmt"
23+
"net/http"
2324
"strings"
2425

2526
"k8s.io/apimachinery/pkg/api/meta"
@@ -52,6 +53,9 @@ type WarningHandlerOptions struct {
5253

5354
// Options are creation options for a Client.
5455
type Options struct {
56+
// HTTPClient is the http client to use for the REST client
57+
HTTPClient *http.Client
58+
5559
// Scheme, if provided, will be used to map go structs to GroupVersionKinds
5660
Scheme *runtime.Scheme
5761

@@ -98,6 +102,15 @@ func newClient(config *rest.Config, options Options) (*client, error) {
98102
)
99103
}
100104

105+
// Use the rest HTTP client for the provided config if unset
106+
if options.HTTPClient == nil {
107+
var err error
108+
options.HTTPClient, err = rest.HTTPClientFor(config)
109+
if err != nil {
110+
return nil, err
111+
}
112+
}
113+
101114
// Init a scheme if none provided
102115
if options.Scheme == nil {
103116
options.Scheme = scheme.Scheme
@@ -106,23 +119,24 @@ func newClient(config *rest.Config, options Options) (*client, error) {
106119
// Init a Mapper if none provided
107120
if options.Mapper == nil {
108121
var err error
109-
options.Mapper, err = apiutil.NewDynamicRESTMapper(config)
122+
options.Mapper, err = apiutil.NewDynamicRESTMapper(config, options.HTTPClient)
110123
if err != nil {
111124
return nil, err
112125
}
113126
}
114127

115128
resources := &clientRestResources{
116-
config: config,
117-
scheme: options.Scheme,
118-
mapper: options.Mapper,
119-
codecs: serializer.NewCodecFactory(options.Scheme),
129+
httpClient: options.HTTPClient,
130+
config: config,
131+
scheme: options.Scheme,
132+
mapper: options.Mapper,
133+
codecs: serializer.NewCodecFactory(options.Scheme),
120134

121135
structuredResourceByType: make(map[schema.GroupVersionKind]*resourceMeta),
122136
unstructuredResourceByType: make(map[schema.GroupVersionKind]*resourceMeta),
123137
}
124138

125-
rawMetaClient, err := metadata.NewForConfig(config)
139+
rawMetaClient, err := metadata.NewForConfigAndClient(config, options.HTTPClient)
126140
if err != nil {
127141
return nil, fmt.Errorf("unable to construct metadata-only client for use as part of client: %w", err)
128142
}

pkg/client/client_rest_resources.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package client
1818

1919
import (
20+
"net/http"
2021
"strings"
2122
"sync"
2223

@@ -32,6 +33,9 @@ import (
3233

3334
// clientRestResources creates and stores rest clients and metadata for Kubernetes types.
3435
type clientRestResources struct {
36+
// httpClient is the http client to use for requests
37+
httpClient *http.Client
38+
3539
// config is the rest.Config to talk to an apiserver
3640
config *rest.Config
3741

@@ -59,7 +63,7 @@ func (c *clientRestResources) newResource(gvk schema.GroupVersionKind, isList, i
5963
gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
6064
}
6165

62-
client, err := apiutil.RESTClientForGVK(gvk, isUnstructured, c.config, c.codecs)
66+
client, err := apiutil.RESTClientForGVK(gvk, isUnstructured, c.config, c.codecs, c.httpClient)
6367
if err != nil {
6468
return nil, err
6569
}

pkg/client/watch.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,21 @@ import (
2929

3030
// NewWithWatch returns a new WithWatch.
3131
func NewWithWatch(config *rest.Config, options Options) (WithWatch, error) {
32+
// Use the rest HTTP client for the provided config if unset
33+
if options.HTTPClient == nil {
34+
var err error
35+
options.HTTPClient, err = rest.HTTPClientFor(config)
36+
if err != nil {
37+
return nil, err
38+
}
39+
}
40+
3241
client, err := newClient(config, options)
3342
if err != nil {
3443
return nil, err
3544
}
36-
dynamicClient, err := dynamic.NewForConfig(config)
45+
46+
dynamicClient, err := dynamic.NewForConfigAndClient(config, options.HTTPClient)
3747
if err != nil {
3848
return nil, err
3949
}

0 commit comments

Comments
 (0)