@@ -99,6 +99,13 @@ type Cloud struct {
99
99
// for the cloudprovider to start watching the configmap.
100
100
ClusterID ClusterID
101
101
102
+ // initializer is used for lazy initialization of subnetworkURL
103
+ // and isLegacyNetwork fields if they are not passed via the config.
104
+ // The reason is to avoid GCE API calls to initialize them if they
105
+ // will never be used. This is especially important when
106
+ // it is run from Kubelets, as there can be thousands of them.
107
+ subnetworkURLAndIsLegacyNetworkInitializer sync.Once
108
+
102
109
service * compute.Service
103
110
serviceBeta * computebeta.Service
104
111
serviceAlpha * computealpha.Service
@@ -115,10 +122,14 @@ type Cloud struct {
115
122
// managedZones will be set to the 1 zone if running a single zone cluster
116
123
// it will be set to ALL zones in region for any multi-zone cluster
117
124
// Use GetAllCurrentZones to get only zones that contain nodes
118
- managedZones []string
119
- networkURL string
120
- isLegacyNetwork bool
121
- subnetworkURL string
125
+ managedZones []string
126
+ networkURL string
127
+ // unsafeIsLegacyNetwork should be used only via IsLegacyNetwork() accessor,
128
+ // to ensure it was properly initialized.
129
+ unsafeIsLegacyNetwork bool
130
+ // unsafeSubnetworkURL should be used only via SubnetworkURL() accessor,
131
+ // to ensure it was properly initialized.
132
+ unsafeSubnetworkURL string
122
133
secondaryRangeName string
123
134
networkProjectID string
124
135
onXPN bool
@@ -465,32 +476,12 @@ func CreateGCECloud(config *CloudConfig) (*Cloud, error) {
465
476
subnetURL = config .SubnetworkURL
466
477
} else if config .SubnetworkName != "" {
467
478
subnetURL = gceSubnetworkURL (config .APIEndpoint , netProjID , config .Region , config .SubnetworkName )
468
- } else {
469
- // Determine the type of network and attempt to discover the correct subnet for AUTO mode.
470
- // Gracefully fail because kubelet calls CreateGCECloud without any config, and minions
471
- // lack the proper credentials for API calls.
472
- if networkName := lastComponent (networkURL ); networkName != "" {
473
- var n * compute.Network
474
- if n , err = getNetwork (service , netProjID , networkName ); err != nil {
475
- klog .Warningf ("Could not retrieve network %q; err: %v" , networkName , err )
476
- } else {
477
- switch typeOfNetwork (n ) {
478
- case netTypeLegacy :
479
- klog .Infof ("Network %q is type legacy - no subnetwork" , networkName )
480
- isLegacyNetwork = true
481
- case netTypeCustom :
482
- klog .Warningf ("Network %q is type custom - cannot auto select a subnetwork" , networkName )
483
- case netTypeAuto :
484
- subnetURL , err = determineSubnetURL (service , netProjID , networkName , config .Region )
485
- if err != nil {
486
- klog .Warningf ("Could not determine subnetwork for network %q and region %v; err: %v" , networkName , config .Region , err )
487
- } else {
488
- klog .Infof ("Auto selecting subnetwork %q" , subnetURL )
489
- }
490
- }
491
- }
492
- }
493
479
}
480
+ // If neither SubnetworkURL nor SubnetworkName are provided, defer to
481
+ // lazy initialization. Determining subnetURL and isLegacyNetwork requires
482
+ // GCE API call. Given that it's not used in many cases and the fact that
483
+ // the provider is initialized also for Kubelets (and there can be thousands
484
+ // of them) we defer to lazy initialization here.
494
485
495
486
if len (config .ManagedZones ) == 0 {
496
487
config .ManagedZones , err = getZonesForRegion (service , config .ProjectID , config .Region )
@@ -518,8 +509,8 @@ func CreateGCECloud(config *CloudConfig) (*Cloud, error) {
518
509
localZone : config .Zone ,
519
510
managedZones : config .ManagedZones ,
520
511
networkURL : networkURL ,
521
- isLegacyNetwork : isLegacyNetwork ,
522
- subnetworkURL : subnetURL ,
512
+ unsafeIsLegacyNetwork : isLegacyNetwork ,
513
+ unsafeSubnetworkURL : subnetURL ,
523
514
secondaryRangeName : config .SecondaryRangeName ,
524
515
nodeTags : config .NodeTags ,
525
516
nodeInstancePrefix : config .NodeInstancePrefix ,
@@ -542,6 +533,45 @@ func CreateGCECloud(config *CloudConfig) (*Cloud, error) {
542
533
return gce , nil
543
534
}
544
535
536
+ // initializeNetworkConfig() is supposed to be called under sync.Once()
537
+ // for accessors to subnetworkURL and isLegacyNetwork fields.
538
+ func (g * Cloud ) initializeSubnetworkURLAndIsLegacyNetwork () {
539
+ if g .unsafeSubnetworkURL != "" {
540
+ // This has already been initialized via the config.
541
+ return
542
+ }
543
+
544
+ var subnetURL string
545
+ var isLegacyNetwork bool
546
+
547
+ // Determine the type of network and attempt to discover the correct subnet for AUTO mode.
548
+ // Gracefully fail because kubelet calls CreateGCECloud without any config, and minions
549
+ // lack the proper credentials for API calls.
550
+ if networkName := lastComponent (g .NetworkURL ()); networkName != "" {
551
+ if n , err := getNetwork (g .service , g .NetworkProjectID (), networkName ); err != nil {
552
+ klog .Warningf ("Could not retrieve network %q; err: %v" , networkName , err )
553
+ } else {
554
+ switch typeOfNetwork (n ) {
555
+ case netTypeLegacy :
556
+ klog .Infof ("Network %q is type legacy - no subnetwork" , networkName )
557
+ isLegacyNetwork = true
558
+ case netTypeCustom :
559
+ klog .Warningf ("Network %q is type custom - cannot auto select a subnetwork" , networkName )
560
+ case netTypeAuto :
561
+ subnetURL , err = determineSubnetURL (g .service , g .NetworkProjectID (), networkName , g .Region ())
562
+ if err != nil {
563
+ klog .Warningf ("Could not determine subnetwork for network %q and region %v; err: %v" , networkName , g .Region (), err )
564
+ } else {
565
+ klog .Infof ("Auto selecting subnetwork %q" , subnetURL )
566
+ }
567
+ }
568
+ }
569
+ }
570
+
571
+ g .unsafeSubnetworkURL = subnetURL
572
+ g .unsafeIsLegacyNetwork = isLegacyNetwork
573
+ }
574
+
545
575
// SetRateLimiter adds a custom cloud.RateLimiter implementation.
546
576
// WARNING: Calling this could have unexpected behavior if you have in-flight
547
577
// requests. It is best to use this immediately after creating a Cloud.
@@ -672,12 +702,14 @@ func (g *Cloud) NetworkURL() string {
672
702
673
703
// SubnetworkURL returns the subnetwork url
674
704
func (g * Cloud ) SubnetworkURL () string {
675
- return g .subnetworkURL
705
+ g .subnetworkURLAndIsLegacyNetworkInitializer .Do (g .initializeSubnetworkURLAndIsLegacyNetwork )
706
+ return g .unsafeSubnetworkURL
676
707
}
677
708
678
709
// IsLegacyNetwork returns true if the cluster is still running a legacy network configuration.
679
710
func (g * Cloud ) IsLegacyNetwork () bool {
680
- return g .isLegacyNetwork
711
+ g .subnetworkURLAndIsLegacyNetworkInitializer .Do (g .initializeSubnetworkURLAndIsLegacyNetwork )
712
+ return g .unsafeIsLegacyNetwork
681
713
}
682
714
683
715
// SetInformers sets up the zone handlers we need watching for node changes.
0 commit comments