k8s.io/kubernetes@v1.29.3/pkg/proxy/topology_test.go (about) 1 /* 2 Copyright 2019 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 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 pteEnabled bool 53 nodeLabels map[string]string 54 serviceInfo ServicePort 55 endpoints []Endpoint 56 57 // We distinguish `nil` ("service doesn't use this kind of endpoints") from 58 // `sets.Set[string]()` ("service uses this kind of endpoints but has no endpoints"). 59 // allEndpoints can be left unset if only one of clusterEndpoints and 60 // localEndpoints is set, and allEndpoints is identical to it. 61 // onlyRemoteEndpoints should be true if CategorizeEndpoints returns true for 62 // hasAnyEndpoints despite allEndpoints being empty. 63 clusterEndpoints sets.Set[string] 64 localEndpoints sets.Set[string] 65 allEndpoints sets.Set[string] 66 onlyRemoteEndpoints bool 67 }{{ 68 name: "hints enabled, hints annotation == auto", 69 hintsEnabled: true, 70 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"}, 71 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "auto"}, 72 endpoints: []Endpoint{ 73 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 74 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true}, 75 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true}, 76 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 77 }, 78 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.6:80"), 79 localEndpoints: nil, 80 }, { 81 name: "hints, hints annotation == disabled, hints ignored", 82 hintsEnabled: true, 83 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"}, 84 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "disabled"}, 85 endpoints: []Endpoint{ 86 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 87 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true}, 88 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true}, 89 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 90 }, 91 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.4:80", "10.1.2.5:80", "10.1.2.6:80"), 92 localEndpoints: nil, 93 }, { 94 name: "hints disabled, hints annotation == auto", 95 hintsEnabled: false, 96 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"}, 97 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "auto"}, 98 endpoints: []Endpoint{ 99 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 100 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true}, 101 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true}, 102 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 103 }, 104 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.4:80", "10.1.2.5:80", "10.1.2.6:80"), 105 localEndpoints: nil, 106 }, { 107 108 name: "hints, hints annotation == aUto (wrong capitalization), hints no longer ignored", 109 hintsEnabled: true, 110 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"}, 111 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "aUto"}, 112 endpoints: []Endpoint{ 113 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 114 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true}, 115 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true}, 116 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 117 }, 118 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.6:80"), 119 localEndpoints: nil, 120 }, { 121 name: "hints, hints annotation empty, hints ignored", 122 hintsEnabled: true, 123 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"}, 124 serviceInfo: &BaseServicePortInfo{}, 125 endpoints: []Endpoint{ 126 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 127 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true}, 128 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true}, 129 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 130 }, 131 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.4:80", "10.1.2.5:80", "10.1.2.6:80"), 132 localEndpoints: nil, 133 }, { 134 name: "externalTrafficPolicy: Local, topology ignored for Local endpoints", 135 hintsEnabled: true, 136 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"}, 137 serviceInfo: &BaseServicePortInfo{externalPolicyLocal: true, nodePort: 8080, hintsAnnotation: "auto"}, 138 endpoints: []Endpoint{ 139 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true, isLocal: true}, 140 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true, isLocal: true}, 141 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true}, 142 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 143 }, 144 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.6:80"), 145 localEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.4:80"), 146 allEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.4:80", "10.1.2.6:80"), 147 }, { 148 name: "internalTrafficPolicy: Local, topology ignored for Local endpoints", 149 hintsEnabled: true, 150 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"}, 151 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: true, hintsAnnotation: "auto", externalPolicyLocal: false, nodePort: 8080}, 152 endpoints: []Endpoint{ 153 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true, isLocal: true}, 154 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true, isLocal: true}, 155 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true}, 156 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 157 }, 158 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.6:80"), 159 localEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.4:80"), 160 allEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.4:80", "10.1.2.6:80"), 161 }, { 162 name: "empty node labels", 163 hintsEnabled: true, 164 nodeLabels: map[string]string{}, 165 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "auto"}, 166 endpoints: []Endpoint{ 167 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 168 }, 169 clusterEndpoints: sets.New[string]("10.1.2.3:80"), 170 localEndpoints: nil, 171 }, { 172 name: "empty zone label", 173 hintsEnabled: true, 174 nodeLabels: map[string]string{v1.LabelTopologyZone: ""}, 175 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "auto"}, 176 endpoints: []Endpoint{ 177 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 178 }, 179 clusterEndpoints: sets.New[string]("10.1.2.3:80"), 180 localEndpoints: nil, 181 }, { 182 name: "node in different zone, no endpoint filtering", 183 hintsEnabled: true, 184 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-b"}, 185 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "auto"}, 186 endpoints: []Endpoint{ 187 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 188 }, 189 clusterEndpoints: sets.New[string]("10.1.2.3:80"), 190 localEndpoints: nil, 191 }, { 192 name: "normal endpoint filtering, auto annotation", 193 hintsEnabled: true, 194 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"}, 195 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "auto"}, 196 endpoints: []Endpoint{ 197 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 198 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true}, 199 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true}, 200 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 201 }, 202 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.6:80"), 203 localEndpoints: nil, 204 }, { 205 name: "unready endpoint", 206 hintsEnabled: true, 207 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"}, 208 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "auto"}, 209 endpoints: []Endpoint{ 210 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 211 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true}, 212 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true}, 213 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: false}, 214 }, 215 clusterEndpoints: sets.New[string]("10.1.2.3:80"), 216 localEndpoints: nil, 217 }, { 218 name: "only unready endpoints in same zone (should not filter)", 219 hintsEnabled: true, 220 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"}, 221 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "auto"}, 222 endpoints: []Endpoint{ 223 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: false}, 224 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true}, 225 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true}, 226 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: false}, 227 }, 228 clusterEndpoints: sets.New[string]("10.1.2.4:80", "10.1.2.5:80"), 229 localEndpoints: nil, 230 }, { 231 name: "normal endpoint filtering, Auto annotation", 232 hintsEnabled: true, 233 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"}, 234 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "Auto"}, 235 endpoints: []Endpoint{ 236 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 237 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true}, 238 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true}, 239 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 240 }, 241 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.6:80"), 242 localEndpoints: nil, 243 }, { 244 name: "hintsAnnotation empty, no filtering applied", 245 hintsEnabled: true, 246 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"}, 247 serviceInfo: &BaseServicePortInfo{hintsAnnotation: ""}, 248 endpoints: []Endpoint{ 249 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 250 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true}, 251 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true}, 252 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 253 }, 254 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.4:80", "10.1.2.5:80", "10.1.2.6:80"), 255 localEndpoints: nil, 256 }, { 257 name: "hintsAnnotation disabled, no filtering applied", 258 hintsEnabled: true, 259 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"}, 260 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "disabled"}, 261 endpoints: []Endpoint{ 262 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 263 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true}, 264 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-c"), ready: true}, 265 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 266 }, 267 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.4:80", "10.1.2.5:80", "10.1.2.6:80"), 268 localEndpoints: nil, 269 }, { 270 name: "missing hints, no filtering applied", 271 hintsEnabled: true, 272 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"}, 273 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "auto"}, 274 endpoints: []Endpoint{ 275 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 276 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b"), ready: true}, 277 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: nil, ready: true}, 278 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-a"), ready: true}, 279 }, 280 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.4:80", "10.1.2.5:80", "10.1.2.6:80"), 281 localEndpoints: nil, 282 }, { 283 name: "multiple hints per endpoint, filtering includes any endpoint with zone included", 284 hintsEnabled: true, 285 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-c"}, 286 serviceInfo: &BaseServicePortInfo{hintsAnnotation: "auto"}, 287 endpoints: []Endpoint{ 288 &BaseEndpointInfo{endpoint: "10.1.2.3:80", zoneHints: sets.New[string]("zone-a", "zone-b", "zone-c"), ready: true}, 289 &BaseEndpointInfo{endpoint: "10.1.2.4:80", zoneHints: sets.New[string]("zone-b", "zone-c"), ready: true}, 290 &BaseEndpointInfo{endpoint: "10.1.2.5:80", zoneHints: sets.New[string]("zone-b", "zone-d"), ready: true}, 291 &BaseEndpointInfo{endpoint: "10.1.2.6:80", zoneHints: sets.New[string]("zone-c"), ready: true}, 292 }, 293 clusterEndpoints: sets.New[string]("10.1.2.3:80", "10.1.2.4:80", "10.1.2.6:80"), 294 localEndpoints: nil, 295 }, { 296 name: "conflicting topology and localness require merging allEndpoints", 297 hintsEnabled: true, 298 nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"}, 299 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: false, externalPolicyLocal: true, nodePort: 8080, hintsAnnotation: "auto"}, 300 endpoints: []Endpoint{ 301 &BaseEndpointInfo{endpoint: "10.0.0.0:80", zoneHints: sets.New[string]("zone-a"), ready: true, isLocal: true}, 302 &BaseEndpointInfo{endpoint: "10.0.0.1:80", zoneHints: sets.New[string]("zone-b"), ready: true, isLocal: true}, 303 &BaseEndpointInfo{endpoint: "10.0.0.2:80", zoneHints: sets.New[string]("zone-a"), ready: true, isLocal: false}, 304 &BaseEndpointInfo{endpoint: "10.0.0.3:80", zoneHints: sets.New[string]("zone-b"), ready: true, isLocal: false}, 305 }, 306 clusterEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.2:80"), 307 localEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"), 308 allEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80", "10.0.0.2:80"), 309 }, { 310 name: "internalTrafficPolicy: Local, with empty endpoints", 311 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: true}, 312 endpoints: []Endpoint{}, 313 clusterEndpoints: nil, 314 localEndpoints: sets.New[string](), 315 }, { 316 name: "internalTrafficPolicy: Local, but all endpoints are remote", 317 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: true}, 318 endpoints: []Endpoint{ 319 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: true, isLocal: false}, 320 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: true, isLocal: false}, 321 }, 322 clusterEndpoints: nil, 323 localEndpoints: sets.New[string](), 324 onlyRemoteEndpoints: true, 325 }, { 326 name: "internalTrafficPolicy: Local, all endpoints are local", 327 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: true}, 328 endpoints: []Endpoint{ 329 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: true, isLocal: true}, 330 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: true, isLocal: true}, 331 }, 332 clusterEndpoints: nil, 333 localEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"), 334 }, { 335 name: "internalTrafficPolicy: Local, some endpoints are local", 336 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: true}, 337 endpoints: []Endpoint{ 338 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: true, isLocal: true}, 339 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: true, isLocal: false}, 340 }, 341 clusterEndpoints: nil, 342 localEndpoints: sets.New[string]("10.0.0.0:80"), 343 }, { 344 name: "Cluster traffic policy, endpoints not Ready", 345 serviceInfo: &BaseServicePortInfo{}, 346 endpoints: []Endpoint{ 347 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: false}, 348 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: false}, 349 }, 350 clusterEndpoints: sets.New[string](), 351 localEndpoints: nil, 352 }, { 353 name: "Cluster traffic policy, some endpoints are Ready", 354 serviceInfo: &BaseServicePortInfo{}, 355 endpoints: []Endpoint{ 356 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: false}, 357 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: true}, 358 }, 359 clusterEndpoints: sets.New[string]("10.0.0.1:80"), 360 localEndpoints: nil, 361 }, { 362 name: "Cluster traffic policy, all endpoints are terminating", 363 pteEnabled: true, 364 serviceInfo: &BaseServicePortInfo{}, 365 endpoints: []Endpoint{ 366 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: false, serving: true, terminating: true, isLocal: true}, 367 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: false, serving: true, terminating: true, isLocal: false}, 368 }, 369 clusterEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"), 370 localEndpoints: nil, 371 }, { 372 name: "iTP: Local, eTP: Cluster, some endpoints local", 373 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: true, externalPolicyLocal: false, nodePort: 8080}, 374 endpoints: []Endpoint{ 375 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: true, isLocal: true}, 376 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: true, isLocal: false}, 377 }, 378 clusterEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"), 379 localEndpoints: sets.New[string]("10.0.0.0:80"), 380 allEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"), 381 }, { 382 name: "iTP: Cluster, eTP: Local, some endpoints local", 383 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: false, externalPolicyLocal: true, nodePort: 8080}, 384 endpoints: []Endpoint{ 385 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: true, isLocal: true}, 386 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: true, isLocal: false}, 387 }, 388 clusterEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"), 389 localEndpoints: sets.New[string]("10.0.0.0:80"), 390 allEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"), 391 }, { 392 name: "iTP: Local, eTP: Local, some endpoints local", 393 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: true, externalPolicyLocal: true, nodePort: 8080}, 394 endpoints: []Endpoint{ 395 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: true, isLocal: true}, 396 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: true, isLocal: false}, 397 }, 398 clusterEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"), 399 localEndpoints: sets.New[string]("10.0.0.0:80"), 400 allEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"), 401 }, { 402 name: "iTP: Local, eTP: Local, all endpoints remote", 403 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: true, externalPolicyLocal: true, nodePort: 8080}, 404 endpoints: []Endpoint{ 405 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: true, isLocal: false}, 406 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: true, isLocal: false}, 407 }, 408 clusterEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"), 409 localEndpoints: sets.New[string](), 410 allEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"), 411 }, { 412 name: "iTP: Local, eTP: Local, all endpoints remote and terminating", 413 pteEnabled: true, 414 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: true, externalPolicyLocal: true, nodePort: 8080}, 415 endpoints: []Endpoint{ 416 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: false, serving: true, terminating: true, isLocal: false}, 417 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: false, serving: true, terminating: true, isLocal: false}, 418 }, 419 clusterEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"), 420 localEndpoints: sets.New[string](), 421 allEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"), 422 onlyRemoteEndpoints: true, 423 }, { 424 name: "iTP: Cluster, eTP: Local, with terminating endpoints", 425 pteEnabled: true, 426 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: false, externalPolicyLocal: true, nodePort: 8080}, 427 endpoints: []Endpoint{ 428 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: true, isLocal: false}, 429 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: false, serving: false, isLocal: true}, 430 &BaseEndpointInfo{endpoint: "10.0.0.2:80", ready: false, serving: true, terminating: true, isLocal: true}, 431 &BaseEndpointInfo{endpoint: "10.0.0.3:80", ready: false, serving: true, terminating: true, isLocal: false}, 432 }, 433 clusterEndpoints: sets.New[string]("10.0.0.0:80"), 434 localEndpoints: sets.New[string]("10.0.0.2:80"), 435 allEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.2:80"), 436 }, { 437 name: "externalTrafficPolicy ignored if not externally accessible", 438 serviceInfo: &BaseServicePortInfo{externalPolicyLocal: true}, 439 endpoints: []Endpoint{ 440 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: true, isLocal: false}, 441 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: true, isLocal: true}, 442 }, 443 clusterEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"), 444 localEndpoints: nil, 445 allEndpoints: sets.New[string]("10.0.0.0:80", "10.0.0.1:80"), 446 }, { 447 name: "no cluster endpoints for iTP:Local internal-only service", 448 serviceInfo: &BaseServicePortInfo{internalPolicyLocal: true}, 449 endpoints: []Endpoint{ 450 &BaseEndpointInfo{endpoint: "10.0.0.0:80", ready: true, isLocal: false}, 451 &BaseEndpointInfo{endpoint: "10.0.0.1:80", ready: true, isLocal: true}, 452 }, 453 clusterEndpoints: nil, 454 localEndpoints: sets.New[string]("10.0.0.1:80"), 455 allEndpoints: sets.New[string]("10.0.0.1:80"), 456 }} 457 458 for _, tc := range testCases { 459 t.Run(tc.name, func(t *testing.T) { 460 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.TopologyAwareHints, tc.hintsEnabled)() 461 462 clusterEndpoints, localEndpoints, allEndpoints, hasAnyEndpoints := CategorizeEndpoints(tc.endpoints, tc.serviceInfo, tc.nodeLabels) 463 464 if tc.clusterEndpoints == nil && clusterEndpoints != nil { 465 t.Errorf("expected no cluster endpoints but got %v", clusterEndpoints) 466 } else { 467 err := checkExpectedEndpoints(tc.clusterEndpoints, clusterEndpoints) 468 if err != nil { 469 t.Errorf("error with cluster endpoints: %v", err) 470 } 471 } 472 473 if tc.localEndpoints == nil && localEndpoints != nil { 474 t.Errorf("expected no local endpoints but got %v", localEndpoints) 475 } else { 476 err := checkExpectedEndpoints(tc.localEndpoints, localEndpoints) 477 if err != nil { 478 t.Errorf("error with local endpoints: %v", err) 479 } 480 } 481 482 var expectedAllEndpoints sets.Set[string] 483 if tc.clusterEndpoints != nil && tc.localEndpoints == nil { 484 expectedAllEndpoints = tc.clusterEndpoints 485 } else if tc.localEndpoints != nil && tc.clusterEndpoints == nil { 486 expectedAllEndpoints = tc.localEndpoints 487 } else { 488 expectedAllEndpoints = tc.allEndpoints 489 } 490 err := checkExpectedEndpoints(expectedAllEndpoints, allEndpoints) 491 if err != nil { 492 t.Errorf("error with allEndpoints: %v", err) 493 } 494 495 expectedHasAnyEndpoints := len(expectedAllEndpoints) > 0 || tc.onlyRemoteEndpoints 496 if expectedHasAnyEndpoints != hasAnyEndpoints { 497 t.Errorf("expected hasAnyEndpoints=%v, got %v", expectedHasAnyEndpoints, hasAnyEndpoints) 498 } 499 }) 500 } 501 }