@@ -20,6 +20,7 @@ import (
20
20
"context"
21
21
"crypto/rsa"
22
22
"fmt"
23
+ "net/http"
23
24
"os"
24
25
"sync"
25
26
"time"
@@ -263,8 +264,8 @@ func (t *ClusterCacheTracker) newClusterAccessor(ctx context.Context, cluster cl
263
264
return nil , errors .Wrapf (err , "error fetching REST client config for remote cluster %q" , cluster .String ())
264
265
}
265
266
266
- // Create a client and a mapper for the cluster.
267
- c , mapper , err := t .createClient (config , cluster )
267
+ // Create a client and a cache for the cluster.
268
+ c , cache , err := t .createClient (ctx , config , cluster , indexes )
268
269
if err != nil {
269
270
return nil , err
270
271
}
@@ -280,7 +281,7 @@ func (t *ClusterCacheTracker) newClusterAccessor(ctx context.Context, cluster cl
280
281
if runningOnCluster {
281
282
inClusterConfig , err := ctrl .GetConfig ()
282
283
if err != nil {
283
- return nil , errors .Wrap (err , "error creating client for self-hosted cluster" )
284
+ return nil , errors .Wrapf (err , "error creating client for self-hosted cluster %q" , cluster . String () )
284
285
}
285
286
286
287
// Use CA and Host from in-cluster config.
@@ -289,7 +290,7 @@ func (t *ClusterCacheTracker) newClusterAccessor(ctx context.Context, cluster cl
289
290
config .Host = inClusterConfig .Host
290
291
291
292
// Create a new client and overwrite the previously created client.
292
- c , mapper , err = t .createClient (config , cluster )
293
+ c , cache , err = t .createClient (ctx , config , cluster , indexes )
293
294
if err != nil {
294
295
return nil , errors .Wrap (err , "error creating client for self-hosted cluster" )
295
296
}
@@ -298,56 +299,6 @@ func (t *ClusterCacheTracker) newClusterAccessor(ctx context.Context, cluster cl
298
299
log .Info (fmt .Sprintf ("Creating cluster accessor for cluster %q with the regular apiserver endpoint %q" , cluster .String (), config .Host ))
299
300
}
300
301
301
- // Create the cache for the remote cluster
302
- cacheOptions := cache.Options {
303
- Scheme : t .scheme ,
304
- Mapper : mapper ,
305
- }
306
- remoteCache , err := cache .New (config , cacheOptions )
307
- if err != nil {
308
- return nil , errors .Wrapf (err , "error creating cache for remote cluster %q" , cluster .String ())
309
- }
310
-
311
- cacheCtx , cacheCtxCancel := context .WithCancel (ctx )
312
-
313
- // We need to be able to stop the cache's shared informers, so wrap this in a stoppableCache.
314
- cache := & stoppableCache {
315
- Cache : remoteCache ,
316
- cancelFunc : cacheCtxCancel ,
317
- }
318
-
319
- for _ , index := range indexes {
320
- if err := cache .IndexField (ctx , index .Object , index .Field , index .ExtractValue ); err != nil {
321
- return nil , fmt .Errorf ("failed to index field %s: %w" , index .Field , err )
322
- }
323
- }
324
-
325
- // Start the cache!!!
326
- go cache .Start (cacheCtx ) //nolint:errcheck
327
-
328
- // Wait until the cache is initially synced
329
- cacheSyncCtx , cacheSyncCtxCancel := context .WithTimeout (ctx , initialCacheSyncTimeout )
330
- defer cacheSyncCtxCancel ()
331
- if ! cache .WaitForCacheSync (cacheSyncCtx ) {
332
- cache .Stop ()
333
- return nil , fmt .Errorf ("failed waiting for cache for remote cluster %v to sync: %w" , cluster , cacheCtx .Err ())
334
- }
335
-
336
- // Start cluster healthcheck!!!
337
- go t .healthCheckCluster (cacheCtx , & healthCheckInput {
338
- cluster : cluster ,
339
- cfg : config ,
340
- })
341
-
342
- delegatingClient , err := client .NewDelegatingClient (client.NewDelegatingClientInput {
343
- CacheReader : cache ,
344
- Client : c ,
345
- UncachedObjects : t .clientUncachedObjects ,
346
- })
347
- if err != nil {
348
- return nil , err
349
- }
350
-
351
302
// Generating a new private key to be used for generating temporary certificates to connect to
352
303
// etcd on the target cluster.
353
304
// NOTE: Generating a private key is an expensive operation, so we store it in the cluster accessor.
@@ -359,7 +310,7 @@ func (t *ClusterCacheTracker) newClusterAccessor(ctx context.Context, cluster cl
359
310
return & clusterAccessor {
360
311
cache : cache ,
361
312
config : config ,
362
- client : delegatingClient ,
313
+ client : c ,
363
314
watches : sets.Set [string ]{},
364
315
etcdClientCertificateKey : etcdKey ,
365
316
}, nil
@@ -392,27 +343,83 @@ func (t *ClusterCacheTracker) runningOnWorkloadCluster(ctx context.Context, c cl
392
343
}
393
344
394
345
// createClient creates a client and a mapper based on a rest.Config.
395
- func (t * ClusterCacheTracker ) createClient (config * rest.Config , cluster client.ObjectKey ) (client.Client , meta.RESTMapper , error ) {
396
- var mapper meta.RESTMapper
397
- var err error
346
+ func (t * ClusterCacheTracker ) createClient (ctx context.Context , config * rest.Config , cluster client.ObjectKey , indexes []Index ) (client.Client , * stoppableCache , error ) {
347
+ // Create a http client for the cluster.
348
+ httpClient , err := rest .HTTPClientFor (config )
349
+ if err != nil {
350
+ return nil , nil , errors .Wrapf (err , "error creating http client for remote cluster %q" , cluster .String ())
351
+ }
398
352
353
+ var mapper meta.RESTMapper
399
354
// Create a mapper for it
400
355
if ! feature .Gates .Enabled (feature .LazyRestmapper ) {
401
- mapper , err = apiutil .NewDynamicRESTMapper (config )
356
+ mapper , err = apiutil .NewDynamicRESTMapper (config , httpClient )
402
357
} else {
403
- mapper , err = apiutil .NewDynamicRESTMapper (config , apiutil .WithExperimentalLazyMapper )
358
+ mapper , err = apiutil .NewDynamicRESTMapper (config , httpClient , apiutil .WithExperimentalLazyMapper )
404
359
}
405
360
if err != nil {
406
361
return nil , nil , errors .Wrapf (err , "error creating dynamic rest mapper for remote cluster %q" , cluster .String ())
407
362
}
408
363
364
+ // Create the cache for the remote cluster
365
+ cacheOptions := cache.Options {
366
+ HTTPClient : httpClient ,
367
+ Scheme : t .scheme ,
368
+ Mapper : mapper ,
369
+ }
370
+ remoteCache , err := cache .New (config , cacheOptions )
371
+ if err != nil {
372
+ return nil , nil , errors .Wrapf (err , "error creating cache for remote cluster %q" , cluster .String ())
373
+ }
374
+
375
+ cacheCtx , cacheCtxCancel := context .WithCancel (ctx )
376
+
377
+ // We need to be able to stop the cache's shared informers, so wrap this in a stoppableCache.
378
+ cache := & stoppableCache {
379
+ Cache : remoteCache ,
380
+ cancelFunc : cacheCtxCancel ,
381
+ }
382
+
383
+ for _ , index := range indexes {
384
+ if err := cache .IndexField (ctx , index .Object , index .Field , index .ExtractValue ); err != nil {
385
+ return nil , nil , errors .Wrapf (err , "error adding index for field %q to cache for remote cluster %q" , index .Field , cluster .String ())
386
+ }
387
+ }
388
+
409
389
// Create the client for the remote cluster
410
- c , err := client .New (config , client.Options {Scheme : t .scheme , Mapper : mapper })
390
+ c , err := client .New (config , client.Options {
391
+ Scheme : t .scheme ,
392
+ Mapper : mapper ,
393
+ HTTPClient : httpClient ,
394
+ Cache : & client.CacheOptions {
395
+ Reader : cache ,
396
+ DisableFor : t .clientUncachedObjects ,
397
+ Unstructured : true ,
398
+ },
399
+ })
411
400
if err != nil {
412
401
return nil , nil , errors .Wrapf (err , "error creating client for remote cluster %q" , cluster .String ())
413
402
}
414
403
415
- return c , mapper , nil
404
+ // Start the cache!!!
405
+ go cache .Start (cacheCtx ) //nolint:errcheck
406
+
407
+ // Wait until the cache is initially synced
408
+ cacheSyncCtx , cacheSyncCtxCancel := context .WithTimeout (ctx , initialCacheSyncTimeout )
409
+ defer cacheSyncCtxCancel ()
410
+ if ! cache .WaitForCacheSync (cacheSyncCtx ) {
411
+ cache .Stop ()
412
+ return nil , nil , fmt .Errorf ("failed waiting for cache for remote cluster %v to sync: %w" , cluster , cacheCtx .Err ())
413
+ }
414
+
415
+ // Start cluster healthcheck!!!
416
+ go t .healthCheckCluster (cacheCtx , & healthCheckInput {
417
+ cluster : cluster ,
418
+ cfg : config ,
419
+ httpClient : httpClient ,
420
+ })
421
+
422
+ return c , cache , nil
416
423
}
417
424
418
425
// deleteAccessor stops a clusterAccessor's cache and removes the clusterAccessor from the tracker.
@@ -486,7 +493,7 @@ func (t *ClusterCacheTracker) Watch(ctx context.Context, input WatchInput) error
486
493
}
487
494
488
495
// Need to create the watch
489
- if err := input .Watcher .Watch (source .NewKindWithCache ( input . Kind , accessor . cache ), input .EventHandler , input .Predicates ... ); err != nil {
496
+ if err := input .Watcher .Watch (source .Kind ( accessor . cache , input . Kind ), input .EventHandler , input .Predicates ... ); err != nil {
490
497
return errors .Wrapf (err , "failed to add %s watch on cluster %s: failed to create watch" , input .Kind , klog .KRef (input .Cluster .Namespace , input .Cluster .Name ))
491
498
}
492
499
@@ -498,6 +505,7 @@ func (t *ClusterCacheTracker) Watch(ctx context.Context, input WatchInput) error
498
505
// healthCheckInput provides the input for the healthCheckCluster method.
499
506
type healthCheckInput struct {
500
507
cluster client.ObjectKey
508
+ httpClient * http.Client
501
509
cfg * rest.Config
502
510
interval time.Duration
503
511
requestTimeout time.Duration
@@ -535,9 +543,9 @@ func (t *ClusterCacheTracker) healthCheckCluster(ctx context.Context, in *health
535
543
codec := runtime.NoopEncoder {Decoder : scheme .Codecs .UniversalDecoder ()}
536
544
cfg := rest .CopyConfig (in .cfg )
537
545
cfg .NegotiatedSerializer = serializer .NegotiatedSerializerWrapper (runtime.SerializerInfo {Serializer : codec })
538
- restClient , restClientErr := rest .UnversionedRESTClientFor (cfg )
546
+ restClient , restClientErr := rest .UnversionedRESTClientForConfigAndClient (cfg , in . httpClient )
539
547
540
- runHealthCheckWithThreshold := func () (bool , error ) {
548
+ runHealthCheckWithThreshold := func (ctx context. Context ) (bool , error ) {
541
549
if restClientErr != nil {
542
550
return false , restClientErr
543
551
}
@@ -593,12 +601,12 @@ func (t *ClusterCacheTracker) healthCheckCluster(ctx context.Context, in *health
593
601
return false , nil
594
602
}
595
603
596
- err := wait .PollImmediateUntil ( in .interval , runHealthCheckWithThreshold , ctx . Done () )
604
+ err := wait .PollUntilContextCancel ( ctx , in .interval , true , runHealthCheckWithThreshold )
597
605
// An error returned implies the health check has failed a sufficient number of
598
606
// times for the cluster to be considered unhealthy
599
607
// NB. we are ignoring ErrWaitTimeout because this error happens when the channel is close, that in this case
600
608
// happens when the cache is explicitly stopped.
601
- if err != nil && err != wait .ErrWaitTimeout {
609
+ if err != nil && ! wait .Interrupted ( err ) {
602
610
t .log .Error (err , "Error health checking cluster" , "Cluster" , klog .KRef (in .cluster .Namespace , in .cluster .Name ))
603
611
t .deleteAccessor (ctx , in .cluster )
604
612
}
0 commit comments