diff --git a/pkg/proxy/endpoints.go b/pkg/proxy/endpoints.go index 0de805dc2c1..0ef4a73e1b5 100644 --- a/pkg/proxy/endpoints.go +++ b/pkg/proxy/endpoints.go @@ -49,6 +49,23 @@ type BaseEndpointInfo struct { // IsLocal indicates whether the endpoint is running in same host as kube-proxy. IsLocal bool Topology map[string]string + + // Ready indicates whether this endpoint is ready and NOT terminating. + // For pods, this is true if a pod has a ready status and a nil deletion timestamp. + // This is only set when watching EndpointSlices. If using Endpoints, this is always + // true since only ready endpoints are read from Endpoints. + // TODO: Ready can be inferred from Serving and Terminating below when enabled by default. + Ready bool + // Serving indiciates whether this endpoint is ready regardless of its terminating state. + // For pods this is true if it has a ready status regardless of its deletion timestamp. + // This is only set when watching EndpointSlices. If using Endpoints, this is always + // true since only ready endpoints are read from Endpoints. + Serving bool + // Terminating indicates whether this endpoint is terminating. + // For pods this is true if it has a non-nil deletion timestamp. + // This is only set when watching EndpointSlices. If using Endpoints, this is always + // false since terminating endpoints are always excluded from Endpoints. + Terminating bool } var _ Endpoint = &BaseEndpointInfo{} @@ -63,6 +80,23 @@ func (info *BaseEndpointInfo) GetIsLocal() bool { return info.IsLocal } +// IsReady returns true if an endpoint is ready and not terminating. +func (info *BaseEndpointInfo) IsReady() bool { + return info.Ready +} + +// IsServing returns true if an endpoint is ready, regardless of if the +// endpoint is terminating. +func (info *BaseEndpointInfo) IsServing() bool { + return info.Serving +} + +// IsTerminating retruns true if an endpoint is terminating. For pods, +// that is any pod with a deletion timestamp. +func (info *BaseEndpointInfo) IsTerminating() bool { + return info.Terminating +} + // GetTopology returns the topology information of the endpoint. func (info *BaseEndpointInfo) GetTopology() map[string]string { return info.Topology @@ -83,11 +117,15 @@ func (info *BaseEndpointInfo) Equal(other Endpoint) bool { return info.String() == other.String() && info.GetIsLocal() == other.GetIsLocal() } -func newBaseEndpointInfo(IP string, port int, isLocal bool, topology map[string]string) *BaseEndpointInfo { +func newBaseEndpointInfo(IP string, port int, isLocal bool, topology map[string]string, + ready, serving, terminating bool) *BaseEndpointInfo { return &BaseEndpointInfo{ - Endpoint: net.JoinHostPort(IP, strconv.Itoa(port)), - IsLocal: isLocal, - Topology: topology, + Endpoint: net.JoinHostPort(IP, strconv.Itoa(port)), + IsLocal: isLocal, + Topology: topology, + Ready: ready, + Serving: serving, + Terminating: terminating, } } @@ -331,7 +369,7 @@ func (em EndpointsMap) Update(changes *EndpointChangeTracker) (result UpdateEndp // TODO: If this will appear to be computationally expensive, consider // computing this incrementally similarly to endpointsMap. result.HCEndpointsLocalIPSize = make(map[types.NamespacedName]int) - localIPs := em.getLocalEndpointIPs() + localIPs := em.getLocalReadyEndpointIPs() for nsn, ips := range localIPs { result.HCEndpointsLocalIPSize[nsn] = len(ips) } @@ -383,8 +421,14 @@ func (ect *EndpointChangeTracker) endpointsToEndpointsMap(endpoints *v1.Endpoint continue } + // it is safe to assume that any address in endpoints.subsets[*].addresses is + // ready and NOT terminating + isReady := true + isServing := true + isTerminating := false isLocal := addr.NodeName != nil && *addr.NodeName == ect.hostname - baseEndpointInfo := newBaseEndpointInfo(addr.IP, int(port.Port), isLocal, nil) + + baseEndpointInfo := newBaseEndpointInfo(addr.IP, int(port.Port), isLocal, nil, isReady, isServing, isTerminating) if ect.makeEndpointInfo != nil { endpointsMap[svcPortName] = append(endpointsMap[svcPortName], ect.makeEndpointInfo(baseEndpointInfo)) } else { @@ -437,10 +481,16 @@ func (em EndpointsMap) unmerge(other EndpointsMap) { } // GetLocalEndpointIPs returns endpoints IPs if given endpoint is local - local means the endpoint is running in same host as kube-proxy. -func (em EndpointsMap) getLocalEndpointIPs() map[types.NamespacedName]sets.String { +func (em EndpointsMap) getLocalReadyEndpointIPs() map[types.NamespacedName]sets.String { localIPs := make(map[types.NamespacedName]sets.String) for svcPortName, epList := range em { for _, ep := range epList { + // Only add ready endpoints for health checking. Terminating endpoints may still serve traffic + // but the health check signal should fail if there are only terminating endpoints on a node. + if !ep.IsReady() { + continue + } + if ep.GetIsLocal() { nsn := svcPortName.NamespacedName if localIPs[nsn] == nil { diff --git a/pkg/proxy/endpoints_test.go b/pkg/proxy/endpoints_test.go index 173e3182ebb..469521e8514 100644 --- a/pkg/proxy/endpoints_test.go +++ b/pkg/proxy/endpoints_test.go @@ -55,7 +55,7 @@ func TestGetLocalEndpointIPs(t *testing.T) { // Case[1]: unnamed port endpointsMap: EndpointsMap{ makeServicePortName("ns1", "ep1", "", v1.ProtocolTCP): []Endpoint{ - &BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}, + &BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expected: map[types.NamespacedName]sets.String{}, @@ -63,7 +63,7 @@ func TestGetLocalEndpointIPs(t *testing.T) { // Case[2]: unnamed port local endpointsMap: EndpointsMap{ makeServicePortName("ns1", "ep1", "", v1.ProtocolTCP): []Endpoint{ - &BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true}, + &BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expected: map[types.NamespacedName]sets.String{ @@ -73,12 +73,12 @@ func TestGetLocalEndpointIPs(t *testing.T) { // Case[3]: named local and non-local ports for the same IP. endpointsMap: EndpointsMap{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolTCP): []Endpoint{ - &BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}, - &BaseEndpointInfo{Endpoint: "1.1.1.2:11", IsLocal: true}, + &BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "1.1.1.2:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolTCP): []Endpoint{ - &BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: false}, - &BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: true}, + &BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expected: map[types.NamespacedName]sets.String{ @@ -88,32 +88,57 @@ func TestGetLocalEndpointIPs(t *testing.T) { // Case[4]: named local and non-local ports for different IPs. endpointsMap: EndpointsMap{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolTCP): []Endpoint{ - &BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}, + &BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns2", "ep2", "p22", v1.ProtocolTCP): []Endpoint{ - &BaseEndpointInfo{Endpoint: "2.2.2.2:22", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "2.2.2.22:22", IsLocal: true}, + &BaseEndpointInfo{Endpoint: "2.2.2.2:22", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "2.2.2.22:22", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns2", "ep2", "p23", v1.ProtocolTCP): []Endpoint{ - &BaseEndpointInfo{Endpoint: "2.2.2.3:23", IsLocal: true}, + &BaseEndpointInfo{Endpoint: "2.2.2.3:23", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns4", "ep4", "p44", v1.ProtocolTCP): []Endpoint{ - &BaseEndpointInfo{Endpoint: "4.4.4.4:44", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "4.4.4.5:44", IsLocal: false}, + &BaseEndpointInfo{Endpoint: "4.4.4.4:44", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "4.4.4.5:44", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns4", "ep4", "p45", v1.ProtocolTCP): []Endpoint{ - &BaseEndpointInfo{Endpoint: "4.4.4.6:45", IsLocal: true}, + &BaseEndpointInfo{Endpoint: "4.4.4.6:45", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expected: map[types.NamespacedName]sets.String{ {Namespace: "ns2", Name: "ep2"}: sets.NewString("2.2.2.2", "2.2.2.22", "2.2.2.3"), {Namespace: "ns4", Name: "ep4"}: sets.NewString("4.4.4.4", "4.4.4.6"), }, + }, { + // Case[5]: named local and non-local ports for different IPs, some not ready. + endpointsMap: EndpointsMap{ + makeServicePortName("ns1", "ep1", "p11", v1.ProtocolTCP): []Endpoint{ + &BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + }, + makeServicePortName("ns2", "ep2", "p22", v1.ProtocolTCP): []Endpoint{ + &BaseEndpointInfo{Endpoint: "2.2.2.2:22", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "2.2.2.22:22", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + }, + makeServicePortName("ns2", "ep2", "p23", v1.ProtocolTCP): []Endpoint{ + &BaseEndpointInfo{Endpoint: "2.2.2.3:23", IsLocal: true, Ready: false, Serving: true, Terminating: true}, + }, + makeServicePortName("ns4", "ep4", "p44", v1.ProtocolTCP): []Endpoint{ + &BaseEndpointInfo{Endpoint: "4.4.4.4:44", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "4.4.4.5:44", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + }, + makeServicePortName("ns4", "ep4", "p45", v1.ProtocolTCP): []Endpoint{ + &BaseEndpointInfo{Endpoint: "4.4.4.6:45", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + }, + }, + expected: map[types.NamespacedName]sets.String{ + {Namespace: "ns2", Name: "ep2"}: sets.NewString("2.2.2.2", "2.2.2.22"), + {Namespace: "ns4", Name: "ep4"}: sets.NewString("4.4.4.4", "4.4.4.6"), + }, }} for tci, tc := range testCases { // outputs - localIPs := tc.endpointsMap.getLocalEndpointIPs() + localIPs := tc.endpointsMap.getLocalReadyEndpointIPs() if !reflect.DeepEqual(localIPs, tc.expected) { t.Errorf("[%d] expected %#v, got %#v", tci, tc.expected, localIPs) @@ -169,7 +194,7 @@ func TestEndpointsToEndpointsMap(t *testing.T) { }), expected: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "", v1.ProtocolTCP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, }, @@ -193,7 +218,7 @@ func TestEndpointsToEndpointsMap(t *testing.T) { }), expected: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "port", v1.ProtocolTCP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, }, @@ -216,7 +241,7 @@ func TestEndpointsToEndpointsMap(t *testing.T) { }), expected: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "", v1.ProtocolTCP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, }, @@ -253,12 +278,12 @@ func TestEndpointsToEndpointsMap(t *testing.T) { }), expected: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p1", v1.ProtocolTCP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, - {Endpoint: "2.2.2.2:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "2.2.2.2:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p2", v1.ProtocolTCP): { - {Endpoint: "1.1.1.1:22", IsLocal: false}, - {Endpoint: "2.2.2.2:22", IsLocal: false}, + {Endpoint: "1.1.1.1:22", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "2.2.2.2:22", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, }, @@ -282,7 +307,7 @@ func TestEndpointsToEndpointsMap(t *testing.T) { }), expected: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p1", v1.ProtocolTCP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, }, @@ -306,7 +331,7 @@ func TestEndpointsToEndpointsMap(t *testing.T) { }), expected: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p2", v1.ProtocolTCP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, }, @@ -330,7 +355,7 @@ func TestEndpointsToEndpointsMap(t *testing.T) { }), expected: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p1", v1.ProtocolTCP): { - {Endpoint: "1.1.1.1:22", IsLocal: false}, + {Endpoint: "1.1.1.1:22", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, }, @@ -360,10 +385,10 @@ func TestEndpointsToEndpointsMap(t *testing.T) { }), expected: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p1", v1.ProtocolTCP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p2", v1.ProtocolTCP): { - {Endpoint: "1.1.1.1:22", IsLocal: false}, + {Endpoint: "1.1.1.1:22", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, }, @@ -393,10 +418,10 @@ func TestEndpointsToEndpointsMap(t *testing.T) { }), expected: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p1", v1.ProtocolTCP): { - {Endpoint: "[2001:db8:85a3:0:0:8a2e:370:7334]:11", IsLocal: false}, + {Endpoint: "[2001:db8:85a3:0:0:8a2e:370:7334]:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p2", v1.ProtocolTCP): { - {Endpoint: "[2001:db8:85a3:0:0:8a2e:370:7334]:22", IsLocal: false}, + {Endpoint: "[2001:db8:85a3:0:0:8a2e:370:7334]:22", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, }, @@ -795,12 +820,12 @@ func TestUpdateEndpointsMap(t *testing.T) { }, oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []ServiceEndpoint{}, @@ -816,12 +841,12 @@ func TestUpdateEndpointsMap(t *testing.T) { }, oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []ServiceEndpoint{}, @@ -839,18 +864,18 @@ func TestUpdateEndpointsMap(t *testing.T) { }, oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {Endpoint: "1.1.1.2:12", IsLocal: false}, + {Endpoint: "1.1.1.2:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {Endpoint: "1.1.1.2:12", IsLocal: false}, + {Endpoint: "1.1.1.2:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []ServiceEndpoint{}, @@ -866,24 +891,24 @@ func TestUpdateEndpointsMap(t *testing.T) { }, oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:12", IsLocal: true}, + {Endpoint: "1.1.1.1:12", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p13", v1.ProtocolUDP): { - {Endpoint: "1.1.1.3:13", IsLocal: false}, + {Endpoint: "1.1.1.3:13", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:12", IsLocal: true}, + {Endpoint: "1.1.1.1:12", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p13", v1.ProtocolUDP): { - {Endpoint: "1.1.1.3:13", IsLocal: false}, + {Endpoint: "1.1.1.3:13", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []ServiceEndpoint{}, @@ -903,54 +928,54 @@ func TestUpdateEndpointsMap(t *testing.T) { }, oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, - {Endpoint: "1.1.1.2:11", IsLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.2:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:12", IsLocal: false}, - {Endpoint: "1.1.1.2:12", IsLocal: true}, + {Endpoint: "1.1.1.1:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.2:12", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p13", v1.ProtocolUDP): { - {Endpoint: "1.1.1.3:13", IsLocal: false}, - {Endpoint: "1.1.1.4:13", IsLocal: true}, + {Endpoint: "1.1.1.3:13", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.4:13", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p14", v1.ProtocolUDP): { - {Endpoint: "1.1.1.3:14", IsLocal: false}, - {Endpoint: "1.1.1.4:14", IsLocal: true}, + {Endpoint: "1.1.1.3:14", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.4:14", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns2", "ep2", "p21", v1.ProtocolUDP): { - {Endpoint: "2.2.2.1:21", IsLocal: false}, - {Endpoint: "2.2.2.2:21", IsLocal: true}, + {Endpoint: "2.2.2.1:21", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "2.2.2.2:21", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns2", "ep2", "p22", v1.ProtocolUDP): { - {Endpoint: "2.2.2.1:22", IsLocal: false}, - {Endpoint: "2.2.2.2:22", IsLocal: true}, + {Endpoint: "2.2.2.1:22", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "2.2.2.2:22", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, - {Endpoint: "1.1.1.2:11", IsLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.2:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:12", IsLocal: false}, - {Endpoint: "1.1.1.2:12", IsLocal: true}, + {Endpoint: "1.1.1.1:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.2:12", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p13", v1.ProtocolUDP): { - {Endpoint: "1.1.1.3:13", IsLocal: false}, - {Endpoint: "1.1.1.4:13", IsLocal: true}, + {Endpoint: "1.1.1.3:13", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.4:13", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p14", v1.ProtocolUDP): { - {Endpoint: "1.1.1.3:14", IsLocal: false}, - {Endpoint: "1.1.1.4:14", IsLocal: true}, + {Endpoint: "1.1.1.3:14", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.4:14", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns2", "ep2", "p21", v1.ProtocolUDP): { - {Endpoint: "2.2.2.1:21", IsLocal: false}, - {Endpoint: "2.2.2.2:21", IsLocal: true}, + {Endpoint: "2.2.2.1:21", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "2.2.2.2:21", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns2", "ep2", "p22", v1.ProtocolUDP): { - {Endpoint: "2.2.2.1:22", IsLocal: false}, - {Endpoint: "2.2.2.2:22", IsLocal: true}, + {Endpoint: "2.2.2.1:22", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "2.2.2.2:22", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []ServiceEndpoint{}, @@ -970,7 +995,7 @@ func TestUpdateEndpointsMap(t *testing.T) { oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{}, expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []ServiceEndpoint{}, @@ -990,7 +1015,7 @@ func TestUpdateEndpointsMap(t *testing.T) { }, oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[ServicePortName][]*BaseEndpointInfo{}, @@ -1010,17 +1035,17 @@ func TestUpdateEndpointsMap(t *testing.T) { }, oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, - {Endpoint: "1.1.1.2:11", IsLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.2:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:12", IsLocal: false}, - {Endpoint: "1.1.1.2:12", IsLocal: true}, + {Endpoint: "1.1.1.1:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.2:12", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []ServiceEndpoint{}, @@ -1040,17 +1065,17 @@ func TestUpdateEndpointsMap(t *testing.T) { }, oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, - {Endpoint: "1.1.1.2:11", IsLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.2:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:12", IsLocal: false}, - {Endpoint: "1.1.1.2:12", IsLocal: true}, + {Endpoint: "1.1.1.1:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.2:12", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []ServiceEndpoint{{ @@ -1075,15 +1100,15 @@ func TestUpdateEndpointsMap(t *testing.T) { }, oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {Endpoint: "1.1.1.2:12", IsLocal: true}, + {Endpoint: "1.1.1.2:12", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []ServiceEndpoint{}, @@ -1103,15 +1128,15 @@ func TestUpdateEndpointsMap(t *testing.T) { }, oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {Endpoint: "1.1.1.2:12", IsLocal: false}, + {Endpoint: "1.1.1.2:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []ServiceEndpoint{{ @@ -1130,12 +1155,12 @@ func TestUpdateEndpointsMap(t *testing.T) { }, oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11-2", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []ServiceEndpoint{{ @@ -1156,12 +1181,12 @@ func TestUpdateEndpointsMap(t *testing.T) { }, oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:22", IsLocal: false}, + {Endpoint: "1.1.1.1:22", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []ServiceEndpoint{{ @@ -1186,39 +1211,39 @@ func TestUpdateEndpointsMap(t *testing.T) { }, oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns2", "ep2", "p22", v1.ProtocolUDP): { - {Endpoint: "2.2.2.2:22", IsLocal: true}, - {Endpoint: "2.2.2.22:22", IsLocal: true}, + {Endpoint: "2.2.2.2:22", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "2.2.2.22:22", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns2", "ep2", "p23", v1.ProtocolUDP): { - {Endpoint: "2.2.2.3:23", IsLocal: true}, + {Endpoint: "2.2.2.3:23", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns4", "ep4", "p44", v1.ProtocolUDP): { - {Endpoint: "4.4.4.4:44", IsLocal: true}, - {Endpoint: "4.4.4.5:44", IsLocal: true}, + {Endpoint: "4.4.4.4:44", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "4.4.4.5:44", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns4", "ep4", "p45", v1.ProtocolUDP): { - {Endpoint: "4.4.4.6:45", IsLocal: true}, + {Endpoint: "4.4.4.6:45", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, - {Endpoint: "1.1.1.11:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.11:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {Endpoint: "1.1.1.2:12", IsLocal: false}, + {Endpoint: "1.1.1.2:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p122", v1.ProtocolUDP): { - {Endpoint: "1.1.1.2:122", IsLocal: false}, + {Endpoint: "1.1.1.2:122", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns3", "ep3", "p33", v1.ProtocolUDP): { - {Endpoint: "3.3.3.3:33", IsLocal: false}, + {Endpoint: "3.3.3.3:33", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns4", "ep4", "p44", v1.ProtocolUDP): { - {Endpoint: "4.4.4.4:44", IsLocal: true}, + {Endpoint: "4.4.4.4:44", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []ServiceEndpoint{{ @@ -1256,7 +1281,7 @@ func TestUpdateEndpointsMap(t *testing.T) { oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{}, expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []ServiceEndpoint{}, @@ -1459,7 +1484,7 @@ func TestLastChangeTriggerTime(t *testing.T) { } func TestEndpointSliceUpdate(t *testing.T) { - fqdnSlice := generateEndpointSlice("svc1", "ns1", 2, 5, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}) + fqdnSlice := generateEndpointSlice("svc1", "ns1", 2, 5, 999, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}) fqdnSlice.AddressType = discovery.AddressTypeFQDN testCases := map[string]struct { @@ -1476,30 +1501,30 @@ func TestEndpointSliceUpdate(t *testing.T) { startingSlices: []*discovery.EndpointSlice{}, endpointChangeTracker: NewEndpointChangeTracker("host1", nil, v1.IPv4Protocol, nil, true, nil), namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"}, - paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 1, 3, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 1, 3, 999, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), paramRemoveSlice: false, expectedReturnVal: true, expectedCurrentChange: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "svc1", "port-0", v1.ProtocolTCP): { - &BaseEndpointInfo{Endpoint: "10.0.1.1:80"}, - &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.1.3:80"}, + &BaseEndpointInfo{Endpoint: "10.0.1.1:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.3:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "svc1", "port-1", v1.ProtocolTCP): { - &BaseEndpointInfo{Endpoint: "10.0.1.1:443"}, - &BaseEndpointInfo{Endpoint: "10.0.1.2:443", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.1.3:443"}, + &BaseEndpointInfo{Endpoint: "10.0.1.1:443", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.2:443", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.3:443", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, }, // test no modification to state - current change should be nil as nothing changes "add the same slice that already exists": { startingSlices: []*discovery.EndpointSlice{ - generateEndpointSlice("svc1", "ns1", 1, 3, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + generateEndpointSlice("svc1", "ns1", 1, 3, 999, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), }, endpointChangeTracker: NewEndpointChangeTracker("host1", nil, v1.IPv4Protocol, nil, true, nil), namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"}, - paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 1, 3, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 1, 3, 999, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), paramRemoveSlice: false, expectedReturnVal: false, expectedCurrentChange: nil, @@ -1507,7 +1532,7 @@ func TestEndpointSliceUpdate(t *testing.T) { // ensure that only valide address types are processed "add an FQDN slice (invalid address type)": { startingSlices: []*discovery.EndpointSlice{ - generateEndpointSlice("svc1", "ns1", 1, 3, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + generateEndpointSlice("svc1", "ns1", 1, 3, 999, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), }, endpointChangeTracker: NewEndpointChangeTracker("host1", nil, v1.IPv4Protocol, nil, true, nil), namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"}, @@ -1519,96 +1544,96 @@ func TestEndpointSliceUpdate(t *testing.T) { // test additions to existing state "add a slice that overlaps with existing state": { startingSlices: []*discovery.EndpointSlice{ - generateEndpointSlice("svc1", "ns1", 1, 3, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), - generateEndpointSlice("svc1", "ns1", 2, 2, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + generateEndpointSlice("svc1", "ns1", 1, 3, 999, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + generateEndpointSlice("svc1", "ns1", 2, 2, 999, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), }, endpointChangeTracker: NewEndpointChangeTracker("host1", nil, v1.IPv4Protocol, nil, true, nil), namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"}, - paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 1, 5, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 1, 5, 999, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), paramRemoveSlice: false, expectedReturnVal: true, expectedCurrentChange: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "svc1", "port-0", v1.ProtocolTCP): { - &BaseEndpointInfo{Endpoint: "10.0.1.1:80", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.1.3:80", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.1.4:80", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.1.5:80", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.2.1:80"}, - &BaseEndpointInfo{Endpoint: "10.0.2.2:80", IsLocal: true}, + &BaseEndpointInfo{Endpoint: "10.0.1.1:80", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.3:80", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.4:80", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.5:80", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.2.1:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.2.2:80", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "svc1", "port-1", v1.ProtocolTCP): { - &BaseEndpointInfo{Endpoint: "10.0.1.1:443", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.1.2:443", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.1.3:443", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.1.4:443", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.1.5:443", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.2.1:443"}, - &BaseEndpointInfo{Endpoint: "10.0.2.2:443", IsLocal: true}, + &BaseEndpointInfo{Endpoint: "10.0.1.1:443", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.2:443", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.3:443", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.4:443", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.5:443", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.2.1:443", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.2.2:443", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, }, // test additions to existing state with partially overlapping slices and ports "add a slice that overlaps with existing state and partial ports": { startingSlices: []*discovery.EndpointSlice{ - generateEndpointSlice("svc1", "ns1", 1, 3, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), - generateEndpointSlice("svc1", "ns1", 2, 2, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + generateEndpointSlice("svc1", "ns1", 1, 3, 999, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + generateEndpointSlice("svc1", "ns1", 2, 2, 999, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), }, endpointChangeTracker: NewEndpointChangeTracker("host1", nil, v1.IPv4Protocol, nil, true, nil), namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"}, - paramEndpointSlice: generateEndpointSliceWithOffset("svc1", "ns1", 3, 1, 5, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80)}), + paramEndpointSlice: generateEndpointSliceWithOffset("svc1", "ns1", 3, 1, 5, 999, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80)}), paramRemoveSlice: false, expectedReturnVal: true, expectedCurrentChange: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "svc1", "port-0", v1.ProtocolTCP): { - &BaseEndpointInfo{Endpoint: "10.0.1.1:80", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.1.3:80", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.1.4:80", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.1.5:80", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.2.1:80"}, - &BaseEndpointInfo{Endpoint: "10.0.2.2:80", IsLocal: true}, + &BaseEndpointInfo{Endpoint: "10.0.1.1:80", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.3:80", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.4:80", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.5:80", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.2.1:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.2.2:80", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "svc1", "port-1", v1.ProtocolTCP): { - &BaseEndpointInfo{Endpoint: "10.0.1.1:443"}, - &BaseEndpointInfo{Endpoint: "10.0.1.2:443", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.1.3:443"}, - &BaseEndpointInfo{Endpoint: "10.0.2.1:443"}, - &BaseEndpointInfo{Endpoint: "10.0.2.2:443", IsLocal: true}, + &BaseEndpointInfo{Endpoint: "10.0.1.1:443", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.2:443", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.3:443", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.2.1:443", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.2.2:443", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, }, // test deletions from existing state with partially overlapping slices and ports "remove a slice that overlaps with existing state": { startingSlices: []*discovery.EndpointSlice{ - generateEndpointSlice("svc1", "ns1", 1, 3, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), - generateEndpointSlice("svc1", "ns1", 2, 2, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + generateEndpointSlice("svc1", "ns1", 1, 3, 999, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + generateEndpointSlice("svc1", "ns1", 2, 2, 999, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), }, endpointChangeTracker: NewEndpointChangeTracker("host1", nil, v1.IPv4Protocol, nil, true, nil), namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"}, - paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 1, 5, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 1, 5, 999, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), paramRemoveSlice: true, expectedReturnVal: true, expectedCurrentChange: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "svc1", "port-0", v1.ProtocolTCP): { - &BaseEndpointInfo{Endpoint: "10.0.2.1:80"}, - &BaseEndpointInfo{Endpoint: "10.0.2.2:80", IsLocal: true}, + &BaseEndpointInfo{Endpoint: "10.0.2.1:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.2.2:80", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "svc1", "port-1", v1.ProtocolTCP): { - &BaseEndpointInfo{Endpoint: "10.0.2.1:443"}, - &BaseEndpointInfo{Endpoint: "10.0.2.2:443", IsLocal: true}, + &BaseEndpointInfo{Endpoint: "10.0.2.1:443", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.2.2:443", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, }, // ensure a removal that has no effect turns into a no-op "remove a slice that doesn't even exist in current state": { startingSlices: []*discovery.EndpointSlice{ - generateEndpointSlice("svc1", "ns1", 1, 5, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), - generateEndpointSlice("svc1", "ns1", 2, 2, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + generateEndpointSlice("svc1", "ns1", 1, 5, 999, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + generateEndpointSlice("svc1", "ns1", 2, 2, 999, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), }, endpointChangeTracker: NewEndpointChangeTracker("host1", nil, v1.IPv4Protocol, nil, true, nil), namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"}, - paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 3, 5, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 3, 5, 999, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), paramRemoveSlice: true, expectedReturnVal: false, expectedCurrentChange: nil, @@ -1616,57 +1641,100 @@ func TestEndpointSliceUpdate(t *testing.T) { // start with all endpoints ready, transition to no endpoints ready "transition all endpoints to unready state": { startingSlices: []*discovery.EndpointSlice{ - generateEndpointSlice("svc1", "ns1", 1, 3, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + generateEndpointSlice("svc1", "ns1", 1, 3, 999, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), }, endpointChangeTracker: NewEndpointChangeTracker("host1", nil, v1.IPv4Protocol, nil, true, nil), namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"}, - paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 1, 3, 1, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), - paramRemoveSlice: false, - expectedReturnVal: true, - expectedCurrentChange: map[ServicePortName][]*BaseEndpointInfo{}, - }, - // start with no endpoints ready, transition to all endpoints ready - "transition all endpoints to ready state": { - startingSlices: []*discovery.EndpointSlice{ - generateEndpointSlice("svc1", "ns1", 1, 2, 1, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), - }, - endpointChangeTracker: NewEndpointChangeTracker("host1", nil, v1.IPv4Protocol, nil, true, nil), - namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"}, - paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 1, 2, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 1, 3, 1, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), paramRemoveSlice: false, expectedReturnVal: true, expectedCurrentChange: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "svc1", "port-0", v1.ProtocolTCP): { - &BaseEndpointInfo{Endpoint: "10.0.1.1:80", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: true}, + &BaseEndpointInfo{Endpoint: "10.0.1.1:80", IsLocal: true, Ready: false, Serving: false, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: true, Ready: false, Serving: false, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.3:80", IsLocal: true, Ready: false, Serving: false, Terminating: false}, }, makeServicePortName("ns1", "svc1", "port-1", v1.ProtocolTCP): { - &BaseEndpointInfo{Endpoint: "10.0.1.1:443", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.1.2:443", IsLocal: true}, + &BaseEndpointInfo{Endpoint: "10.0.1.1:443", IsLocal: true, Ready: false, Serving: false, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.2:443", IsLocal: true, Ready: false, Serving: false, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.3:443", IsLocal: true, Ready: false, Serving: false, Terminating: false}, + }, + }, + }, + // start with no endpoints ready, transition to all endpoints ready + "transition all endpoints to ready state": { + startingSlices: []*discovery.EndpointSlice{ + generateEndpointSlice("svc1", "ns1", 1, 2, 1, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + }, + endpointChangeTracker: NewEndpointChangeTracker("host1", nil, v1.IPv4Protocol, nil, true, nil), + namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"}, + paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 1, 2, 999, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + paramRemoveSlice: false, + expectedReturnVal: true, + expectedCurrentChange: map[ServicePortName][]*BaseEndpointInfo{ + makeServicePortName("ns1", "svc1", "port-0", v1.ProtocolTCP): { + &BaseEndpointInfo{Endpoint: "10.0.1.1:80", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + }, + makeServicePortName("ns1", "svc1", "port-1", v1.ProtocolTCP): { + &BaseEndpointInfo{Endpoint: "10.0.1.1:443", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.2:443", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, }, // start with some endpoints ready, transition to more endpoints ready "transition some endpoints to ready state": { startingSlices: []*discovery.EndpointSlice{ - generateEndpointSlice("svc1", "ns1", 1, 3, 2, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), - generateEndpointSlice("svc1", "ns1", 2, 2, 2, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + generateEndpointSlice("svc1", "ns1", 1, 3, 2, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + generateEndpointSlice("svc1", "ns1", 2, 2, 2, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), }, endpointChangeTracker: NewEndpointChangeTracker("host1", nil, v1.IPv4Protocol, nil, true, nil), namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"}, - paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 1, 3, 3, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 1, 3, 3, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), paramRemoveSlice: false, expectedReturnVal: true, expectedCurrentChange: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "svc1", "port-0", v1.ProtocolTCP): { - &BaseEndpointInfo{Endpoint: "10.0.1.1:80", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.2.1:80", IsLocal: true}, + &BaseEndpointInfo{Endpoint: "10.0.1.1:80", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.3:80", IsLocal: true, Ready: false, Serving: false, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.2.1:80", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.2.2:80", IsLocal: true, Ready: false, Serving: false, Terminating: false}, }, makeServicePortName("ns1", "svc1", "port-1", v1.ProtocolTCP): { - &BaseEndpointInfo{Endpoint: "10.0.1.1:443", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.1.2:443", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.2.1:443", IsLocal: true}, + &BaseEndpointInfo{Endpoint: "10.0.1.1:443", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.2:443", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.3:443", IsLocal: true, Ready: false, Serving: false, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.2.1:443", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.2.2:443", IsLocal: true, Ready: false, Serving: false, Terminating: false}, + }, + }, + }, + // start with some endpoints ready, transition to some terminating + "transition some endpoints to terminating state": { + startingSlices: []*discovery.EndpointSlice{ + generateEndpointSlice("svc1", "ns1", 1, 3, 2, 2, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + generateEndpointSlice("svc1", "ns1", 2, 2, 2, 2, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + }, + endpointChangeTracker: NewEndpointChangeTracker("host1", nil, v1.IPv4Protocol, nil, true, nil), + namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"}, + paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 1, 3, 3, 2, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + paramRemoveSlice: false, + expectedReturnVal: true, + expectedCurrentChange: map[ServicePortName][]*BaseEndpointInfo{ + makeServicePortName("ns1", "svc1", "port-0", v1.ProtocolTCP): { + &BaseEndpointInfo{Endpoint: "10.0.1.1:80", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: true, Ready: false, Serving: true, Terminating: true}, + &BaseEndpointInfo{Endpoint: "10.0.1.3:80", IsLocal: true, Ready: false, Serving: false, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.2.1:80", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.2.2:80", IsLocal: true, Ready: false, Serving: false, Terminating: true}, + }, + makeServicePortName("ns1", "svc1", "port-1", v1.ProtocolTCP): { + &BaseEndpointInfo{Endpoint: "10.0.1.1:443", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.2:443", IsLocal: true, Ready: false, Serving: true, Terminating: true}, + &BaseEndpointInfo{Endpoint: "10.0.1.3:443", IsLocal: true, Ready: false, Serving: false, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.2.1:443", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.2.2:443", IsLocal: true, Ready: false, Serving: false, Terminating: true}, }, }, }, @@ -1727,21 +1795,21 @@ func TestCheckoutChanges(t *testing.T) { endpointChangeTracker: NewEndpointChangeTracker("", nil, v1.IPv4Protocol, nil, false, nil), expectedChanges: []*endpointsChange{{ previous: EndpointsMap{ - svcPortName0: []Endpoint{newTestEp("10.0.1.1:80", ""), newTestEp("10.0.1.2:80", "")}, - svcPortName1: []Endpoint{newTestEp("10.0.1.1:443", ""), newTestEp("10.0.1.2:443", "")}, + svcPortName0: []Endpoint{newTestEp("10.0.1.1:80", "", true, true, false), newTestEp("10.0.1.2:80", "", true, true, false)}, + svcPortName1: []Endpoint{newTestEp("10.0.1.1:443", "", true, true, false), newTestEp("10.0.1.2:443", "", true, true, false)}, }, current: EndpointsMap{ - svcPortName0: []Endpoint{newTestEp("10.0.1.1:80", ""), newTestEp("10.0.1.2:80", "")}, + svcPortName0: []Endpoint{newTestEp("10.0.1.1:80", "", true, true, false), newTestEp("10.0.1.2:80", "", true, true, false)}, }, }}, items: map[types.NamespacedName]*endpointsChange{ {Namespace: "ns1", Name: "svc1"}: { previous: EndpointsMap{ - svcPortName0: []Endpoint{newTestEp("10.0.1.1:80", ""), newTestEp("10.0.1.2:80", "")}, - svcPortName1: []Endpoint{newTestEp("10.0.1.1:443", ""), newTestEp("10.0.1.2:443", "")}, + svcPortName0: []Endpoint{newTestEp("10.0.1.1:80", "", true, true, false), newTestEp("10.0.1.2:80", "", true, true, false)}, + svcPortName1: []Endpoint{newTestEp("10.0.1.1:443", "", true, true, false), newTestEp("10.0.1.2:443", "", true, true, false)}, }, current: EndpointsMap{ - svcPortName0: []Endpoint{newTestEp("10.0.1.1:80", ""), newTestEp("10.0.1.2:80", "")}, + svcPortName0: []Endpoint{newTestEp("10.0.1.1:80", "", true, true, false), newTestEp("10.0.1.2:80", "", true, true, false)}, }, }, }, @@ -1752,32 +1820,32 @@ func TestCheckoutChanges(t *testing.T) { expectedChanges: []*endpointsChange{{ previous: EndpointsMap{}, current: EndpointsMap{ - svcPortName0: []Endpoint{newTestEp("10.0.1.1:80", "host1"), newTestEp("10.0.1.2:80", "host1")}, + svcPortName0: []Endpoint{newTestEp("10.0.1.1:80", "host1", true, true, false), newTestEp("10.0.1.2:80", "host1", false, true, true), newTestEp("10.0.1.3:80", "host1", false, false, false)}, }, }}, useEndpointSlices: true, appliedSlices: []*discovery.EndpointSlice{}, pendingSlices: []*discovery.EndpointSlice{ - generateEndpointSlice("svc1", "ns1", 1, 3, 3, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80)}), + generateEndpointSlice("svc1", "ns1", 1, 3, 3, 2, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80)}), }, }, "removing port in update": { endpointChangeTracker: NewEndpointChangeTracker("", nil, v1.IPv4Protocol, nil, true, nil), expectedChanges: []*endpointsChange{{ previous: EndpointsMap{ - svcPortName0: []Endpoint{newTestEp("10.0.1.1:80", "host1"), newTestEp("10.0.1.2:80", "host1")}, - svcPortName1: []Endpoint{newTestEp("10.0.1.1:443", "host1"), newTestEp("10.0.1.2:443", "host1")}, + svcPortName0: []Endpoint{newTestEp("10.0.1.1:80", "host1", true, true, false), newTestEp("10.0.1.2:80", "host1", true, true, false), newTestEp("10.0.1.3:80", "host1", false, false, false)}, + svcPortName1: []Endpoint{newTestEp("10.0.1.1:443", "host1", true, true, false), newTestEp("10.0.1.2:443", "host1", true, true, false), newTestEp("10.0.1.3:443", "host1", false, false, false)}, }, current: EndpointsMap{ - svcPortName0: []Endpoint{newTestEp("10.0.1.1:80", "host1"), newTestEp("10.0.1.2:80", "host1")}, + svcPortName0: []Endpoint{newTestEp("10.0.1.1:80", "host1", true, true, false), newTestEp("10.0.1.2:80", "host1", true, true, false), newTestEp("10.0.1.3:80", "host1", false, false, false)}, }, }}, useEndpointSlices: true, appliedSlices: []*discovery.EndpointSlice{ - generateEndpointSlice("svc1", "ns1", 1, 3, 3, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + generateEndpointSlice("svc1", "ns1", 1, 3, 3, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), }, pendingSlices: []*discovery.EndpointSlice{ - generateEndpointSlice("svc1", "ns1", 1, 3, 3, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80)}), + generateEndpointSlice("svc1", "ns1", 1, 3, 3, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80)}), }, }, } @@ -1825,7 +1893,7 @@ func compareEndpointsMapsStr(t *testing.T, newMap EndpointsMap, expected map[Ser t.Fatalf("expected %d results, got %d: %v", len(expected), len(newMap), newMap) } endpointEqual := func(a, b *BaseEndpointInfo) bool { - return a.Endpoint == b.Endpoint && a.IsLocal == b.IsLocal + return a.Endpoint == b.Endpoint && a.IsLocal == b.IsLocal && a.Ready == b.Ready && a.Serving == b.Serving && a.Terminating == b.Terminating } for x := range expected { if len(newMap[x]) != len(expected[x]) { @@ -1839,15 +1907,18 @@ func compareEndpointsMapsStr(t *testing.T, newMap EndpointsMap, expected map[Ser continue } if !endpointEqual(newEp, expected[x][i]) { - t.Fatalf("expected new[%v][%d] to be %v, got %v (IsLocal expected %v, got %v)", x, i, expected[x][i], newEp, expected[x][i].IsLocal, newEp.IsLocal) + t.Fatalf("expected new[%v][%d] to be %v, got %v"+ + "(IsLocal expected %v, got %v) (Ready expected %v, got %v) (Serving expected %v, got %v) (Terminating expected %v got %v)", + x, i, expected[x][i], newEp, expected[x][i].IsLocal, newEp.IsLocal, expected[x][i].Ready, newEp.Ready, + expected[x][i].Serving, newEp.Serving, expected[x][i].Terminating, newEp.Terminating) } } } } } -func newTestEp(ep, host string) *BaseEndpointInfo { - endpointInfo := &BaseEndpointInfo{Endpoint: ep} +func newTestEp(ep, host string, ready, serving, terminating bool) *BaseEndpointInfo { + endpointInfo := &BaseEndpointInfo{Endpoint: ep, Ready: ready, Serving: serving, Terminating: terminating} if host != "" { endpointInfo.Topology = map[string]string{ "kubernetes.io/hostname": host, diff --git a/pkg/proxy/endpointslicecache.go b/pkg/proxy/endpointslicecache.go index bb180adcfcd..59da3362914 100644 --- a/pkg/proxy/endpointslicecache.go +++ b/pkg/proxy/endpointslicecache.go @@ -80,6 +80,10 @@ type endpointInfo struct { Addresses []string NodeName *string Topology map[string]string + + Ready bool + Serving bool + Terminating bool } // spToEndpointMap stores groups Endpoint objects by ServicePortName and @@ -122,16 +126,21 @@ func newEndpointSliceInfo(endpointSlice *discovery.EndpointSlice, remove bool) * if !remove { for _, endpoint := range endpointSlice.Endpoints { - if endpoint.Conditions.Ready == nil || *endpoint.Conditions.Ready { - eInfo := endpointInfo{ - Addresses: endpoint.Addresses, - Topology: endpoint.Topology, - } - if utilfeature.DefaultFeatureGate.Enabled(features.EndpointSliceNodeName) { - eInfo.NodeName = endpoint.NodeName - } - esInfo.Endpoints = append(esInfo.Endpoints, &eInfo) + epInfo := &endpointInfo{ + Addresses: endpoint.Addresses, + Topology: endpoint.Topology, + + // conditions + Ready: endpoint.Conditions.Ready == nil || *endpoint.Conditions.Ready, + Serving: endpoint.Conditions.Serving == nil || *endpoint.Conditions.Serving, + Terminating: endpoint.Conditions.Terminating != nil && *endpoint.Conditions.Terminating, } + + if utilfeature.DefaultFeatureGate.Enabled(features.EndpointSliceNodeName) { + epInfo.NodeName = endpoint.NodeName + } + + esInfo.Endpoints = append(esInfo.Endpoints, epInfo) } sort.Sort(byAddress(esInfo.Endpoints)) @@ -269,7 +278,8 @@ func (cache *EndpointSliceCache) addEndpointsByIP(serviceNN types.NamespacedName isLocal = cache.isLocal(endpoint.Topology[v1.LabelHostname]) } - endpointInfo := newBaseEndpointInfo(endpoint.Addresses[0], portNum, isLocal, endpoint.Topology) + endpointInfo := newBaseEndpointInfo(endpoint.Addresses[0], portNum, isLocal, endpoint.Topology, + endpoint.Ready, endpoint.Serving, endpoint.Terminating) // This logic ensures we're deduping potential overlapping endpoints // isLocal should not vary between matching IPs, but if it does, we diff --git a/pkg/proxy/endpointslicecache_test.go b/pkg/proxy/endpointslicecache_test.go index ebe4afa7e1d..256c9878e5a 100644 --- a/pkg/proxy/endpointslicecache_test.go +++ b/pkg/proxy/endpointslicecache_test.go @@ -40,35 +40,35 @@ func TestEndpointsMapFromESC(t *testing.T) { namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"}, hostname: "host1", endpointSlices: []*discovery.EndpointSlice{ - generateEndpointSlice("svc1", "ns1", 1, 3, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), + generateEndpointSlice("svc1", "ns1", 1, 3, 999, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}), }, expectedMap: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "svc1", "port-0", v1.ProtocolTCP): { - &BaseEndpointInfo{Endpoint: "10.0.1.1:80", IsLocal: false}, - &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.1.3:80", IsLocal: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.1:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.3:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "svc1", "port-1", v1.ProtocolTCP): { - &BaseEndpointInfo{Endpoint: "10.0.1.1:443", IsLocal: false}, - &BaseEndpointInfo{Endpoint: "10.0.1.2:443", IsLocal: true}, - &BaseEndpointInfo{Endpoint: "10.0.1.3:443", IsLocal: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.1:443", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.2:443", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.3:443", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, }, "2 slices, same port": { namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"}, endpointSlices: []*discovery.EndpointSlice{ - generateEndpointSlice("svc1", "ns1", 1, 3, 999, []string{}, []*int32{utilpointer.Int32Ptr(80)}), - generateEndpointSlice("svc1", "ns1", 2, 3, 999, []string{}, []*int32{utilpointer.Int32Ptr(80)}), + generateEndpointSlice("svc1", "ns1", 1, 3, 999, 999, []string{}, []*int32{utilpointer.Int32Ptr(80)}), + generateEndpointSlice("svc1", "ns1", 2, 3, 999, 999, []string{}, []*int32{utilpointer.Int32Ptr(80)}), }, expectedMap: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "svc1", "port-0", v1.ProtocolTCP): { - &BaseEndpointInfo{Endpoint: "10.0.1.1:80"}, - &BaseEndpointInfo{Endpoint: "10.0.1.2:80"}, - &BaseEndpointInfo{Endpoint: "10.0.1.3:80"}, - &BaseEndpointInfo{Endpoint: "10.0.2.1:80"}, - &BaseEndpointInfo{Endpoint: "10.0.2.2:80"}, - &BaseEndpointInfo{Endpoint: "10.0.2.3:80"}, + &BaseEndpointInfo{Endpoint: "10.0.1.1:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.3:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.2.1:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.2.2:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.2.3:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, }, @@ -77,15 +77,15 @@ func TestEndpointsMapFromESC(t *testing.T) { "2 overlapping slices, same port": { namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"}, endpointSlices: []*discovery.EndpointSlice{ - generateEndpointSlice("svc1", "ns1", 1, 3, 999, []string{}, []*int32{utilpointer.Int32Ptr(80)}), - generateEndpointSlice("svc1", "ns1", 1, 4, 999, []string{}, []*int32{utilpointer.Int32Ptr(80)}), + generateEndpointSlice("svc1", "ns1", 1, 3, 999, 999, []string{}, []*int32{utilpointer.Int32Ptr(80)}), + generateEndpointSlice("svc1", "ns1", 1, 4, 999, 999, []string{}, []*int32{utilpointer.Int32Ptr(80)}), }, expectedMap: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "svc1", "port-0", v1.ProtocolTCP): { - &BaseEndpointInfo{Endpoint: "10.0.1.1:80"}, - &BaseEndpointInfo{Endpoint: "10.0.1.2:80"}, - &BaseEndpointInfo{Endpoint: "10.0.1.3:80"}, - &BaseEndpointInfo{Endpoint: "10.0.1.4:80"}, + &BaseEndpointInfo{Endpoint: "10.0.1.1:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.3:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.4:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, }, @@ -96,43 +96,79 @@ func TestEndpointsMapFromESC(t *testing.T) { "2 slices, overlapping endpoints, some endpoints unready in 1 or both": { namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"}, endpointSlices: []*discovery.EndpointSlice{ - generateEndpointSlice("svc1", "ns1", 1, 10, 3, []string{}, []*int32{utilpointer.Int32Ptr(80)}), - generateEndpointSlice("svc1", "ns1", 1, 10, 6, []string{}, []*int32{utilpointer.Int32Ptr(80)}), + generateEndpointSlice("svc1", "ns1", 1, 10, 3, 999, []string{}, []*int32{utilpointer.Int32Ptr(80)}), + generateEndpointSlice("svc1", "ns1", 1, 10, 6, 999, []string{}, []*int32{utilpointer.Int32Ptr(80)}), }, expectedMap: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "svc1", "port-0", v1.ProtocolTCP): { - &BaseEndpointInfo{Endpoint: "10.0.1.10:80"}, - &BaseEndpointInfo{Endpoint: "10.0.1.1:80"}, - &BaseEndpointInfo{Endpoint: "10.0.1.2:80"}, - &BaseEndpointInfo{Endpoint: "10.0.1.3:80"}, - &BaseEndpointInfo{Endpoint: "10.0.1.4:80"}, - &BaseEndpointInfo{Endpoint: "10.0.1.5:80"}, - &BaseEndpointInfo{Endpoint: "10.0.1.7:80"}, - &BaseEndpointInfo{Endpoint: "10.0.1.8:80"}, - &BaseEndpointInfo{Endpoint: "10.0.1.9:80"}, + &BaseEndpointInfo{Endpoint: "10.0.1.10:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.1:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.3:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.4:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.5:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.6:80", IsLocal: false, Ready: false, Serving: false, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.7:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.8:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.9:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + }, + }, + }, + // 2 slices with all endpoints overlapping, some unready and terminating. + "2 slices, overlapping endpoints, some endpoints unready and some endpoints terminating": { + namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"}, + endpointSlices: []*discovery.EndpointSlice{ + generateEndpointSlice("svc1", "ns1", 1, 10, 3, 5, []string{}, []*int32{utilpointer.Int32Ptr(80)}), + generateEndpointSlice("svc1", "ns1", 1, 10, 6, 5, []string{}, []*int32{utilpointer.Int32Ptr(80)}), + }, + expectedMap: map[ServicePortName][]*BaseEndpointInfo{ + makeServicePortName("ns1", "svc1", "port-0", v1.ProtocolTCP): { + &BaseEndpointInfo{Endpoint: "10.0.1.10:80", IsLocal: false, Ready: false, Serving: true, Terminating: true}, + &BaseEndpointInfo{Endpoint: "10.0.1.1:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.3:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.4:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.5:80", IsLocal: false, Ready: false, Serving: true, Terminating: true}, + &BaseEndpointInfo{Endpoint: "10.0.1.6:80", IsLocal: false, Ready: false, Serving: false, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.7:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.8:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.9:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, }, "2 slices, overlapping endpoints, all unready": { namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"}, endpointSlices: []*discovery.EndpointSlice{ - generateEndpointSlice("svc1", "ns1", 1, 10, 1, []string{}, []*int32{utilpointer.Int32Ptr(80)}), - generateEndpointSlice("svc1", "ns1", 1, 10, 1, []string{}, []*int32{utilpointer.Int32Ptr(80)}), + generateEndpointSlice("svc1", "ns1", 1, 10, 1, 999, []string{}, []*int32{utilpointer.Int32Ptr(80)}), + generateEndpointSlice("svc1", "ns1", 1, 10, 1, 999, []string{}, []*int32{utilpointer.Int32Ptr(80)}), + }, + expectedMap: map[ServicePortName][]*BaseEndpointInfo{ + makeServicePortName("ns1", "svc1", "port-0", v1.ProtocolTCP): { + &BaseEndpointInfo{Endpoint: "10.0.1.10:80", IsLocal: false, Ready: false, Serving: false, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.1:80", IsLocal: false, Ready: false, Serving: false, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: false, Ready: false, Serving: false, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.3:80", IsLocal: false, Ready: false, Serving: false, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.4:80", IsLocal: false, Ready: false, Serving: false, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.5:80", IsLocal: false, Ready: false, Serving: false, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.6:80", IsLocal: false, Ready: false, Serving: false, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.7:80", IsLocal: false, Ready: false, Serving: false, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.8:80", IsLocal: false, Ready: false, Serving: false, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.9:80", IsLocal: false, Ready: false, Serving: false, Terminating: false}, + }, }, - expectedMap: map[ServicePortName][]*BaseEndpointInfo{}, }, "3 slices with different services and namespaces": { namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"}, endpointSlices: []*discovery.EndpointSlice{ - generateEndpointSlice("svc1", "ns1", 1, 3, 999, []string{}, []*int32{utilpointer.Int32Ptr(80)}), - generateEndpointSlice("svc2", "ns1", 2, 3, 999, []string{}, []*int32{utilpointer.Int32Ptr(80)}), - generateEndpointSlice("svc1", "ns2", 3, 3, 999, []string{}, []*int32{utilpointer.Int32Ptr(80)}), + generateEndpointSlice("svc1", "ns1", 1, 3, 999, 999, []string{}, []*int32{utilpointer.Int32Ptr(80)}), + generateEndpointSlice("svc2", "ns1", 2, 3, 999, 999, []string{}, []*int32{utilpointer.Int32Ptr(80)}), + generateEndpointSlice("svc1", "ns2", 3, 3, 999, 999, []string{}, []*int32{utilpointer.Int32Ptr(80)}), }, expectedMap: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "svc1", "port-0", v1.ProtocolTCP): { - &BaseEndpointInfo{Endpoint: "10.0.1.1:80"}, - &BaseEndpointInfo{Endpoint: "10.0.1.2:80"}, - &BaseEndpointInfo{Endpoint: "10.0.1.3:80"}, + &BaseEndpointInfo{Endpoint: "10.0.1.1:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + &BaseEndpointInfo{Endpoint: "10.0.1.3:80", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, }, @@ -143,7 +179,7 @@ func TestEndpointsMapFromESC(t *testing.T) { namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"}, hostname: "host1", endpointSlices: []*discovery.EndpointSlice{ - generateEndpointSlice("svc1", "ns1", 1, 3, 999, []string{"host1", "host2"}, []*int32{nil}), + generateEndpointSlice("svc1", "ns1", 1, 3, 999, 999, []string{"host1", "host2"}, []*int32{nil}), }, expectedMap: map[ServicePortName][]*BaseEndpointInfo{}, }, @@ -175,13 +211,34 @@ func TestEndpointInfoByServicePort(t *testing.T) { namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"}, hostname: "host1", endpointSlices: []*discovery.EndpointSlice{ - generateEndpointSlice("svc1", "ns1", 1, 3, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80)}), + generateEndpointSlice("svc1", "ns1", 1, 3, 999, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80)}), }, expectedMap: spToEndpointMap{ makeServicePortName("ns1", "svc1", "port-0", v1.ProtocolTCP): { - "10.0.1.1": &BaseEndpointInfo{Endpoint: "10.0.1.1:80", IsLocal: false, Topology: map[string]string{"kubernetes.io/hostname": "host2"}}, - "10.0.1.2": &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: true, Topology: map[string]string{"kubernetes.io/hostname": "host1"}}, - "10.0.1.3": &BaseEndpointInfo{Endpoint: "10.0.1.3:80", IsLocal: false, Topology: map[string]string{"kubernetes.io/hostname": "host2"}}, + "10.0.1.1": &BaseEndpointInfo{ + Endpoint: "10.0.1.1:80", + IsLocal: false, + Topology: map[string]string{"kubernetes.io/hostname": "host2"}, + Ready: true, + Serving: true, + Terminating: false, + }, + "10.0.1.2": &BaseEndpointInfo{ + Endpoint: "10.0.1.2:80", + IsLocal: true, + Topology: map[string]string{"kubernetes.io/hostname": "host1"}, + Ready: true, + Serving: true, + Terminating: false, + }, + "10.0.1.3": &BaseEndpointInfo{ + Endpoint: "10.0.1.3:80", + IsLocal: false, + Topology: map[string]string{"kubernetes.io/hostname": "host2"}, + Ready: true, + Serving: true, + Terminating: false, + }, }, }, }, @@ -342,7 +399,7 @@ func TestEsInfoChanged(t *testing.T) { } } -func generateEndpointSliceWithOffset(serviceName, namespace string, sliceNum, offset, numEndpoints, unreadyMod int, hosts []string, portNums []*int32) *discovery.EndpointSlice { +func generateEndpointSliceWithOffset(serviceName, namespace string, sliceNum, offset, numEndpoints, unreadyMod int, terminatingMod int, hosts []string, portNums []*int32) *discovery.EndpointSlice { tcpProtocol := v1.ProtocolTCP endpointSlice := &discovery.EndpointSlice{ @@ -365,9 +422,20 @@ func generateEndpointSliceWithOffset(serviceName, namespace string, sliceNum, of } for i := 1; i <= numEndpoints; i++ { + readyCondition := i%unreadyMod != 0 + terminatingCondition := i%terminatingMod == 0 + + ready := utilpointer.BoolPtr(readyCondition && !terminatingCondition) + serving := utilpointer.BoolPtr(readyCondition) + terminating := utilpointer.BoolPtr(terminatingCondition) + endpoint := discovery.Endpoint{ - Addresses: []string{fmt.Sprintf("10.0.%d.%d", offset, i)}, - Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(i%unreadyMod != 0)}, + Addresses: []string{fmt.Sprintf("10.0.%d.%d", offset, i)}, + Conditions: discovery.EndpointConditions{ + Ready: ready, + Serving: serving, + Terminating: terminating, + }, } if len(hosts) > 0 { @@ -382,8 +450,8 @@ func generateEndpointSliceWithOffset(serviceName, namespace string, sliceNum, of return endpointSlice } -func generateEndpointSlice(serviceName, namespace string, sliceNum, numEndpoints, unreadyMod int, hosts []string, portNums []*int32) *discovery.EndpointSlice { - return generateEndpointSliceWithOffset(serviceName, namespace, sliceNum, sliceNum, numEndpoints, unreadyMod, hosts, portNums) +func generateEndpointSlice(serviceName, namespace string, sliceNum, numEndpoints, unreadyMod int, terminatingMod int, hosts []string, portNums []*int32) *discovery.EndpointSlice { + return generateEndpointSliceWithOffset(serviceName, namespace, sliceNum, sliceNum, numEndpoints, unreadyMod, terminatingMod, hosts, portNums) } // cacheMutationCheck helps ensure that cached objects have not been changed diff --git a/pkg/proxy/iptables/proxier.go b/pkg/proxy/iptables/proxier.go index a3ba549e89e..78b837c5756 100644 --- a/pkg/proxy/iptables/proxier.go +++ b/pkg/proxy/iptables/proxier.go @@ -1020,8 +1020,6 @@ func (proxier *Proxier) syncProxyRules() { allEndpoints := proxier.endpointsMap[svcName] - hasEndpoints := len(allEndpoints) > 0 - // Service Topology will not be enabled in the following cases: // 1. externalTrafficPolicy=Local (mutually exclusive with service topology). // 2. ServiceTopology is not enabled. @@ -1029,9 +1027,18 @@ func (proxier *Proxier) syncProxyRules() { // to get topology information). if !svcInfo.OnlyNodeLocalEndpoints() && utilfeature.DefaultFeatureGate.Enabled(features.ServiceTopology) && utilfeature.DefaultFeatureGate.Enabled(features.EndpointSliceProxying) { allEndpoints = proxy.FilterTopologyEndpoint(proxier.nodeLabels, svcInfo.TopologyKeys(), allEndpoints) - hasEndpoints = len(allEndpoints) > 0 } + readyEndpoints := make([]proxy.Endpoint, 0, len(allEndpoints)) + for _, endpoint := range allEndpoints { + if !endpoint.IsReady() { + continue + } + + readyEndpoints = append(readyEndpoints, endpoint) + } + hasEndpoints := len(readyEndpoints) > 0 + svcChain := svcInfo.servicePortChainName if hasEndpoints { // Create the per-service chain, retaining counters if possible. @@ -1340,7 +1347,7 @@ func (proxier *Proxier) syncProxyRules() { endpoints = endpoints[:0] endpointChains = endpointChains[:0] var endpointChain utiliptables.Chain - for _, ep := range allEndpoints { + for _, ep := range readyEndpoints { epInfo, ok := ep.(*endpointsInfo) if !ok { klog.ErrorS(err, "Failed to cast endpointsInfo", "endpointsInfo", ep.String()) diff --git a/pkg/proxy/iptables/proxier_test.go b/pkg/proxy/iptables/proxier_test.go index aaebb517236..e3dd8d5c4bd 100644 --- a/pkg/proxy/iptables/proxier_test.go +++ b/pkg/proxy/iptables/proxier_test.go @@ -2044,12 +2044,12 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -2065,12 +2065,12 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -2088,18 +2088,18 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -2115,24 +2115,24 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns1", "ep1", "p13", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.3:13", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.3:13", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns1", "ep1", "p13", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.3:13", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.3:13", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -2152,54 +2152,54 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:11", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: false}}, - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns1", "ep1", "p13", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.3:13", IsLocal: false}}, - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.4:13", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.3:13", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.4:13", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns1", "ep1", "p14", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.3:14", IsLocal: false}}, - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.4:14", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.3:14", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.4:14", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns2", "ep2", "p21", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.1:21", IsLocal: false}}, - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.2:21", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.1:21", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.2:21", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns2", "ep2", "p22", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.1:22", IsLocal: false}}, - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.2:22", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.1:22", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.2:22", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:11", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: false}}, - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns1", "ep1", "p13", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.3:13", IsLocal: false}}, - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.4:13", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.3:13", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.4:13", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns1", "ep1", "p14", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.3:14", IsLocal: false}}, - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.4:14", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.3:14", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.4:14", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns2", "ep2", "p21", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.1:21", IsLocal: false}}, - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.2:21", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.1:21", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.2:21", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns2", "ep2", "p22", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.1:22", IsLocal: false}}, - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.2:22", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.1:22", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.2:22", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -2219,7 +2219,7 @@ func Test_updateEndpointsMap(t *testing.T) { oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{}, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -2239,7 +2239,7 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{}, @@ -2259,17 +2259,17 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:11", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: false}}, - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -2289,17 +2289,17 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:11", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: false}}, - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -2324,15 +2324,15 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -2352,15 +2352,15 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -2379,12 +2379,12 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11-2", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -2405,12 +2405,12 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:22", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:22", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -2435,39 +2435,39 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns2", "ep2", "p22", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.2:22", IsLocal: true}}, - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.22:22", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.2:22", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.22:22", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns2", "ep2", "p23", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.3:23", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.3:23", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns4", "ep4", "p44", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "4.4.4.4:44", IsLocal: true}}, - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "4.4.4.5:44", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "4.4.4.4:44", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "4.4.4.5:44", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns4", "ep4", "p45", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "4.4.4.6:45", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "4.4.4.6:45", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.11:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.11:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns1", "ep1", "p122", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:122", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:122", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns3", "ep3", "p33", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "3.3.3.3:33", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "3.3.3.3:33", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, makeServicePortName("ns4", "ep4", "p44", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "4.4.4.4:44", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "4.4.4.4:44", IsLocal: true, Ready: true, Serving: true, Terminating: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -2505,7 +2505,7 @@ func Test_updateEndpointsMap(t *testing.T) { oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{}, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "", v1.ProtocolUDP): { - {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -2670,6 +2670,10 @@ COMMIT Addresses: []string{"10.0.1.3"}, Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)}, Topology: map[string]string{"kubernetes.io/hostname": "node3"}, + }, { // not ready endpoints should be ignored + Addresses: []string{"10.0.1.4"}, + Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(false)}, + Topology: map[string]string{"kubernetes.io/hostname": "node4"}, }}, } diff --git a/pkg/proxy/ipvs/proxier.go b/pkg/proxy/ipvs/proxier.go index d01a3f347d0..2705b1657b9 100644 --- a/pkg/proxy/ipvs/proxier.go +++ b/pkg/proxy/ipvs/proxier.go @@ -2036,9 +2036,14 @@ func (proxier *Proxier) syncEndpoint(svcPortName proxy.ServicePortName, onlyNode } for _, epInfo := range endpoints { + if !epInfo.IsReady() { + continue + } + if onlyNodeLocalEndpoints && !epInfo.GetIsLocal() { continue } + newEndpoints.Insert(epInfo.String()) } diff --git a/pkg/proxy/ipvs/proxier_test.go b/pkg/proxy/ipvs/proxier_test.go index 8b7c602a1e3..11cd73fd810 100644 --- a/pkg/proxy/ipvs/proxier_test.go +++ b/pkg/proxy/ipvs/proxier_test.go @@ -2881,12 +2881,12 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -2902,12 +2902,12 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -2925,18 +2925,18 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {Endpoint: "1.1.1.2:12", IsLocal: false}, + {Endpoint: "1.1.1.2:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {Endpoint: "1.1.1.2:12", IsLocal: false}, + {Endpoint: "1.1.1.2:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -2952,24 +2952,24 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:12", IsLocal: true}, + {Endpoint: "1.1.1.1:12", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p13", v1.ProtocolUDP): { - {Endpoint: "1.1.1.3:13", IsLocal: false}, + {Endpoint: "1.1.1.3:13", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:12", IsLocal: true}, + {Endpoint: "1.1.1.1:12", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p13", v1.ProtocolUDP): { - {Endpoint: "1.1.1.3:13", IsLocal: false}, + {Endpoint: "1.1.1.3:13", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -2989,54 +2989,54 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, - {Endpoint: "1.1.1.2:11", IsLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.2:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:12", IsLocal: false}, - {Endpoint: "1.1.1.2:12", IsLocal: true}, + {Endpoint: "1.1.1.1:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.2:12", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p13", v1.ProtocolUDP): { - {Endpoint: "1.1.1.3:13", IsLocal: false}, - {Endpoint: "1.1.1.4:13", IsLocal: true}, + {Endpoint: "1.1.1.3:13", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.4:13", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p14", v1.ProtocolUDP): { - {Endpoint: "1.1.1.3:14", IsLocal: false}, - {Endpoint: "1.1.1.4:14", IsLocal: true}, + {Endpoint: "1.1.1.3:14", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.4:14", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns2", "ep2", "p21", v1.ProtocolUDP): { - {Endpoint: "2.2.2.1:21", IsLocal: false}, - {Endpoint: "2.2.2.2:21", IsLocal: true}, + {Endpoint: "2.2.2.1:21", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "2.2.2.2:21", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns2", "ep2", "p22", v1.ProtocolUDP): { - {Endpoint: "2.2.2.1:22", IsLocal: false}, - {Endpoint: "2.2.2.2:22", IsLocal: true}, + {Endpoint: "2.2.2.1:22", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "2.2.2.2:22", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, - {Endpoint: "1.1.1.2:11", IsLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.2:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:12", IsLocal: false}, - {Endpoint: "1.1.1.2:12", IsLocal: true}, + {Endpoint: "1.1.1.1:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.2:12", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p13", v1.ProtocolUDP): { - {Endpoint: "1.1.1.3:13", IsLocal: false}, - {Endpoint: "1.1.1.4:13", IsLocal: true}, + {Endpoint: "1.1.1.3:13", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.4:13", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p14", v1.ProtocolUDP): { - {Endpoint: "1.1.1.3:14", IsLocal: false}, - {Endpoint: "1.1.1.4:14", IsLocal: true}, + {Endpoint: "1.1.1.3:14", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.4:14", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns2", "ep2", "p21", v1.ProtocolUDP): { - {Endpoint: "2.2.2.1:21", IsLocal: false}, - {Endpoint: "2.2.2.2:21", IsLocal: true}, + {Endpoint: "2.2.2.1:21", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "2.2.2.2:21", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns2", "ep2", "p22", v1.ProtocolUDP): { - {Endpoint: "2.2.2.1:22", IsLocal: false}, - {Endpoint: "2.2.2.2:22", IsLocal: true}, + {Endpoint: "2.2.2.1:22", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "2.2.2.2:22", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -3056,7 +3056,7 @@ func Test_updateEndpointsMap(t *testing.T) { oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{}, expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -3076,7 +3076,7 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{}, @@ -3096,17 +3096,17 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, - {Endpoint: "1.1.1.2:11", IsLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.2:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:12", IsLocal: false}, - {Endpoint: "1.1.1.2:12", IsLocal: true}, + {Endpoint: "1.1.1.1:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.2:12", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -3126,17 +3126,17 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, - {Endpoint: "1.1.1.2:11", IsLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.2:11", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:12", IsLocal: false}, - {Endpoint: "1.1.1.2:12", IsLocal: true}, + {Endpoint: "1.1.1.1:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.2:12", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -3161,15 +3161,15 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {Endpoint: "1.1.1.2:12", IsLocal: true}, + {Endpoint: "1.1.1.2:12", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -3189,15 +3189,15 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {Endpoint: "1.1.1.2:12", IsLocal: false}, + {Endpoint: "1.1.1.2:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -3216,12 +3216,12 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11-2", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -3242,12 +3242,12 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:22", IsLocal: false}, + {Endpoint: "1.1.1.1:22", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -3272,39 +3272,39 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns2", "ep2", "p22", v1.ProtocolUDP): { - {Endpoint: "2.2.2.2:22", IsLocal: true}, - {Endpoint: "2.2.2.22:22", IsLocal: true}, + {Endpoint: "2.2.2.2:22", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "2.2.2.22:22", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns2", "ep2", "p23", v1.ProtocolUDP): { - {Endpoint: "2.2.2.3:23", IsLocal: true}, + {Endpoint: "2.2.2.3:23", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns4", "ep4", "p44", v1.ProtocolUDP): { - {Endpoint: "4.4.4.4:44", IsLocal: true}, - {Endpoint: "4.4.4.5:44", IsLocal: true}, + {Endpoint: "4.4.4.4:44", IsLocal: true, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "4.4.4.5:44", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns4", "ep4", "p45", v1.ProtocolUDP): { - {Endpoint: "4.4.4.6:45", IsLocal: true}, + {Endpoint: "4.4.4.6:45", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, - {Endpoint: "1.1.1.11:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, + {Endpoint: "1.1.1.11:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): { - {Endpoint: "1.1.1.2:12", IsLocal: false}, + {Endpoint: "1.1.1.2:12", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns1", "ep1", "p122", v1.ProtocolUDP): { - {Endpoint: "1.1.1.2:122", IsLocal: false}, + {Endpoint: "1.1.1.2:122", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns3", "ep3", "p33", v1.ProtocolUDP): { - {Endpoint: "3.3.3.3:33", IsLocal: false}, + {Endpoint: "3.3.3.3:33", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, makeServicePortName("ns4", "ep4", "p44", v1.ProtocolUDP): { - {Endpoint: "4.4.4.4:44", IsLocal: true}, + {Endpoint: "4.4.4.4:44", IsLocal: true, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -3342,7 +3342,7 @@ func Test_updateEndpointsMap(t *testing.T) { oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{}, expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "", v1.ProtocolUDP): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false, Ready: true, Serving: true, Terminating: false}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -4256,6 +4256,10 @@ func TestEndpointSliceE2E(t *testing.T) { Addresses: []string{"10.0.1.3"}, Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)}, Topology: map[string]string{"kubernetes.io/hostname": "node3"}, + }, { // not ready endpoints should be ignored + Addresses: []string{"10.0.1.4"}, + Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(false)}, + Topology: map[string]string{"kubernetes.io/hostname": "node3"}, }}, } diff --git a/pkg/proxy/types.go b/pkg/proxy/types.go index 2d0f9e42856..96ccb403295 100644 --- a/pkg/proxy/types.go +++ b/pkg/proxy/types.go @@ -97,6 +97,20 @@ type Endpoint interface { String() string // GetIsLocal returns true if the endpoint is running in same host as kube-proxy, otherwise returns false. GetIsLocal() bool + // IsReady returns true if an endpoint is ready and not terminating. + // This is only set when watching EndpointSlices. If using Endpoints, this is always + // true since only ready endpoints are read from Endpoints. + IsReady() bool + // IsServing returns true if an endpoint is ready. It does not account + // for terminating state. + // This is only set when watching EndpointSlices. If using Endpoints, this is always + // true since only ready endpoints are read from Endpoints. + IsServing() bool + // IsTerminating retruns true if an endpoint is terminating. For pods, + // that is any pod with a deletion timestamp. + // This is only set when watching EndpointSlices. If using Endpoints, this is always + // false since terminating endpoints are always excluded from Endpoints. + IsTerminating() bool // GetTopology returns the topology information of the endpoint. GetTopology() map[string]string // IP returns IP part of the endpoint. diff --git a/pkg/proxy/winkernel/hnsV1.go b/pkg/proxy/winkernel/hnsV1.go index ae31ffea97e..88da6a48d34 100644 --- a/pkg/proxy/winkernel/hnsV1.go +++ b/pkg/proxy/winkernel/hnsV1.go @@ -65,6 +65,11 @@ func (hns hnsV1) getEndpointByID(id string) (*endpointsInfo, error) { macAddress: hnsendpoint.MacAddress, hnsID: hnsendpoint.Id, hns: hns, + + // only ready and not terminating endpoints were added to HNS + ready: true, + serving: true, + terminating: false, }, nil } func (hns hnsV1) getEndpointByIpAddress(ip string, networkName string) (*endpointsInfo, error) { @@ -90,6 +95,11 @@ func (hns hnsV1) getEndpointByIpAddress(ip string, networkName string) (*endpoin macAddress: endpoint.MacAddress, hnsID: endpoint.Id, hns: hns, + + // only ready and not terminating endpoints were added to HNS + ready: true, + serving: true, + terminating: false, }, nil } } @@ -137,6 +147,10 @@ func (hns hnsV1) createEndpoint(ep *endpointsInfo, networkName string) (*endpoin hnsID: createdEndpoint.Id, providerAddress: ep.providerAddress, //TODO get from createdEndpoint hns: hns, + + ready: ep.ready, + serving: ep.serving, + terminating: ep.terminating, }, nil } func (hns hnsV1) deleteEndpoint(hnsID string) error { diff --git a/pkg/proxy/winkernel/proxier.go b/pkg/proxy/winkernel/proxier.go index dcd6489d2ed..a84271234ac 100644 --- a/pkg/proxy/winkernel/proxier.go +++ b/pkg/proxy/winkernel/proxier.go @@ -162,6 +162,11 @@ type endpointsInfo struct { refCount *uint16 providerAddress string hns HostNetworkService + + // conditions + ready bool + serving bool + terminating bool } // String is part of proxy.Endpoint interface. @@ -174,6 +179,21 @@ func (info *endpointsInfo) GetIsLocal() bool { return info.isLocal } +// IsReady returns true if an endpoint is ready and not terminating. +func (info *endpointsInfo) IsReady() bool { + return info.ready +} + +// IsServing returns true if an endpoint is ready, regardless of it's terminating state. +func (info *endpointsInfo) IsServing() bool { + return info.serving +} + +// IsTerminating returns true if an endpoint is terminating. +func (info *endpointsInfo) IsTerminating() bool { + return info.terminating +} + // GetTopology returns the topology information of the endpoint. func (info *endpointsInfo) GetTopology() map[string]string { return nil @@ -300,6 +320,10 @@ func (proxier *Proxier) newEndpointInfo(baseInfo *proxy.BaseEndpointInfo) proxy. refCount: new(uint16), hnsID: "", hns: proxier.hns, + + ready: baseInfo.Ready, + serving: baseInfo.Serving, + terminating: baseInfo.Terminating, } return info @@ -311,6 +335,10 @@ func newSourceVIP(hns HostNetworkService, network string, ip string, mac string, isLocal: true, macAddress: mac, providerAddress: providerAddress, + + ready: true, + serving: true, + terminating: false, } ep, err := hns.createEndpoint(hnsEndpoint, network) return ep, err @@ -1010,13 +1038,16 @@ func (proxier *Proxier) syncProxyRules() { containsNodeIP := false for _, epInfo := range proxier.endpointsMap[svcName] { - ep, ok := epInfo.(*endpointsInfo) if !ok { klog.Errorf("Failed to cast endpointsInfo %q", svcName.String()) continue } + if !ep.IsReady() { + continue + } + var newHnsEndpoint *endpointsInfo hnsNetworkName := proxier.network.name var err error