@@ -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"
@@ -443,24 +444,26 @@ func CreateGCECloud(config *CloudConfig) (*GCECloud, error) {
443
444
} else if config .SubnetworkName != "" {
444
445
subnetURL = gceSubnetworkURL (config .ApiEndpoint , netProjID , config .Region , config .SubnetworkName )
445
446
} else {
446
- // Attempt to determine the subnetwork in case it's an automatic network.
447
- // Legacy networks will not have a subnetwork, so subnetworkURL should remain empty.
447
+ // Determine the type of network and attempt to discover the correct subnet for AUTO mode.
448
+ // Gracefully fail because kubelet calls CreateGCECloud without any config, and minions
449
+ // lack the proper credentials for API calls.
448
450
if networkName := lastComponent (networkURL ); networkName != "" {
449
- if n , err := getNetwork ( service , netProjID , networkName ); err != nil {
450
- // Gracefully fail because kubelet calls CreateGCECloud without any config, and API calls will fail coming from minions.
451
- glog .Warningf ("Could not retrieve network %q in attempt to determine if legacy network or see list of subnets, err %v" , networkURL , err )
451
+ var n * compute. Network
452
+ if n , err = getNetwork ( service , netProjID , networkName ); err != nil {
453
+ glog .Warningf ("Could not retrieve network %q; err: %v" , networkName , err )
452
454
} else {
453
- // Legacy networks have a non-empty IPv4Range
454
- if len ( n . IPv4Range ) > 0 {
455
- glog .Infof ("Determined network %q is type legacy" , networkURL )
455
+ switch typeOfNetwork ( n ) {
456
+ case netTypeLegacy :
457
+ glog .Infof ("Network %q is type legacy - no subnetwork " , networkName )
456
458
isLegacyNetwork = true
457
- } else {
458
- // Try to find the subnet in the list of subnets
459
- subnetURL = findSubnetForRegion (n .Subnetworks , config .Region )
460
- if len (subnetURL ) > 0 {
461
- glog .Infof ("Using subnet %q within network %q & region %q because none was specified." , subnetURL , n .Name , config .Region )
459
+ case netTypeCustom :
460
+ glog .Warningf ("Network %q is type custom - cannot auto select a subnetwork" , networkName )
461
+ case netTypeAuto :
462
+ subnetURL , err = determineSubnetURL (service , netProjID , networkName , config .Region )
463
+ if err != nil {
464
+ glog .Warningf ("Could not determine subnetwork for network %q and region %v; err: %v" , networkName , config .Region , err )
462
465
} else {
463
- glog .Warningf ( "Could not find any subnet in region %q within list %v. " , config . Region , n . Subnetworks )
466
+ glog .Infof ( "Auto selecting subnetwork %q " , subnetURL )
464
467
}
465
468
}
466
469
}
@@ -507,6 +510,30 @@ func CreateGCECloud(config *CloudConfig) (*GCECloud, error) {
507
510
return gce , nil
508
511
}
509
512
513
+ // determineSubnetURL queries for all subnetworks in a region for a given network and returns
514
+ // the URL of the subnetwork which exists in the auto-subnet range.
515
+ func determineSubnetURL (service * compute.Service , networkProjectID , networkName , region string ) (string , error ) {
516
+ subnets , err := listSubnetworksOfNetwork (service , networkProjectID , networkName , region )
517
+ if err != nil {
518
+ return "" , err
519
+ }
520
+
521
+ autoSubnets , err := subnetsInCIDR (subnets , autoSubnetIPRange )
522
+ if err != nil {
523
+ return "" , err
524
+ }
525
+
526
+ if len (autoSubnets ) == 0 {
527
+ return "" , fmt .Errorf ("no subnet exists in auto CIDR" )
528
+ }
529
+
530
+ if len (autoSubnets ) > 1 {
531
+ return "" , fmt .Errorf ("multiple subnetworks in the same region exist in auto CIDR" )
532
+ }
533
+
534
+ return autoSubnets [0 ].SelfLink , nil
535
+ }
536
+
510
537
func tryConvertToProjectNames (configProject , configNetworkProject string , service * compute.Service ) (projID , netProjID string ) {
511
538
projID = configProject
512
539
if isProjectNumber (projID ) {
@@ -734,6 +761,16 @@ func getNetwork(svc *compute.Service, networkProjectID, networkID string) (*comp
734
761
return svc .Networks .Get (networkProjectID , networkID ).Do ()
735
762
}
736
763
764
+ // listSubnetworksOfNetwork returns a list of subnetworks for a particular region of a network.
765
+ func listSubnetworksOfNetwork (svc * compute.Service , networkProjectID , networkID , region string ) ([]* compute.Subnetwork , error ) {
766
+ var subnets []* compute.Subnetwork
767
+ err := svc .Subnetworks .List (networkProjectID , region ).Filter (fmt .Sprintf ("network eq .*/%v$" , networkID )).Pages (context .Background (), func (res * compute.SubnetworkList ) error {
768
+ subnets = append (subnets , res .Items ... )
769
+ return nil
770
+ })
771
+ return subnets , err
772
+ }
773
+
737
774
// getProjectID returns the project's string ID given a project number or string
738
775
func getProjectID (svc * compute.Service , projectNumberOrID string ) (string , error ) {
739
776
proj , err := svc .Projects .Get (projectNumberOrID ).Do ()
0 commit comments