k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/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 trafficDistFeatureEnabled bool 53 pteEnabled bool 54 nodeLabels map[string]string 55 serviceInfo ServicePort 56 endpoints []Endpoint 57 58 // We distinguish `nil` ("service doesn't use this kind of endpoints") from 59 // `sets.Set[string]()` ("service uses this kind of endpoints but has no endpoints"). 60 // allEndpoints can be left unset if only one of clusterEndpoints and 61 // localEndpoints is set, and allEndpoints is identical to it. 62 // onlyRemoteEndpoints should be true if CategorizeEndpoints returns true for 63 // hasAnyEndpoints despite allEndpoints being empty. 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 featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.TopologyAwareHints, tc.hintsEnabled) 492 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 }