@@ -3,22 +3,27 @@ package targetgroupbinding
33import (
44 "context"
55 "fmt"
6- smithy "github.com/aws/smithy-go"
7- "k8s.io/apimachinery/pkg/util/cache"
86 "net/netip"
97 "sync"
108 "time"
119
10+ smithy "github.com/aws/smithy-go"
11+ "k8s.io/apimachinery/pkg/util/cache"
12+
13+ "strings"
14+
1215 awssdk "github.com/aws/aws-sdk-go-v2/aws"
1316 elbv2types "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types"
1417 "github.com/go-logr/logr"
1518 "github.com/pkg/errors"
1619 corev1 "k8s.io/api/core/v1"
1720 apierrors "k8s.io/apimachinery/pkg/api/errors"
1821 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
22+ "k8s.io/apimachinery/pkg/types"
1923 "k8s.io/apimachinery/pkg/util/sets"
2024 "k8s.io/client-go/tools/record"
2125 elbv2api "sigs.k8s.io/aws-load-balancer-controller/apis/elbv2/v1beta1"
26+ "sigs.k8s.io/aws-load-balancer-controller/pkg/annotations"
2227 "sigs.k8s.io/aws-load-balancer-controller/pkg/aws/services"
2328 "sigs.k8s.io/aws-load-balancer-controller/pkg/backend"
2429 ctrlerrors "sigs.k8s.io/aws-load-balancer-controller/pkg/error"
@@ -53,6 +58,7 @@ func NewDefaultResourceManager(k8sClient client.Client, elbv2Client services.ELB
5358 endpointResolver := backend .NewDefaultEndpointResolver (k8sClient , podInfoRepo , failOpenEnabled , endpointSliceEnabled , logger )
5459 return & defaultResourceManager {
5560 k8sClient : k8sClient ,
61+ elbv2Client : elbv2Client ,
5662 targetsManager : targetsManager ,
5763 endpointResolver : endpointResolver ,
5864 networkingManager : networkingManager ,
@@ -77,6 +83,7 @@ var _ ResourceManager = &defaultResourceManager{}
7783// default implementation for ResourceManager.
7884type defaultResourceManager struct {
7985 k8sClient client.Client
86+ elbv2Client services.ELBV2
8087 targetsManager TargetsManager
8188 endpointResolver backend.EndpointResolver
8289 networkingManager networking.NetworkingManager
@@ -569,19 +576,26 @@ func (m *defaultResourceManager) registerPodEndpoints(ctx context.Context, tgb *
569576 }
570577
571578 overrideAzFn , err := m .generateOverrideAzFn (ctx , vpcID , tgb .Spec .IamRoleArnToAssume )
579+ if err != nil {
580+ return err
581+ }
572582
583+ svcAnnotations , err := m .getServiceAnnotations (ctx , tgb )
573584 if err != nil {
574585 return err
575586 }
576587
577- sdkTargets , err := m .prepareRegistrationCall (endpoints , tgb , overrideAzFn )
588+ sdkTargets , err := m .prepareRegistrationCall (ctx , endpoints , tgb , overrideAzFn , svcAnnotations )
578589 if err != nil {
579590 return err
580591 }
581592 return m .targetsManager .RegisterTargets (ctx , tgb , sdkTargets )
582593}
583594
584- func (m * defaultResourceManager ) prepareRegistrationCall (endpoints []backend.PodEndpoint , tgb * elbv2api.TargetGroupBinding , doAzOverride func (addr netip.Addr ) bool ) ([]elbv2types.TargetDescription , error ) {
595+ func (m * defaultResourceManager ) prepareRegistrationCall (ctx context.Context , endpoints []backend.PodEndpoint , tgb * elbv2api.TargetGroupBinding , doAzOverride func (addr netip.Addr ) bool , svcAnnotations map [string ]string ) ([]elbv2types.TargetDescription , error ) {
596+ isALB := m .isALBIngress (svcAnnotations )
597+ crossZoneDisabled := m .isCrossZoneDisabled (svcAnnotations , isALB )
598+
585599 sdkTargets := make ([]elbv2types.TargetDescription , 0 , len (endpoints ))
586600 for _ , endpoint := range endpoints {
587601 target := elbv2types.TargetDescription {
@@ -593,7 +607,15 @@ func (m *defaultResourceManager) prepareRegistrationCall(endpoints []backend.Pod
593607 return sdkTargets , err
594608 }
595609 if doAzOverride (podIP ) {
596- target .AvailabilityZone = awssdk .String ("all" )
610+ if isALB && crossZoneDisabled && tgb .Spec .IamRoleArnToAssume == "" {
611+ az , err := m .getPodAvailabilityZone (ctx , endpoint .Pod )
612+ if err != nil {
613+ return sdkTargets , err
614+ }
615+ target .AvailabilityZone = awssdk .String (az )
616+ } else {
617+ target .AvailabilityZone = awssdk .String ("all" )
618+ }
597619 }
598620
599621 doAppend := true
@@ -844,3 +866,57 @@ func (m *defaultResourceManager) getMaxNewTargets(newTargetCount int, currentTar
844866
845867 return newTargetCount
846868}
869+
870+ func (m * defaultResourceManager ) getServiceAnnotations (ctx context.Context , tgb * elbv2api.TargetGroupBinding ) (map [string ]string , error ) {
871+ svcKey := buildServiceReferenceKey (tgb , tgb .Spec .ServiceRef )
872+ svc := & corev1.Service {}
873+ if err := m .k8sClient .Get (ctx , svcKey , svc ); err != nil {
874+ return nil , err
875+ }
876+ return svc .Annotations , nil
877+ }
878+
879+ func (m * defaultResourceManager ) isALBIngress (svcAnnotations map [string ]string ) bool {
880+ for key := range svcAnnotations {
881+ if strings .HasPrefix (key , annotations .AnnotationPrefixIngress ) {
882+ return true
883+ }
884+ }
885+ return false
886+ }
887+
888+ func (m * defaultResourceManager ) isCrossZoneDisabled (svcAnnotations map [string ]string , isALB bool ) bool {
889+ crossZoneDisabled := "load_balancing.cross_zone.enabled=false"
890+ if isALB {
891+ if attrs , ok := svcAnnotations [annotations .AnnotationPrefixIngress + "/" + annotations .IngressSuffixTargetGroupAttributes ]; ok {
892+ return strings .Contains (attrs , crossZoneDisabled )
893+ }
894+ } else {
895+ if attrs , ok := svcAnnotations [annotations .SvcBetaAnnotationPrefix + "/" + annotations .SvcLBSuffixLoadBalancerAttributes ]; ok {
896+ return strings .Contains (attrs , crossZoneDisabled )
897+ }
898+ }
899+ return false
900+ }
901+
902+ func (m * defaultResourceManager ) getPodAvailabilityZone (ctx context.Context , pod k8s.PodInfo ) (string , error ) {
903+ if pod .NodeName == "" {
904+ return "" , errors .Errorf ("pod %s has no node assigned" , pod .Key )
905+ }
906+
907+ node := & corev1.Node {}
908+ if err := m .k8sClient .Get (ctx , types.NamespacedName {Name : pod .NodeName }, node ); err != nil {
909+ return "" , err
910+ }
911+
912+ az , ok := node .Labels [corev1 .LabelTopologyZone ]
913+ // fallback: try legacy/deprecated label failure-domain.beta.kubernetes.io/zone
914+ if ! ok {
915+ az , ok = node .Labels ["failure-domain.beta.kubernetes.io/zone" ]
916+ }
917+ if ! ok {
918+ return "" , errors .Errorf ("node %s has no availability zone label" , pod .NodeName )
919+ }
920+
921+ return az , nil
922+ }
0 commit comments