sigs.k8s.io/cluster-api-provider-aws@v1.5.5/pkg/cloud/scope/shared.go (about) 1 /* 2 Copyright 2021 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package scope 18 19 import ( 20 "fmt" 21 22 "github.com/go-logr/logr" 23 "github.com/pkg/errors" 24 25 infrav1 "sigs.k8s.io/cluster-api-provider-aws/api/v1beta1" 26 ) 27 28 var ( 29 // ErrAZSubnetsNotFound is an error when a availability zone is specified but there are 30 // no matching subnets for that availability zone (a.k.a. fault domain). 31 ErrAZSubnetsNotFound = errors.New("no subnets found for supplied availability zone") 32 // ErrLoggerRequired is an error if a logger isn't specified. 33 ErrLoggerRequired = errors.New("logger is required") 34 // ErrNotPlaced is an error if there is no placement determined. 35 ErrNotPlaced = errors.New("placement not determined") 36 ) 37 38 type placementInput struct { 39 SpecSubnetIDs []string 40 SpecAvailabilityZones []string 41 ParentAvailabilityZones []string 42 ControlplaneSubnets infrav1.Subnets 43 } 44 45 type subnetsPlacementStratgey interface { 46 Place(input *placementInput) ([]string, error) 47 } 48 49 func newDefaultSubnetPlacementStrategy(logger *logr.Logger) (subnetsPlacementStratgey, error) { 50 if logger == nil { 51 return nil, ErrLoggerRequired 52 } 53 54 return &defaultSubnetPlacementStrategy{ 55 logger: *logger, 56 }, nil 57 } 58 59 // defaultSubnetPlacementStrategy is the default strategy for subnet placement. 60 type defaultSubnetPlacementStrategy struct { 61 logger logr.Logger 62 } 63 64 // Place works out the subnet placement based on the following precedence: 65 // 1. Explicit definition of subnet IDs in the spec 66 // 2. If the spec has Availability Zones then get the subnets for these AZs 67 // 3. If the parent resource has Availability Zones then get the subnets for these AZs 68 // 4. All the private subnets from the control plane are used 69 // In Cluster API Availability Zone can also be referred to by the name `Failure Domain`. 70 func (p *defaultSubnetPlacementStrategy) Place(input *placementInput) ([]string, error) { 71 if len(input.SpecSubnetIDs) > 0 { 72 p.logger.V(2).Info("using subnets from the spec") 73 return input.SpecSubnetIDs, nil 74 } 75 76 if len(input.SpecAvailabilityZones) > 0 { 77 p.logger.V(2).Info("determining subnets to use from the spec availability zones") 78 subnetIDs, err := p.getSubnetsForAZs(input.SpecAvailabilityZones, input.ControlplaneSubnets) 79 if err != nil { 80 return nil, fmt.Errorf("getting subnets for spec azs: %w", err) 81 } 82 83 return subnetIDs, nil 84 } 85 86 if len(input.ParentAvailabilityZones) > 0 { 87 p.logger.V(2).Info("determining subnets to use from the parents availability zones") 88 subnetIDs, err := p.getSubnetsForAZs(input.ParentAvailabilityZones, input.ControlplaneSubnets) 89 if err != nil { 90 return nil, fmt.Errorf("getting subnets for parent azs: %w", err) 91 } 92 93 return subnetIDs, nil 94 } 95 96 controlPlaneSubnetIDs := input.ControlplaneSubnets.FilterPrivate().IDs() 97 if len(controlPlaneSubnetIDs) > 0 { 98 p.logger.V(2).Info("using all the private subnets from the control plane") 99 return controlPlaneSubnetIDs, nil 100 } 101 102 return nil, ErrNotPlaced 103 } 104 105 func (p *defaultSubnetPlacementStrategy) getSubnetsForAZs(azs []string, controlPlaneSubnets infrav1.Subnets) ([]string, error) { 106 subnetIDs := []string{} 107 108 for _, zone := range azs { 109 subnets := controlPlaneSubnets.FilterByZone(zone) 110 if len(subnets) == 0 { 111 return nil, fmt.Errorf("getting subnets for availability zone %s: %w", zone, ErrAZSubnetsNotFound) 112 } 113 subnetIDs = append(subnetIDs, subnets.IDs()...) 114 } 115 116 return subnetIDs, nil 117 }