@@ -3,6 +3,7 @@ package backend
3
3
import (
4
4
"context"
5
5
"fmt"
6
+ "net"
6
7
7
8
awssdk "github.com/aws/aws-sdk-go-v2/aws"
8
9
"github.com/go-logr/logr"
@@ -27,12 +28,17 @@ var ErrNotFound = errors.New("backend not found")
27
28
type EndpointResolver interface {
28
29
// ResolvePodEndpoints will resolve endpoints backed by pods directly.
29
30
// returns resolved podEndpoints and whether there are unready endpoints that can potentially turn ready in future reconciles.
30
- ResolvePodEndpoints (ctx context.Context , svcKey types.NamespacedName , port intstr.IntOrString ,
31
- opts ... EndpointResolveOption ) ([]PodEndpoint , bool , error )
31
+ ResolvePodEndpoints (ctx context.Context , svckey types.NamespacedName , svc * corev1.Service , port intstr.IntOrString , opts ... EndpointResolveOption ) ([]IpEndpoint , bool , error )
32
32
33
33
// ResolveNodePortEndpoints will resolve endpoints backed by nodePort.
34
34
ResolveNodePortEndpoints (ctx context.Context , svcKey types.NamespacedName , port intstr.IntOrString ,
35
35
opts ... EndpointResolveOption ) ([]NodePortEndpoint , error )
36
+
37
+ // FindService finds a k8s service
38
+ FindService (ctx context.Context , svcKey types.NamespacedName ) (* corev1.Service , error )
39
+
40
+ // ResolveExternalNameEndpoints will resolve external name using dns
41
+ ResolveExternalNameEndpoints (ctx context.Context , svc * corev1.Service , port intstr.IntOrString ) ([]IpEndpoint , error )
36
42
}
37
43
38
44
// NewDefaultEndpointResolver constructs new defaultEndpointResolver
@@ -42,6 +48,7 @@ func NewDefaultEndpointResolver(k8sClient client.Client, podInfoRepo k8s.PodInfo
42
48
podInfoRepo : podInfoRepo ,
43
49
failOpenEnabled : failOpenEnabled ,
44
50
endpointSliceEnabled : endpointSliceEnabled ,
51
+ dnsResolver : net .DefaultResolver ,
45
52
logger : logger ,
46
53
}
47
54
}
@@ -58,13 +65,34 @@ type defaultEndpointResolver struct {
58
65
// [Pod Endpoint] whether to use endpointSlice instead of endpoints
59
66
endpointSliceEnabled bool
60
67
logger logr.Logger
68
+ // dnsResolver to use for resolving external names
69
+ dnsResolver dnsResolver
70
+ }
71
+
72
+ type dnsResolver interface {
73
+ LookupHost (ctx context.Context , host string ) (addrs []string , err error )
74
+ }
75
+
76
+ func (r * defaultEndpointResolver ) ResolveExternalNameEndpoints (ctx context.Context , svc * corev1.Service , port intstr.IntOrString ) ([]IpEndpoint , error ) {
77
+ if port .Type == intstr .String {
78
+ return nil , fmt .Errorf ("port of target group must be numeric for external name" )
79
+ }
80
+ addrs , err := r .dnsResolver .LookupHost (ctx , svc .Spec .ExternalName )
81
+ if err != nil {
82
+ return nil , err
83
+ }
84
+ endpoints := make ([]IpEndpoint , len (addrs ))
85
+ for i , ip := range addrs {
86
+ endpoints [i ] = IpEndpoint {IP : ip , Port : port .IntVal }
87
+ }
88
+ return endpoints , nil
61
89
}
62
90
63
- func (r * defaultEndpointResolver ) ResolvePodEndpoints (ctx context.Context , svcKey types.NamespacedName , port intstr.IntOrString , opts ... EndpointResolveOption ) ([]PodEndpoint , bool , error ) {
91
+ func (r * defaultEndpointResolver ) ResolvePodEndpoints (ctx context.Context , svcKey types.NamespacedName , svc * corev1. Service , port intstr.IntOrString , opts ... EndpointResolveOption ) ([]IpEndpoint , bool , error ) {
64
92
resolveOpts := defaultEndpointResolveOptions ()
65
93
resolveOpts .ApplyOptions (opts )
66
94
67
- _ , svcPort , err := r .findServiceAndServicePort ( ctx , svcKey , port )
95
+ _ , svcPort , err := r .findServicePort ( svc , port )
68
96
if err != nil {
69
97
return nil , false , err
70
98
}
@@ -140,9 +168,9 @@ func (r *defaultEndpointResolver) computeServiceEndpointsData(ctx context.Contex
140
168
return endpointsDataList , nil
141
169
}
142
170
143
- func (r * defaultEndpointResolver ) resolvePodEndpointsWithEndpointsData (ctx context.Context , svcKey types.NamespacedName , svcPort corev1.ServicePort , endpointsDataList []EndpointsData , podReadinessGates []corev1.PodConditionType ) ([]PodEndpoint , bool , error ) {
144
- var readyPodEndpoints []PodEndpoint
145
- var unknownPodEndpoints []PodEndpoint
171
+ func (r * defaultEndpointResolver ) resolvePodEndpointsWithEndpointsData (ctx context.Context , svcKey types.NamespacedName , svcPort corev1.ServicePort , endpointsDataList []EndpointsData , podReadinessGates []corev1.PodConditionType ) ([]IpEndpoint , bool , error ) {
172
+ var readyPodEndpoints []IpEndpoint
173
+ var unknownPodEndpoints []IpEndpoint
146
174
containsPotentialReadyEndpoints := false
147
175
148
176
for _ , epsData := range endpointsDataList {
@@ -171,7 +199,7 @@ func (r *defaultEndpointResolver) resolvePodEndpointsWithEndpointsData(ctx conte
171
199
continue
172
200
}
173
201
174
- podEndpoint := buildPodEndpoint (pod , epAddr , epPort )
202
+ podEndpoint := buildPodEndpoint (& pod , epAddr , epPort )
175
203
// Recommendation from Kubernetes is to consider unknown ready status as ready (ready == nil)
176
204
if ep .Conditions .Ready == nil || * ep .Conditions .Ready {
177
205
readyPodEndpoints = append (readyPodEndpoints , podEndpoint )
@@ -216,13 +244,14 @@ func (r *defaultEndpointResolver) resolvePodEndpointsWithEndpointsData(ctx conte
216
244
}
217
245
218
246
func (r * defaultEndpointResolver ) findServiceAndServicePort (ctx context.Context , svcKey types.NamespacedName , port intstr.IntOrString ) (* corev1.Service , corev1.ServicePort , error ) {
219
- svc := & corev1.Service {}
220
- if err := r .k8sClient .Get (ctx , svcKey , svc ); err != nil {
221
- if apierrors .IsNotFound (err ) {
222
- return nil , corev1.ServicePort {}, fmt .Errorf ("%w: %v" , ErrNotFound , err .Error ())
223
- }
247
+ svc , err := r .FindService (ctx , svcKey )
248
+ if err != nil {
224
249
return nil , corev1.ServicePort {}, err
225
250
}
251
+ return r .findServicePort (svc , port )
252
+ }
253
+
254
+ func (r * defaultEndpointResolver ) findServicePort (svc * corev1.Service , port intstr.IntOrString ) (* corev1.Service , corev1.ServicePort , error ) {
226
255
svcPort , err := k8s .LookupServicePort (svc , port )
227
256
if err != nil {
228
257
return nil , corev1.ServicePort {}, fmt .Errorf ("%w: %v" , ErrNotFound , err .Error ())
@@ -231,6 +260,17 @@ func (r *defaultEndpointResolver) findServiceAndServicePort(ctx context.Context,
231
260
return svc , svcPort , nil
232
261
}
233
262
263
+ func (r * defaultEndpointResolver ) FindService (ctx context.Context , svcKey types.NamespacedName ) (* corev1.Service , error ) {
264
+ svc := & corev1.Service {}
265
+ if err := r .k8sClient .Get (ctx , svcKey , svc ); err != nil {
266
+ if apierrors .IsNotFound (err ) {
267
+ return nil , fmt .Errorf ("%w: %v" , ErrNotFound , err .Error ())
268
+ }
269
+ return nil , err
270
+ }
271
+ return svc , nil
272
+ }
273
+
234
274
// filterNodesByReadyConditionStatus will filter out nodes that matches specified ready condition status
235
275
func filterNodesByReadyConditionStatus (nodes []* corev1.Node , readyCondStatus corev1.ConditionStatus ) []* corev1.Node {
236
276
var nodesWithMatchingReadyStatus []* corev1.Node
@@ -283,8 +323,8 @@ func buildEndpointsDataFromEndpointSliceList(epsList *discovery.EndpointSliceLis
283
323
return endpointsDataList
284
324
}
285
325
286
- func buildPodEndpoint (pod k8s.PodInfo , epAddr string , port int32 ) PodEndpoint {
287
- return PodEndpoint {
326
+ func buildPodEndpoint (pod * k8s.PodInfo , epAddr string , port int32 ) IpEndpoint {
327
+ return IpEndpoint {
288
328
IP : epAddr ,
289
329
Port : port ,
290
330
Pod : pod ,
0 commit comments