...

Source file src/k8s.io/kubernetes/pkg/proxy/topology_test.go

Documentation: k8s.io/kubernetes/pkg/proxy

     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  			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