@@ -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 {
@@ -175,7 +203,7 @@ func (r *defaultEndpointResolver) resolvePodEndpointsWithEndpointsData(ctx conte
175
203
continue
176
204
}
177
205
178
- podEndpoint := buildPodEndpoint (pod , epAddr , epPort )
206
+ podEndpoint := buildPodEndpoint (& pod , epAddr , epPort )
179
207
// Recommendation from Kubernetes is to consider unknown ready status as ready (ready == nil)
180
208
if ep .Conditions .Ready == nil || * ep .Conditions .Ready {
181
209
readyPodEndpoints = append (readyPodEndpoints , podEndpoint )
@@ -220,13 +248,14 @@ func (r *defaultEndpointResolver) resolvePodEndpointsWithEndpointsData(ctx conte
220
248
}
221
249
222
250
func (r * defaultEndpointResolver ) findServiceAndServicePort (ctx context.Context , svcKey types.NamespacedName , port intstr.IntOrString ) (* corev1.Service , corev1.ServicePort , error ) {
223
- svc := & corev1.Service {}
224
- if err := r .k8sClient .Get (ctx , svcKey , svc ); err != nil {
225
- if apierrors .IsNotFound (err ) {
226
- return nil , corev1.ServicePort {}, fmt .Errorf ("%w: %v" , ErrNotFound , err .Error ())
227
- }
251
+ svc , err := r .FindService (ctx , svcKey )
252
+ if err != nil {
228
253
return nil , corev1.ServicePort {}, err
229
254
}
255
+ return r .findServicePort (svc , port )
256
+ }
257
+
258
+ func (r * defaultEndpointResolver ) findServicePort (svc * corev1.Service , port intstr.IntOrString ) (* corev1.Service , corev1.ServicePort , error ) {
230
259
svcPort , err := k8s .LookupServicePort (svc , port )
231
260
if err != nil {
232
261
return nil , corev1.ServicePort {}, fmt .Errorf ("%w: %v" , ErrNotFound , err .Error ())
@@ -235,6 +264,17 @@ func (r *defaultEndpointResolver) findServiceAndServicePort(ctx context.Context,
235
264
return svc , svcPort , nil
236
265
}
237
266
267
+ func (r * defaultEndpointResolver ) FindService (ctx context.Context , svcKey types.NamespacedName ) (* corev1.Service , error ) {
268
+ svc := & corev1.Service {}
269
+ if err := r .k8sClient .Get (ctx , svcKey , svc ); err != nil {
270
+ if apierrors .IsNotFound (err ) {
271
+ return nil , fmt .Errorf ("%w: %v" , ErrNotFound , err .Error ())
272
+ }
273
+ return nil , err
274
+ }
275
+ return svc , nil
276
+ }
277
+
238
278
// filterNodesByReadyConditionStatus will filter out nodes that matches specified ready condition status
239
279
func filterNodesByReadyConditionStatus (nodes []* corev1.Node , readyCondStatus corev1.ConditionStatus ) []* corev1.Node {
240
280
var nodesWithMatchingReadyStatus []* corev1.Node
@@ -287,8 +327,8 @@ func buildEndpointsDataFromEndpointSliceList(epsList *discovery.EndpointSliceLis
287
327
return endpointsDataList
288
328
}
289
329
290
- func buildPodEndpoint (pod k8s.PodInfo , epAddr string , port int32 ) PodEndpoint {
291
- return PodEndpoint {
330
+ func buildPodEndpoint (pod * k8s.PodInfo , epAddr string , port int32 ) IpEndpoint {
331
+ return IpEndpoint {
292
332
IP : epAddr ,
293
333
Port : port ,
294
334
Pod : pod ,
0 commit comments