123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659 |
- /*
- Copyright 2017 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package proxy
- import (
- "net"
- "testing"
- "github.com/davecgh/go-spew/spew"
- "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/types"
- "k8s.io/apimachinery/pkg/util/intstr"
- "k8s.io/apimachinery/pkg/util/sets"
- )
- const testHostname = "test-hostname"
- func makeTestServiceInfo(clusterIP string, port int, protocol string, healthcheckNodePort int, svcInfoFuncs ...func(*BaseServiceInfo)) *BaseServiceInfo {
- info := &BaseServiceInfo{
- ClusterIP: net.ParseIP(clusterIP),
- Port: port,
- Protocol: v1.Protocol(protocol),
- }
- if healthcheckNodePort != 0 {
- info.HealthCheckNodePort = healthcheckNodePort
- }
- for _, svcInfoFunc := range svcInfoFuncs {
- svcInfoFunc(info)
- }
- return info
- }
- func makeTestService(namespace, name string, svcFunc func(*v1.Service)) *v1.Service {
- svc := &v1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: name,
- Namespace: namespace,
- Annotations: map[string]string{},
- },
- Spec: v1.ServiceSpec{},
- Status: v1.ServiceStatus{},
- }
- svcFunc(svc)
- return svc
- }
- func addTestPort(array []v1.ServicePort, name string, protocol v1.Protocol, port, nodeport int32, targetPort int) []v1.ServicePort {
- svcPort := v1.ServicePort{
- Name: name,
- Protocol: protocol,
- Port: port,
- NodePort: nodeport,
- TargetPort: intstr.FromInt(targetPort),
- }
- return append(array, svcPort)
- }
- func makeNSN(namespace, name string) types.NamespacedName {
- return types.NamespacedName{Namespace: namespace, Name: name}
- }
- func makeServicePortName(ns, name, port string) ServicePortName {
- return ServicePortName{
- NamespacedName: makeNSN(ns, name),
- Port: port,
- }
- }
- func TestServiceToServiceMap(t *testing.T) {
- svcTracker := NewServiceChangeTracker(nil, nil, nil)
- trueVal := true
- falseVal := false
- testClusterIPv4 := "10.0.0.1"
- testExternalIPv4 := "8.8.8.8"
- testSourceRangeIPv4 := "0.0.0.0/1"
- testClusterIPv6 := "2001:db8:85a3:0:0:8a2e:370:7334"
- testExternalIPv6 := "2001:db8:85a3:0:0:8a2e:370:7335"
- testSourceRangeIPv6 := "2001:db8::/32"
- testCases := []struct {
- desc string
- service *v1.Service
- expected map[ServicePortName]*BaseServiceInfo
- isIPv6Mode *bool
- }{
- {
- desc: "nothing",
- service: nil,
- expected: map[ServicePortName]*BaseServiceInfo{},
- },
- {
- desc: "headless service",
- service: makeTestService("ns2", "headless", func(svc *v1.Service) {
- svc.Spec.Type = v1.ServiceTypeClusterIP
- svc.Spec.ClusterIP = v1.ClusterIPNone
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "rpc", "UDP", 1234, 0, 0)
- }),
- expected: map[ServicePortName]*BaseServiceInfo{},
- },
- {
- desc: "headless sctp service",
- service: makeTestService("ns2", "headless", func(svc *v1.Service) {
- svc.Spec.Type = v1.ServiceTypeClusterIP
- svc.Spec.ClusterIP = v1.ClusterIPNone
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "sip", "SCTP", 7777, 0, 0)
- }),
- expected: map[ServicePortName]*BaseServiceInfo{},
- },
- {
- desc: "headless service without port",
- service: makeTestService("ns2", "headless-without-port", func(svc *v1.Service) {
- svc.Spec.Type = v1.ServiceTypeClusterIP
- svc.Spec.ClusterIP = v1.ClusterIPNone
- }),
- expected: map[ServicePortName]*BaseServiceInfo{},
- },
- {
- desc: "cluster ip service",
- service: makeTestService("ns2", "cluster-ip", func(svc *v1.Service) {
- svc.Spec.Type = v1.ServiceTypeClusterIP
- svc.Spec.ClusterIP = "172.16.55.4"
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p1", "UDP", 1234, 4321, 0)
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p2", "UDP", 1235, 5321, 0)
- }),
- expected: map[ServicePortName]*BaseServiceInfo{
- makeServicePortName("ns2", "cluster-ip", "p1"): makeTestServiceInfo("172.16.55.4", 1234, "UDP", 0),
- makeServicePortName("ns2", "cluster-ip", "p2"): makeTestServiceInfo("172.16.55.4", 1235, "UDP", 0),
- },
- },
- {
- desc: "nodeport service",
- service: makeTestService("ns2", "node-port", func(svc *v1.Service) {
- svc.Spec.Type = v1.ServiceTypeNodePort
- svc.Spec.ClusterIP = "172.16.55.10"
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port1", "UDP", 345, 678, 0)
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port2", "TCP", 344, 677, 0)
- }),
- expected: map[ServicePortName]*BaseServiceInfo{
- makeServicePortName("ns2", "node-port", "port1"): makeTestServiceInfo("172.16.55.10", 345, "UDP", 0),
- makeServicePortName("ns2", "node-port", "port2"): makeTestServiceInfo("172.16.55.10", 344, "TCP", 0),
- },
- },
- {
- desc: "load balancer service",
- service: makeTestService("ns1", "load-balancer", func(svc *v1.Service) {
- svc.Spec.Type = v1.ServiceTypeLoadBalancer
- svc.Spec.ClusterIP = "172.16.55.11"
- svc.Spec.LoadBalancerIP = "5.6.7.8"
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port3", "UDP", 8675, 30061, 7000)
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port4", "UDP", 8676, 30062, 7001)
- svc.Status.LoadBalancer = v1.LoadBalancerStatus{
- Ingress: []v1.LoadBalancerIngress{
- {IP: "10.1.2.4"},
- },
- }
- }),
- expected: map[ServicePortName]*BaseServiceInfo{
- makeServicePortName("ns1", "load-balancer", "port3"): makeTestServiceInfo("172.16.55.11", 8675, "UDP", 0),
- makeServicePortName("ns1", "load-balancer", "port4"): makeTestServiceInfo("172.16.55.11", 8676, "UDP", 0),
- },
- },
- {
- desc: "load balancer service with only local traffic policy",
- service: makeTestService("ns1", "only-local-load-balancer", func(svc *v1.Service) {
- svc.Spec.Type = v1.ServiceTypeLoadBalancer
- svc.Spec.ClusterIP = "172.16.55.12"
- svc.Spec.LoadBalancerIP = "5.6.7.8"
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "portx", "UDP", 8677, 30063, 7002)
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "porty", "UDP", 8678, 30064, 7003)
- svc.Status.LoadBalancer = v1.LoadBalancerStatus{
- Ingress: []v1.LoadBalancerIngress{
- {IP: "10.1.2.3"},
- },
- }
- svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyTypeLocal
- svc.Spec.HealthCheckNodePort = 345
- }),
- expected: map[ServicePortName]*BaseServiceInfo{
- makeServicePortName("ns1", "only-local-load-balancer", "portx"): makeTestServiceInfo("172.16.55.12", 8677, "UDP", 345),
- makeServicePortName("ns1", "only-local-load-balancer", "porty"): makeTestServiceInfo("172.16.55.12", 8678, "UDP", 345),
- },
- },
- {
- desc: "external name service",
- service: makeTestService("ns2", "external-name", func(svc *v1.Service) {
- svc.Spec.Type = v1.ServiceTypeExternalName
- svc.Spec.ClusterIP = "172.16.55.4" // Should be ignored
- svc.Spec.ExternalName = "foo2.bar.com"
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "portz", "UDP", 1235, 5321, 0)
- }),
- expected: map[ServicePortName]*BaseServiceInfo{},
- },
- {
- desc: "service with ipv6 clusterIP under ipv4 mode, service should be filtered",
- service: &v1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "invalidIPv6InIPV4Mode",
- Namespace: "test",
- },
- Spec: v1.ServiceSpec{
- ClusterIP: testClusterIPv6,
- Ports: []v1.ServicePort{
- {
- Name: "testPort",
- Port: int32(12345),
- Protocol: v1.ProtocolTCP,
- },
- },
- },
- },
- isIPv6Mode: &falseVal,
- },
- {
- desc: "service with ipv4 clusterIP under ipv6 mode, service should be filtered",
- service: &v1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "invalidIPv4InIPV6Mode",
- Namespace: "test",
- },
- Spec: v1.ServiceSpec{
- ClusterIP: testClusterIPv4,
- Ports: []v1.ServicePort{
- {
- Name: "testPort",
- Port: int32(12345),
- Protocol: v1.ProtocolTCP,
- },
- },
- },
- },
- isIPv6Mode: &trueVal,
- },
- {
- desc: "service with ipv4 configurations under ipv4 mode",
- service: &v1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "validIPv4",
- Namespace: "test",
- },
- Spec: v1.ServiceSpec{
- ClusterIP: testClusterIPv4,
- ExternalIPs: []string{testExternalIPv4},
- LoadBalancerSourceRanges: []string{testSourceRangeIPv4},
- Ports: []v1.ServicePort{
- {
- Name: "testPort",
- Port: int32(12345),
- Protocol: v1.ProtocolTCP,
- },
- },
- },
- },
- expected: map[ServicePortName]*BaseServiceInfo{
- makeServicePortName("test", "validIPv4", "testPort"): makeTestServiceInfo(testClusterIPv4, 12345, "TCP", 0, func(info *BaseServiceInfo) {
- info.ExternalIPs = []string{testExternalIPv4}
- info.LoadBalancerSourceRanges = []string{testSourceRangeIPv4}
- }),
- },
- isIPv6Mode: &falseVal,
- },
- {
- desc: "service with ipv6 configurations under ipv6 mode",
- service: &v1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "validIPv6",
- Namespace: "test",
- },
- Spec: v1.ServiceSpec{
- ClusterIP: testClusterIPv6,
- ExternalIPs: []string{testExternalIPv6},
- LoadBalancerSourceRanges: []string{testSourceRangeIPv6},
- Ports: []v1.ServicePort{
- {
- Name: "testPort",
- Port: int32(12345),
- Protocol: v1.ProtocolTCP,
- },
- },
- },
- },
- expected: map[ServicePortName]*BaseServiceInfo{
- makeServicePortName("test", "validIPv6", "testPort"): makeTestServiceInfo(testClusterIPv6, 12345, "TCP", 0, func(info *BaseServiceInfo) {
- info.ExternalIPs = []string{testExternalIPv6}
- info.LoadBalancerSourceRanges = []string{testSourceRangeIPv6}
- }),
- },
- isIPv6Mode: &trueVal,
- },
- {
- desc: "service with both ipv4 and ipv6 configurations under ipv4 mode, ipv6 fields should be filtered",
- service: &v1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "filterIPv6InIPV4Mode",
- Namespace: "test",
- },
- Spec: v1.ServiceSpec{
- ClusterIP: testClusterIPv4,
- ExternalIPs: []string{testExternalIPv4, testExternalIPv6},
- LoadBalancerSourceRanges: []string{testSourceRangeIPv4, testSourceRangeIPv6},
- Ports: []v1.ServicePort{
- {
- Name: "testPort",
- Port: int32(12345),
- Protocol: v1.ProtocolTCP,
- },
- },
- },
- },
- expected: map[ServicePortName]*BaseServiceInfo{
- makeServicePortName("test", "filterIPv6InIPV4Mode", "testPort"): makeTestServiceInfo(testClusterIPv4, 12345, "TCP", 0, func(info *BaseServiceInfo) {
- info.ExternalIPs = []string{testExternalIPv4}
- info.LoadBalancerSourceRanges = []string{testSourceRangeIPv4}
- }),
- },
- isIPv6Mode: &falseVal,
- },
- {
- desc: "service with both ipv4 and ipv6 configurations under ipv6 mode, ipv4 fields should be filtered",
- service: &v1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "filterIPv4InIPV6Mode",
- Namespace: "test",
- },
- Spec: v1.ServiceSpec{
- ClusterIP: testClusterIPv6,
- ExternalIPs: []string{testExternalIPv4, testExternalIPv6},
- LoadBalancerSourceRanges: []string{testSourceRangeIPv4, testSourceRangeIPv6},
- Ports: []v1.ServicePort{
- {
- Name: "testPort",
- Port: int32(12345),
- Protocol: v1.ProtocolTCP,
- },
- },
- },
- },
- expected: map[ServicePortName]*BaseServiceInfo{
- makeServicePortName("test", "filterIPv4InIPV6Mode", "testPort"): makeTestServiceInfo(testClusterIPv6, 12345, "TCP", 0, func(info *BaseServiceInfo) {
- info.ExternalIPs = []string{testExternalIPv6}
- info.LoadBalancerSourceRanges = []string{testSourceRangeIPv6}
- }),
- },
- isIPv6Mode: &trueVal,
- },
- }
- for _, tc := range testCases {
- svcTracker.isIPv6Mode = tc.isIPv6Mode
- // outputs
- newServices := svcTracker.serviceToServiceMap(tc.service)
- if len(newServices) != len(tc.expected) {
- t.Errorf("[%s] expected %d new, got %d: %v", tc.desc, len(tc.expected), len(newServices), spew.Sdump(newServices))
- }
- for svcKey, expectedInfo := range tc.expected {
- svcInfo := newServices[svcKey].(*BaseServiceInfo)
- if !svcInfo.ClusterIP.Equal(expectedInfo.ClusterIP) ||
- svcInfo.Port != expectedInfo.Port ||
- svcInfo.Protocol != expectedInfo.Protocol ||
- svcInfo.HealthCheckNodePort != expectedInfo.HealthCheckNodePort ||
- !sets.NewString(svcInfo.ExternalIPs...).Equal(sets.NewString(expectedInfo.ExternalIPs...)) ||
- !sets.NewString(svcInfo.LoadBalancerSourceRanges...).Equal(sets.NewString(expectedInfo.LoadBalancerSourceRanges...)) {
- t.Errorf("[%s] expected new[%v]to be %v, got %v", tc.desc, svcKey, expectedInfo, *svcInfo)
- }
- }
- }
- }
- type FakeProxier struct {
- endpointsChanges *EndpointChangeTracker
- serviceChanges *ServiceChangeTracker
- serviceMap ServiceMap
- endpointsMap EndpointsMap
- hostname string
- }
- func newFakeProxier() *FakeProxier {
- return &FakeProxier{
- serviceMap: make(ServiceMap),
- serviceChanges: NewServiceChangeTracker(nil, nil, nil),
- endpointsMap: make(EndpointsMap),
- endpointsChanges: NewEndpointChangeTracker(testHostname, nil, nil, nil),
- }
- }
- func makeServiceMap(fake *FakeProxier, allServices ...*v1.Service) {
- for i := range allServices {
- fake.addService(allServices[i])
- }
- }
- func (fake *FakeProxier) addService(service *v1.Service) {
- fake.serviceChanges.Update(nil, service)
- }
- func (fake *FakeProxier) updateService(oldService *v1.Service, service *v1.Service) {
- fake.serviceChanges.Update(oldService, service)
- }
- func (fake *FakeProxier) deleteService(service *v1.Service) {
- fake.serviceChanges.Update(service, nil)
- }
- func TestUpdateServiceMapHeadless(t *testing.T) {
- fp := newFakeProxier()
- makeServiceMap(fp,
- makeTestService("ns2", "headless", func(svc *v1.Service) {
- svc.Spec.Type = v1.ServiceTypeClusterIP
- svc.Spec.ClusterIP = v1.ClusterIPNone
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "rpc", "UDP", 1234, 0, 0)
- }),
- makeTestService("ns2", "headless-without-port", func(svc *v1.Service) {
- svc.Spec.Type = v1.ServiceTypeClusterIP
- svc.Spec.ClusterIP = v1.ClusterIPNone
- }),
- )
- // Headless service should be ignored
- result := UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
- if len(fp.serviceMap) != 0 {
- t.Errorf("expected service map length 0, got %d", len(fp.serviceMap))
- }
- // No proxied services, so no healthchecks
- if len(result.HCServiceNodePorts) != 0 {
- t.Errorf("expected healthcheck ports length 0, got %d", len(result.HCServiceNodePorts))
- }
- if len(result.UDPStaleClusterIP) != 0 {
- t.Errorf("expected stale UDP services length 0, got %d", len(result.UDPStaleClusterIP))
- }
- }
- func TestUpdateServiceTypeExternalName(t *testing.T) {
- fp := newFakeProxier()
- makeServiceMap(fp,
- makeTestService("ns2", "external-name", func(svc *v1.Service) {
- svc.Spec.Type = v1.ServiceTypeExternalName
- svc.Spec.ClusterIP = "172.16.55.4" // Should be ignored
- svc.Spec.ExternalName = "foo2.bar.com"
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "blah", "UDP", 1235, 5321, 0)
- }),
- )
- result := UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
- if len(fp.serviceMap) != 0 {
- t.Errorf("expected service map length 0, got %v", fp.serviceMap)
- }
- // No proxied services, so no healthchecks
- if len(result.HCServiceNodePorts) != 0 {
- t.Errorf("expected healthcheck ports length 0, got %v", result.HCServiceNodePorts)
- }
- if len(result.UDPStaleClusterIP) != 0 {
- t.Errorf("expected stale UDP services length 0, got %v", result.UDPStaleClusterIP)
- }
- }
- func TestBuildServiceMapAddRemove(t *testing.T) {
- fp := newFakeProxier()
- services := []*v1.Service{
- makeTestService("ns2", "cluster-ip", func(svc *v1.Service) {
- svc.Spec.Type = v1.ServiceTypeClusterIP
- svc.Spec.ClusterIP = "172.16.55.4"
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port1", "UDP", 1234, 4321, 0)
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port2", "UDP", 1235, 5321, 0)
- }),
- makeTestService("ns2", "node-port", func(svc *v1.Service) {
- svc.Spec.Type = v1.ServiceTypeNodePort
- svc.Spec.ClusterIP = "172.16.55.10"
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port1", "UDP", 345, 678, 0)
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port2", "TCP", 344, 677, 0)
- }),
- makeTestService("ns1", "load-balancer", func(svc *v1.Service) {
- svc.Spec.Type = v1.ServiceTypeLoadBalancer
- svc.Spec.ClusterIP = "172.16.55.11"
- svc.Spec.LoadBalancerIP = "5.6.7.8"
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "foobar", "UDP", 8675, 30061, 7000)
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "baz", "UDP", 8676, 30062, 7001)
- svc.Status.LoadBalancer = v1.LoadBalancerStatus{
- Ingress: []v1.LoadBalancerIngress{
- {IP: "10.1.2.4"},
- },
- }
- }),
- makeTestService("ns1", "only-local-load-balancer", func(svc *v1.Service) {
- svc.Spec.Type = v1.ServiceTypeLoadBalancer
- svc.Spec.ClusterIP = "172.16.55.12"
- svc.Spec.LoadBalancerIP = "5.6.7.8"
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "foobar2", "UDP", 8677, 30063, 7002)
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "baz", "UDP", 8678, 30064, 7003)
- svc.Status.LoadBalancer = v1.LoadBalancerStatus{
- Ingress: []v1.LoadBalancerIngress{
- {IP: "10.1.2.3"},
- },
- }
- svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyTypeLocal
- svc.Spec.HealthCheckNodePort = 345
- }),
- }
- for i := range services {
- fp.addService(services[i])
- }
- result := UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
- if len(fp.serviceMap) != 8 {
- t.Errorf("expected service map length 2, got %v", fp.serviceMap)
- }
- // The only-local-loadbalancer ones get added
- if len(result.HCServiceNodePorts) != 1 {
- t.Errorf("expected 1 healthcheck port, got %v", result.HCServiceNodePorts)
- } else {
- nsn := makeNSN("ns1", "only-local-load-balancer")
- if port, found := result.HCServiceNodePorts[nsn]; !found || port != 345 {
- t.Errorf("expected healthcheck port [%q]=345: got %v", nsn, result.HCServiceNodePorts)
- }
- }
- if len(result.UDPStaleClusterIP) != 0 {
- // Services only added, so nothing stale yet
- t.Errorf("expected stale UDP services length 0, got %d", len(result.UDPStaleClusterIP))
- }
- // Remove some stuff
- // oneService is a modification of services[0] with removed first port.
- oneService := makeTestService("ns2", "cluster-ip", func(svc *v1.Service) {
- svc.Spec.Type = v1.ServiceTypeClusterIP
- svc.Spec.ClusterIP = "172.16.55.4"
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p2", "UDP", 1235, 5321, 0)
- })
- fp.updateService(services[0], oneService)
- fp.deleteService(services[1])
- fp.deleteService(services[2])
- fp.deleteService(services[3])
- result = UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
- if len(fp.serviceMap) != 1 {
- t.Errorf("expected service map length 1, got %v", fp.serviceMap)
- }
- if len(result.HCServiceNodePorts) != 0 {
- t.Errorf("expected 0 healthcheck ports, got %v", result.HCServiceNodePorts)
- }
- // All services but one were deleted. While you'd expect only the ClusterIPs
- // from the three deleted services here, we still have the ClusterIP for
- // the not-deleted service, because one of it's ServicePorts was deleted.
- expectedStaleUDPServices := []string{"172.16.55.10", "172.16.55.4", "172.16.55.11", "172.16.55.12"}
- if len(result.UDPStaleClusterIP) != len(expectedStaleUDPServices) {
- t.Errorf("expected stale UDP services length %d, got %v", len(expectedStaleUDPServices), result.UDPStaleClusterIP.UnsortedList())
- }
- for _, ip := range expectedStaleUDPServices {
- if !result.UDPStaleClusterIP.Has(ip) {
- t.Errorf("expected stale UDP service service %s", ip)
- }
- }
- }
- func TestBuildServiceMapServiceUpdate(t *testing.T) {
- fp := newFakeProxier()
- servicev1 := makeTestService("ns1", "svc1", func(svc *v1.Service) {
- svc.Spec.Type = v1.ServiceTypeClusterIP
- svc.Spec.ClusterIP = "172.16.55.4"
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p1", "UDP", 1234, 4321, 0)
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p2", "TCP", 1235, 5321, 0)
- })
- servicev2 := makeTestService("ns1", "svc1", func(svc *v1.Service) {
- svc.Spec.Type = v1.ServiceTypeLoadBalancer
- svc.Spec.ClusterIP = "172.16.55.4"
- svc.Spec.LoadBalancerIP = "5.6.7.8"
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p1", "UDP", 1234, 4321, 7002)
- svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p2", "TCP", 1235, 5321, 7003)
- svc.Status.LoadBalancer = v1.LoadBalancerStatus{
- Ingress: []v1.LoadBalancerIngress{
- {IP: "10.1.2.3"},
- },
- }
- svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyTypeLocal
- svc.Spec.HealthCheckNodePort = 345
- })
- fp.addService(servicev1)
- result := UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
- if len(fp.serviceMap) != 2 {
- t.Errorf("expected service map length 2, got %v", fp.serviceMap)
- }
- if len(result.HCServiceNodePorts) != 0 {
- t.Errorf("expected healthcheck ports length 0, got %v", result.HCServiceNodePorts)
- }
- if len(result.UDPStaleClusterIP) != 0 {
- // Services only added, so nothing stale yet
- t.Errorf("expected stale UDP services length 0, got %d", len(result.UDPStaleClusterIP))
- }
- // Change service to load-balancer
- fp.updateService(servicev1, servicev2)
- result = UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
- if len(fp.serviceMap) != 2 {
- t.Errorf("expected service map length 2, got %v", fp.serviceMap)
- }
- if len(result.HCServiceNodePorts) != 1 {
- t.Errorf("expected healthcheck ports length 1, got %v", result.HCServiceNodePorts)
- }
- if len(result.UDPStaleClusterIP) != 0 {
- t.Errorf("expected stale UDP services length 0, got %v", result.UDPStaleClusterIP.UnsortedList())
- }
- // No change; make sure the service map stays the same and there are
- // no health-check changes
- fp.updateService(servicev2, servicev2)
- result = UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
- if len(fp.serviceMap) != 2 {
- t.Errorf("expected service map length 2, got %v", fp.serviceMap)
- }
- if len(result.HCServiceNodePorts) != 1 {
- t.Errorf("expected healthcheck ports length 1, got %v", result.HCServiceNodePorts)
- }
- if len(result.UDPStaleClusterIP) != 0 {
- t.Errorf("expected stale UDP services length 0, got %v", result.UDPStaleClusterIP.UnsortedList())
- }
- // And back to ClusterIP
- fp.updateService(servicev2, servicev1)
- result = UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
- if len(fp.serviceMap) != 2 {
- t.Errorf("expected service map length 2, got %v", fp.serviceMap)
- }
- if len(result.HCServiceNodePorts) != 0 {
- t.Errorf("expected healthcheck ports length 0, got %v", result.HCServiceNodePorts)
- }
- if len(result.UDPStaleClusterIP) != 0 {
- // Services only added, so nothing stale yet
- t.Errorf("expected stale UDP services length 0, got %d", len(result.UDPStaleClusterIP))
- }
- }
|