1
16
17 package proxy
18
19 import (
20 "fmt"
21 "testing"
22
23 v1 "k8s.io/api/core/v1"
24 kerrors "k8s.io/apimachinery/pkg/util/errors"
25 "k8s.io/apimachinery/pkg/util/sets"
26 utilfeature "k8s.io/apiserver/pkg/util/feature"
27 featuregatetesting "k8s.io/component-base/featuregate/testing"
28 "k8s.io/kubernetes/pkg/features"
29 )
30
31 func checkExpectedEndpoints(expected sets.Set[string], actual []Endpoint) error {
32 var errs []error
33
34 expectedCopy := sets.New[string](expected.UnsortedList()...)
35 for _, ep := range actual {
36 if !expectedCopy.Has(ep.String()) {
37 errs = append(errs, fmt.Errorf("unexpected endpoint %v", ep))
38 }
39 expectedCopy.Delete(ep.String())
40 }
41 if len(expectedCopy) > 0 {
42 errs = append(errs, fmt.Errorf("missing endpoints %v", expectedCopy.UnsortedList()))
43 }
44
45 return kerrors.NewAggregate(errs)
46 }
47
48 func TestCategorizeEndpoints(t *testing.T) {
49 testCases := []struct {
50 name string
51 hintsEnabled bool
52 trafficDistFeatureEnabled bool
53 pteEnabled bool
54 nodeLabels map[string]string
55 serviceInfo ServicePort
56 endpoints []Endpoint
57
58
59
60
61
62
63
64 clusterEndpoints sets.Set[string]
65 localEndpoints sets.Set[string]
66 allEndpoints sets.Set[string]
67 onlyRemoteEndpoints bool
68 }{{
69 name: "hints enabled, hints annotation == auto",
70 hintsEnabled: true,
71 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
72 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "auto"},
73 endpoints: []Endpoint{
74 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true},
75 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true},
76 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true},
77 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true},
78 },
79 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.6:80"),
80 localEndpoints: nil,
81 }, {
82 name: "hints, hints annotation == disabled, hints ignored",
83 hintsEnabled: true,
84 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
85 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "disabled"},
86 endpoints: []Endpoint{
87 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true},
88 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true},
89 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true},
90 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true},
91 },
92 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.4:80", "10.1.2.5:80", "10.1.2.6:80"),
93 localEndpoints: nil,
94 }, {
95 name: "hints disabled, hints annotation == auto",
96 hintsEnabled: false,
97 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
98 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "auto"},
99 endpoints: []Endpoint{
100 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true},
101 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true},
102 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true},
103 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true},
104 },
105 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.4:80", "10.1.2.5:80", "10.1.2.6:80"),
106 localEndpoints: nil,
107 }, {
108
109 name: "hints, hints annotation == aUto (wrong capitalization), hints no longer ignored",
110 hintsEnabled: true,
111 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
112 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "aUto"},
113 endpoints: []Endpoint{
114 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true},
115 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true},
116 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true},
117 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true},
118 },
119 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.6:80"),
120 localEndpoints: nil,
121 }, {
122 name: "hints, hints annotation empty, hints ignored",
123 hintsEnabled: true,
124 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
125 serviceInfo: &BaseServicePortInfo{},
126 endpoints: []Endpoint{
127 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true},
128 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true},
129 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true},
130 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true},
131 },
132 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.4:80", "10.1.2.5:80", "10.1.2.6:80"),
133 localEndpoints: nil,
134 }, {
135 name: "hints, hints annotation empty but trafficDist feature gate enabled, hints are not ignored",
136 hintsEnabled: true,
137 trafficDistFeatureEnabled: true,
138 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
139 serviceInfo: &BaseServicePortInfo{},
140 endpoints: []Endpoint{
141 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true},
142 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true},
143 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true},
144 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true},
145 },
146 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.6:80"),
147 localEndpoints: nil,
148 }, {
149 name: "hints disabled, trafficDist feature gate enabled, hints are not ignored",
150 hintsEnabled: false,
151 trafficDistFeatureEnabled: true,
152 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
153 serviceInfo: &BaseServicePortInfo{},
154 endpoints: []Endpoint{
155 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true},
156 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true},
157 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true},
158 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true},
159 },
160 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.6:80"),
161 localEndpoints: nil,
162 }, {
163 name: "externalTrafficPolicy: Local, topology ignored for Local endpoints",
164 hintsEnabled: true,
165 trafficDistFeatureEnabled: true,
166 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
167 serviceInfo: &BaseServicePortInfo{externalPolicyLocal: true, nodePort: 8080, hintsAnnotation: "auto"},
168 endpoints: []Endpoint{
169 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true, isLocal: true},
170 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true, isLocal: true},
171 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true},
172 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true},
173 },
174 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.6:80"),
175 localEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.4:80"),
176 allEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.4:80", "10.1.2.6:80"),
177 }, {
178 name: "internalTrafficPolicy: Local, topology ignored for Local endpoints",
179 hintsEnabled: true,
180 trafficDistFeatureEnabled: true,
181 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
182 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: true, hintsAnnotation: "auto", externalPolicyLocal: false, nodePort: 8080},
183 endpoints: []Endpoint{
184 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true, isLocal: true},
185 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true, isLocal: true},
186 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true},
187 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true},
188 },
189 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.6:80"),
190 localEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.4:80"),
191 allEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.4:80", "10.1.2.6:80"),
192 }, {
193 name: "empty node labels",
194 hintsEnabled: true,
195 nodeLabels: map[string]string{},
196 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "auto"},
197 endpoints: []Endpoint{
198 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true},
199 },
200 clusterEndpoints: sets.New[string]("10.1.2.3:80"),
201 localEndpoints: nil,
202 }, {
203 name: "empty zone label",
204 hintsEnabled: true,
205 nodeLabels: map[string]string{v1.LabelTopologyZone: ""},
206 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "auto"},
207 endpoints: []Endpoint{
208 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true},
209 },
210 clusterEndpoints: sets.New[string]("10.1.2.3:80"),
211 localEndpoints: nil,
212 }, {
213 name: "node in different zone, no endpoint filtering",
214 hintsEnabled: true,
215 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-b"},
216 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "auto"},
217 endpoints: []Endpoint{
218 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true},
219 },
220 clusterEndpoints: sets.New[string]("10.1.2.3:80"),
221 localEndpoints: nil,
222 }, {
223 name: "normal endpoint filtering, auto annotation",
224 hintsEnabled: true,
225 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
226 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "auto"},
227 endpoints: []Endpoint{
228 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true},
229 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true},
230 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true},
231 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true},
232 },
233 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.6:80"),
234 localEndpoints: nil,
235 }, {
236 name: "unready endpoint",
237 hintsEnabled: true,
238 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
239 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "auto"},
240 endpoints: []Endpoint{
241 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true},
242 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true},
243 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true},
244 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: false},
245 },
246 clusterEndpoints: sets.New[string]("10.1.2.3:80"),
247 localEndpoints: nil,
248 }, {
249 name: "only unready endpoints in same zone (should not filter)",
250 hintsEnabled: true,
251 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
252 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "auto"},
253 endpoints: []Endpoint{
254 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: false},
255 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true},
256 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true},
257 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: false},
258 },
259 clusterEndpoints: sets.New[string]("10.1.2.4:80", "10.1.2.5:80"),
260 localEndpoints: nil,
261 }, {
262 name: "normal endpoint filtering, Auto annotation",
263 hintsEnabled: true,
264 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
265 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "Auto"},
266 endpoints: []Endpoint{
267 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true},
268 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true},
269 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true},
270 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true},
271 },
272 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.6:80"),
273 localEndpoints: nil,
274 }, {
275 name: "hintsAnnotation empty, no filtering applied",
276 hintsEnabled: true,
277 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
278 serviceInfo: &BaseServicePortInfo{hintsAnnotation: ""},
279 endpoints: []Endpoint{
280 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true},
281 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true},
282 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true},
283 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true},
284 },
285 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.4:80", "10.1.2.5:80", "10.1.2.6:80"),
286 localEndpoints: nil,
287 }, {
288 name: "hintsAnnotation disabled, no filtering applied",
289 hintsEnabled: true,
290 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
291 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "disabled"},
292 endpoints: []Endpoint{
293 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true},
294 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true},
295 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true},
296 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true},
297 },
298 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.4:80", "10.1.2.5:80", "10.1.2.6:80"),
299 localEndpoints: nil,
300 }, {
301 name: "missing hints, no filtering applied",
302 hintsEnabled: true,
303 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
304 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "auto"},
305 endpoints: []Endpoint{
306 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true},
307 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true},
308 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: nil, ready: true},
309 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true},
310 },
311 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.4:80", "10.1.2.5:80", "10.1.2.6:80"),
312 localEndpoints: nil,
313 }, {
314 name: "multiple hints per endpoint, filtering includes any endpoint with zone included",
315 hintsEnabled: true,
316 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-c"},
317 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "auto"},
318 endpoints: []Endpoint{
319 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a", "zone-b", "zone-c"), ready: true},
320 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b", "zone-c"), ready: true},
321 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-b", "zone-d"), ready: true},
322 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-c"), ready: true},
323 },
324 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.4:80", "10.1.2.6:80"),
325 localEndpoints: nil,
326 }, {
327 name: "conflicting topology and localness require merging allEndpoints",
328 hintsEnabled: true,
329 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
330 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: false, externalPolicyLocal: true, nodePort: 8080, hintsAnnotation: "auto"},
331 endpoints: []Endpoint{
332 &BaseEndpointInfo{endpoint: "10.0.0.0:80", zoneHints: sets.New[string]("zone-a"), ready: true, isLocal: true},
333 &BaseEndpointInfo{endpoint: "10.0.0.1:80", zoneHints: sets.New[string]("zone-b"), ready: true, isLocal: true},
334 &BaseEndpointInfo{endpoint: "10.0.0.2:80", zoneHints: sets.New[string]("zone-a"), ready: true, isLocal: false},
335 &BaseEndpointInfo{endpoint: "10.0.0.3:80", zoneHints: sets.New[string]("zone-b"), ready: true, isLocal: false},
336 },
337 clusterEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.2:80"),
338 localEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"),
339 allEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80", "10.0.0.2:80"),
340 }, {
341 name: "internalTrafficPolicy: Local, with empty endpoints",
342 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: true},
343 endpoints: []Endpoint{},
344 clusterEndpoints: nil,
345 localEndpoints: sets.New[string](),
346 }, {
347 name: "internalTrafficPolicy: Local, but all endpoints are remote",
348 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: true},
349 endpoints: []Endpoint{
350 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: true, isLocal: false},
351 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: true, isLocal: false},
352 },
353 clusterEndpoints: nil,
354 localEndpoints: sets.New[string](),
355 onlyRemoteEndpoints: true,
356 }, {
357 name: "internalTrafficPolicy: Local, all endpoints are local",
358 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: true},
359 endpoints: []Endpoint{
360 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: true, isLocal: true},
361 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: true, isLocal: true},
362 },
363 clusterEndpoints: nil,
364 localEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"),
365 }, {
366 name: "internalTrafficPolicy: Local, some endpoints are local",
367 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: true},
368 endpoints: []Endpoint{
369 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: true, isLocal: true},
370 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: true, isLocal: false},
371 },
372 clusterEndpoints: nil,
373 localEndpoints: sets.New[string]("10.0.0.0:80"),
374 }, {
375 name: "Cluster traffic policy, endpoints not Ready",
376 serviceInfo: &BaseServicePortInfo{},
377 endpoints: []Endpoint{
378 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: false},
379 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: false},
380 },
381 clusterEndpoints: sets.New[string](),
382 localEndpoints: nil,
383 }, {
384 name: "Cluster traffic policy, some endpoints are Ready",
385 serviceInfo: &BaseServicePortInfo{},
386 endpoints: []Endpoint{
387 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: false},
388 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: true},
389 },
390 clusterEndpoints: sets.New[string]("10.0.0.1:80"),
391 localEndpoints: nil,
392 }, {
393 name: "Cluster traffic policy, all endpoints are terminating",
394 pteEnabled: true,
395 serviceInfo: &BaseServicePortInfo{},
396 endpoints: []Endpoint{
397 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: false, serving: true, terminating: true, isLocal: true},
398 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: false, serving: true, terminating: true, isLocal: false},
399 },
400 clusterEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"),
401 localEndpoints: nil,
402 }, {
403 name: "iTP: Local, eTP: Cluster, some endpoints local",
404 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: true, externalPolicyLocal: false, nodePort: 8080},
405 endpoints: []Endpoint{
406 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: true, isLocal: true},
407 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: true, isLocal: false},
408 },
409 clusterEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"),
410 localEndpoints: sets.New[string]("10.0.0.0:80"),
411 allEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"),
412 }, {
413 name: "iTP: Cluster, eTP: Local, some endpoints local",
414 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: false, externalPolicyLocal: true, nodePort: 8080},
415 endpoints: []Endpoint{
416 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: true, isLocal: true},
417 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: true, isLocal: false},
418 },
419 clusterEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"),
420 localEndpoints: sets.New[string]("10.0.0.0:80"),
421 allEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"),
422 }, {
423 name: "iTP: Local, eTP: Local, some endpoints local",
424 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: true, externalPolicyLocal: true, nodePort: 8080},
425 endpoints: []Endpoint{
426 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: true, isLocal: true},
427 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: true, isLocal: false},
428 },
429 clusterEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"),
430 localEndpoints: sets.New[string]("10.0.0.0:80"),
431 allEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"),
432 }, {
433 name: "iTP: Local, eTP: Local, all endpoints remote",
434 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: true, externalPolicyLocal: true, nodePort: 8080},
435 endpoints: []Endpoint{
436 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: true, isLocal: false},
437 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: true, isLocal: false},
438 },
439 clusterEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"),
440 localEndpoints: sets.New[string](),
441 allEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"),
442 }, {
443 name: "iTP: Local, eTP: Local, all endpoints remote and terminating",
444 pteEnabled: true,
445 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: true, externalPolicyLocal: true, nodePort: 8080},
446 endpoints: []Endpoint{
447 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: false, serving: true, terminating: true, isLocal: false},
448 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: false, serving: true, terminating: true, isLocal: false},
449 },
450 clusterEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"),
451 localEndpoints: sets.New[string](),
452 allEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"),
453 onlyRemoteEndpoints: true,
454 }, {
455 name: "iTP: Cluster, eTP: Local, with terminating endpoints",
456 pteEnabled: true,
457 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: false, externalPolicyLocal: true, nodePort: 8080},
458 endpoints: []Endpoint{
459 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: true, isLocal: false},
460 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: false, serving: false, isLocal: true},
461 &BaseEndpointInfo{endpoint: "10.0.0.2:80", ready: false, serving: true, terminating: true, isLocal: true},
462 &BaseEndpointInfo{endpoint: "10.0.0.3:80", ready: false, serving: true, terminating: true, isLocal: false},
463 },
464 clusterEndpoints: sets.New[string]("10.0.0.0:80"),
465 localEndpoints: sets.New[string]("10.0.0.2:80"),
466 allEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.2:80"),
467 }, {
468 name: "externalTrafficPolicy ignored if not externally accessible",
469 serviceInfo: &BaseServicePortInfo{externalPolicyLocal: true},
470 endpoints: []Endpoint{
471 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: true, isLocal: false},
472 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: true, isLocal: true},
473 },
474 clusterEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"),
475 localEndpoints: nil,
476 allEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"),
477 }, {
478 name: "no cluster endpoints for iTP:Local internal-only service",
479 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: true},
480 endpoints: []Endpoint{
481 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: true, isLocal: false},
482 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: true, isLocal: true},
483 },
484 clusterEndpoints: nil,
485 localEndpoints: sets.New[string]("10.0.0.1:80"),
486 allEndpoints: sets.New[string]("10.0.0.1:80"),
487 }}
488
489 for _, tc := range testCases {
490 t.Run(tc.name, func(t *testing.T) {
491 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.TopologyAwareHints, tc.hintsEnabled)()
492 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ServiceTrafficDistribution, tc.trafficDistFeatureEnabled)()
493
494 clusterEndpoints, localEndpoints, allEndpoints, hasAnyEndpoints := CategorizeEndpoints(tc.endpoints, tc.serviceInfo, tc.nodeLabels)
495
496 if tc.clusterEndpoints == nil && clusterEndpoints != nil {
497 t.Errorf("expected no cluster endpoints but got %v", clusterEndpoints)
498 } else {
499 err := checkExpectedEndpoints(tc.clusterEndpoints, clusterEndpoints)
500 if err != nil {
501 t.Errorf("error with cluster endpoints: %v", err)
502 }
503 }
504
505 if tc.localEndpoints == nil && localEndpoints != nil {
506 t.Errorf("expected no local endpoints but got %v", localEndpoints)
507 } else {
508 err := checkExpectedEndpoints(tc.localEndpoints, localEndpoints)
509 if err != nil {
510 t.Errorf("error with local endpoints: %v", err)
511 }
512 }
513
514 var expectedAllEndpoints sets.Set[string]
515 if tc.clusterEndpoints != nil && tc.localEndpoints == nil {
516 expectedAllEndpoints = tc.clusterEndpoints
517 } else if tc.localEndpoints != nil && tc.clusterEndpoints == nil {
518 expectedAllEndpoints = tc.localEndpoints
519 } else {
520 expectedAllEndpoints = tc.allEndpoints
521 }
522 err := checkExpectedEndpoints(expectedAllEndpoints, allEndpoints)
523 if err != nil {
524 t.Errorf("error with allEndpoints: %v", err)
525 }
526
527 expectedHasAnyEndpoints := len(expectedAllEndpoints) > 0 || tc.onlyRemoteEndpoints
528 if expectedHasAnyEndpoints != hasAnyEndpoints {
529 t.Errorf("expected hasAnyEndpoints=%v, got %v", expectedHasAnyEndpoints, hasAnyEndpoints)
530 }
531 })
532 }
533 }
534
View as plain text