github.com/cilium/cilium@v1.16.2/pkg/ipam/allocator/aws/aws.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package aws 5 6 import ( 7 "context" 8 "fmt" 9 10 "github.com/aws/aws-sdk-go-v2/aws" 11 "github.com/aws/aws-sdk-go-v2/service/ec2" 12 13 operatorMetrics "github.com/cilium/cilium/operator/metrics" 14 operatorOption "github.com/cilium/cilium/operator/option" 15 apiMetrics "github.com/cilium/cilium/pkg/api/metrics" 16 ec2shim "github.com/cilium/cilium/pkg/aws/ec2" 17 "github.com/cilium/cilium/pkg/aws/eni" 18 "github.com/cilium/cilium/pkg/aws/eni/limits" 19 "github.com/cilium/cilium/pkg/defaults" 20 "github.com/cilium/cilium/pkg/ipam" 21 "github.com/cilium/cilium/pkg/ipam/allocator" 22 ipamMetrics "github.com/cilium/cilium/pkg/ipam/metrics" 23 "github.com/cilium/cilium/pkg/logging" 24 "github.com/cilium/cilium/pkg/logging/logfields" 25 "github.com/cilium/cilium/pkg/metrics" 26 "github.com/cilium/cilium/pkg/option" 27 ) 28 29 var log = logging.DefaultLogger.WithField(logfields.LogSubsys, "ipam-allocator-aws") 30 31 // AllocatorAWS is an implementation of IPAM allocator interface for AWS ENI 32 type AllocatorAWS struct { 33 client *ec2shim.Client 34 eniGCTags map[string]string 35 } 36 37 func initENIGarbageCollectionTags(ctx context.Context, cfg aws.Config) (eniTags map[string]string) { 38 // Use user-provided tags if available 39 if len(operatorOption.Config.ENIGarbageCollectionTags) != 0 { 40 return operatorOption.Config.ENIGarbageCollectionTags 41 } 42 43 eniTags = map[string]string{ 44 defaults.ENIGarbageCollectionTagManagedName: defaults.ENIGarbageCollectionTagManagedValue, 45 defaults.ENIGarbageCollectionTagClusterName: defaults.ENIGarbageCollectionTagClusterValue, 46 } 47 48 // Use cilium cluster name if available 49 if clusterName := option.Config.ClusterName; clusterName != defaults.ClusterName { 50 eniTags[defaults.ENIGarbageCollectionTagClusterName] = clusterName 51 return eniTags 52 } 53 54 // Try to auto-detect EKS cluster name 55 clusterName, err := ec2shim.DetectEKSClusterName(ctx, cfg) 56 if err != nil { 57 log.WithError(err).Debug("Auto-detection of EKS cluster name failed") 58 } else { 59 log.WithField(logfields.ClusterName, clusterName). 60 Info("Auto-detected EKS cluster name for ENI garbage collection") 61 eniTags[defaults.ENIGarbageCollectionTagClusterName] = clusterName 62 return eniTags 63 } 64 65 log.Info("Unable to detect EKS cluster name for ENI garbage collection. " + 66 "This operator instance may clean up dangling ENIs from other Cilium clusters. " + 67 "Set a --cluster-name or cluster-specific --eni-gc-tags to prevent this.") 68 return eniTags 69 } 70 71 // Init sets up ENI limits based on given options 72 func (a *AllocatorAWS) Init(ctx context.Context) error { 73 var aMetrics ec2shim.MetricsAPI 74 75 cfg, err := ec2shim.NewConfig(ctx) 76 if err != nil { 77 return err 78 } 79 subnetsFilters := ec2shim.NewSubnetsFilters(operatorOption.Config.IPAMSubnetsTags, operatorOption.Config.IPAMSubnetsIDs) 80 instancesFilters := ec2shim.NewTagsFilter(operatorOption.Config.IPAMInstanceTags) 81 82 if operatorOption.Config.EnableMetrics { 83 aMetrics = apiMetrics.NewPrometheusMetrics(metrics.Namespace, "ec2", operatorMetrics.Registry) 84 } else { 85 aMetrics = &apiMetrics.NoOpMetrics{} 86 } 87 88 eniCreationTags := operatorOption.Config.ENITags 89 if operatorOption.Config.ENIGarbageCollectionInterval > 0 { 90 a.eniGCTags = initENIGarbageCollectionTags(ctx, cfg) 91 // Make sure GC tags are also used for ENI creation 92 eniCreationTags = ec2shim.MergeTags(eniCreationTags, a.eniGCTags) 93 } 94 95 a.client = ec2shim.NewClient(ec2.NewFromConfig(cfg), aMetrics, operatorOption.Config.IPAMAPIQPSLimit, 96 operatorOption.Config.IPAMAPIBurst, subnetsFilters, instancesFilters, eniCreationTags, 97 operatorOption.Config.AWSUsePrimaryAddress) 98 99 if err := limits.UpdateFromUserDefinedMappings(operatorOption.Config.AWSInstanceLimitMapping); err != nil { 100 return fmt.Errorf("failed to parse aws-instance-limit-mapping: %w", err) 101 } 102 if operatorOption.Config.UpdateEC2AdapterLimitViaAPI { 103 if err := limits.UpdateFromEC2API(ctx, a.client); err != nil { 104 return fmt.Errorf("unable to update instance type to adapter limits from EC2 API: %w", err) 105 } 106 } 107 return nil 108 } 109 110 // Start kicks of ENI allocation, the initial connection to AWS 111 // APIs is done in a blocking manner, given that is successful, a controller is 112 // started to manage allocation based on CiliumNode custom resources 113 func (a *AllocatorAWS) Start(ctx context.Context, getterUpdater ipam.CiliumNodeGetterUpdater) (allocator.NodeEventHandler, error) { 114 var iMetrics ipam.MetricsAPI 115 116 log.Info("Starting ENI allocator...") 117 118 if operatorOption.Config.EnableMetrics { 119 iMetrics = ipamMetrics.NewPrometheusMetrics(metrics.Namespace, operatorMetrics.Registry) 120 } else { 121 iMetrics = &ipamMetrics.NoOpMetrics{} 122 } 123 instances := eni.NewInstancesManager(a.client) 124 nodeManager, err := ipam.NewNodeManager(instances, getterUpdater, iMetrics, 125 operatorOption.Config.ParallelAllocWorkers, operatorOption.Config.AWSReleaseExcessIPs, 126 operatorOption.Config.AWSEnablePrefixDelegation) 127 if err != nil { 128 return nil, fmt.Errorf("unable to initialize ENI node manager: %w", err) 129 } 130 131 if err := nodeManager.Start(ctx); err != nil { 132 return nil, err 133 } 134 135 if operatorOption.Config.ENIGarbageCollectionInterval > 0 { 136 eni.StartENIGarbageCollector(ctx, a.client, eni.GarbageCollectionParams{ 137 RunInterval: operatorOption.Config.ENIGarbageCollectionInterval, 138 MaxPerInterval: defaults.ENIGarbageCollectionMaxPerInterval, 139 ENITags: a.eniGCTags, 140 }) 141 } 142 143 return nodeManager, nil 144 }