@@ -17,6 +17,7 @@ limitations under the License.
17
17
package gce
18
18
19
19
import (
20
+ "context"
20
21
"fmt"
21
22
"io"
22
23
"net/http"
@@ -435,24 +436,26 @@ func CreateGCECloud(config *CloudConfig) (*GCECloud, error) {
435
436
} else if config .SubnetworkName != "" {
436
437
subnetURL = gceSubnetworkURL (config .ApiEndpoint , netProjID , config .Region , config .SubnetworkName )
437
438
} else {
438
- // Attempt to determine the subnetwork in case it's an automatic network.
439
- // Legacy networks will not have a subnetwork, so subnetworkURL should remain empty.
439
+ // Determine the type of network and attempt to discover the correct subnet for AUTO mode.
440
+ // Gracefully fail because kubelet calls CreateGCECloud without any config, and minions
441
+ // lack the proper credentials for API calls.
440
442
if networkName := lastComponent (networkURL ); networkName != "" {
441
- if n , err := getNetwork ( service , netProjID , networkName ); err != nil {
442
- // Gracefully fail because kubelet calls CreateGCECloud without any config, and API calls will fail coming from minions.
443
- glog .Warningf ("Could not retrieve network %q in attempt to determine if legacy network or see list of subnets, err %v" , networkURL , err )
443
+ var n * compute. Network
444
+ if n , err = getNetwork ( service , netProjID , networkName ); err != nil {
445
+ glog .Warningf ("Could not retrieve network %q; err: %v" , networkName , err )
444
446
} else {
445
- // Legacy networks have a non-empty IPv4Range
446
- if len ( n . IPv4Range ) > 0 {
447
- glog .Infof ("Determined network %q is type legacy" , networkURL )
447
+ switch typeOfNetwork ( n ) {
448
+ case netTypeLegacy :
449
+ glog .Infof ("Network %q is type legacy - no subnetwork " , networkName )
448
450
isLegacyNetwork = true
449
- } else {
450
- // Try to find the subnet in the list of subnets
451
- subnetURL = findSubnetForRegion (n .Subnetworks , config .Region )
452
- if len (subnetURL ) > 0 {
453
- glog .Infof ("Using subnet %q within network %q & region %q because none was specified." , subnetURL , n .Name , config .Region )
451
+ case netTypeCustom :
452
+ glog .Warningf ("Network %q is type custom - cannot auto select a subnetwork" , networkName )
453
+ case netTypeAuto :
454
+ subnetURL , err = determineSubnetURL (service , netProjID , networkName , config .Region )
455
+ if err != nil {
456
+ glog .Warningf ("Could not determine subnetwork for network %q and region %v; err: %v" , networkName , config .Region , err )
454
457
} else {
455
- glog .Warningf ( "Could not find any subnet in region %q within list %v. " , config . Region , n . Subnetworks )
458
+ glog .Infof ( "Auto selecting subnetwork %q " , subnetURL )
456
459
}
457
460
}
458
461
}
@@ -499,6 +502,30 @@ func CreateGCECloud(config *CloudConfig) (*GCECloud, error) {
499
502
return gce , nil
500
503
}
501
504
505
+ // determineSubnetURL queries for all subnetworks in a region for a given network and returns
506
+ // the URL of the subnetwork which exists in the auto-subnet range.
507
+ func determineSubnetURL (service * compute.Service , networkProjectID , networkName , region string ) (string , error ) {
508
+ subnets , err := listSubnetworksOfNetwork (service , networkProjectID , networkName , region )
509
+ if err != nil {
510
+ return "" , err
511
+ }
512
+
513
+ autoSubnets , err := subnetsInCIDR (subnets , autoSubnetIPRange )
514
+ if err != nil {
515
+ return "" , err
516
+ }
517
+
518
+ if len (autoSubnets ) == 0 {
519
+ return "" , fmt .Errorf ("no subnet exists in auto CIDR" )
520
+ }
521
+
522
+ if len (autoSubnets ) > 1 {
523
+ return "" , fmt .Errorf ("multiple subnetworks in the same region exist in auto CIDR" )
524
+ }
525
+
526
+ return autoSubnets [0 ].SelfLink , nil
527
+ }
528
+
502
529
func tryConvertToProjectNames (configProject , configNetworkProject string , service * compute.Service ) (projID , netProjID string ) {
503
530
projID = configProject
504
531
if isProjectNumber (projID ) {
@@ -740,6 +767,16 @@ func getNetwork(svc *compute.Service, networkProjectID, networkID string) (*comp
740
767
return svc .Networks .Get (networkProjectID , networkID ).Do ()
741
768
}
742
769
770
+ // listSubnetworksOfNetwork returns a list of subnetworks for a particular region of a network.
771
+ func listSubnetworksOfNetwork (svc * compute.Service , networkProjectID , networkID , region string ) ([]* compute.Subnetwork , error ) {
772
+ var subnets []* compute.Subnetwork
773
+ err := svc .Subnetworks .List (networkProjectID , region ).Filter (fmt .Sprintf ("network eq .*/%v$" , networkID )).Pages (context .Background (), func (res * compute.SubnetworkList ) error {
774
+ subnets = append (subnets , res .Items ... )
775
+ return nil
776
+ })
777
+ return subnets , err
778
+ }
779
+
743
780
// getProjectID returns the project's string ID given a project number or string
744
781
func getProjectID (svc * compute.Service , projectNumberOrID string ) (string , error ) {
745
782
proj , err := svc .Projects .Get (projectNumberOrID ).Do ()
0 commit comments