k3s/pkg/proxy/ipvs/proxier_test.go

2910 lines
85 KiB
Go
Raw Normal View History

/*
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 ipvs
import (
2017-08-30 08:48:06 +00:00
"bytes"
2017-11-26 13:47:50 +00:00
"fmt"
"net"
"reflect"
2018-03-20 09:03:36 +00:00
"strings"
"testing"
"time"
2018-08-15 13:51:19 +00:00
"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/kubernetes/pkg/proxy"
"k8s.io/utils/exec"
fakeexec "k8s.io/utils/exec/testing"
"k8s.io/apimachinery/pkg/util/sets"
2017-09-04 05:41:44 +00:00
netlinktest "k8s.io/kubernetes/pkg/proxy/ipvs/testing"
utilproxy "k8s.io/kubernetes/pkg/proxy/util"
2018-01-17 02:30:33 +00:00
proxyutiltest "k8s.io/kubernetes/pkg/proxy/util/testing"
utilipset "k8s.io/kubernetes/pkg/util/ipset"
ipsettest "k8s.io/kubernetes/pkg/util/ipset/testing"
utiliptables "k8s.io/kubernetes/pkg/util/iptables"
iptablestest "k8s.io/kubernetes/pkg/util/iptables/testing"
utilipvs "k8s.io/kubernetes/pkg/util/ipvs"
ipvstest "k8s.io/kubernetes/pkg/util/ipvs/testing"
)
const testHostname = "test-hostname"
type fakeIPGetter struct {
nodeIPs []net.IP
}
func (f *fakeIPGetter) NodeIPs() ([]net.IP, error) {
return f.nodeIPs, nil
}
type fakeHealthChecker struct {
services map[types.NamespacedName]uint16
Endpoints map[types.NamespacedName]int
}
func newFakeHealthChecker() *fakeHealthChecker {
return &fakeHealthChecker{
services: map[types.NamespacedName]uint16{},
Endpoints: map[types.NamespacedName]int{},
}
}
// fakePortOpener implements portOpener.
type fakePortOpener struct {
openPorts []*utilproxy.LocalPort
}
// OpenLocalPort fakes out the listen() and bind() used by syncProxyRules
// to lock a local port.
func (f *fakePortOpener) OpenLocalPort(lp *utilproxy.LocalPort) (utilproxy.Closeable, error) {
f.openPorts = append(f.openPorts, lp)
return nil, nil
}
func (fake *fakeHealthChecker) SyncServices(newServices map[types.NamespacedName]uint16) error {
fake.services = newServices
return nil
}
func (fake *fakeHealthChecker) SyncEndpoints(newEndpoints map[types.NamespacedName]int) error {
fake.Endpoints = newEndpoints
return nil
}
2017-11-26 13:47:50 +00:00
// fakeKernelHandler implements KernelHandler.
type fakeKernelHandler struct {
modules []string
}
func (fake *fakeKernelHandler) GetModules() ([]string, error) {
return fake.modules, nil
}
// fakeKernelHandler implements KernelHandler.
type fakeIPSetVersioner struct {
version string
err error
}
func (fake *fakeIPSetVersioner) GetVersion() (string, error) {
return fake.version, fake.err
}
// New returns a new FakeSysctl
func NewFakeSysctl() *FakeSysctl {
return &FakeSysctl{}
}
type FakeSysctl struct {
}
// GetSysctl returns the value for the specified sysctl setting
func (fakeSysctl *FakeSysctl) GetSysctl(sysctl string) (int, error) {
return 1, nil
}
// SetSysctl modifies the specified sysctl flag to the new value
func (fakeSysctl *FakeSysctl) SetSysctl(sysctl string, newVal int) error {
return nil
}
func NewFakeProxier(ipt utiliptables.Interface, ipvs utilipvs.Interface, ipset utilipset.Interface, nodeIPs []net.IP) *Proxier {
fcmd := fakeexec.FakeCmd{
CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
func() ([]byte, error) { return []byte("dummy device have been created"), nil },
2018-06-09 08:00:54 +00:00
func() ([]byte, error) { return []byte(""), nil },
},
}
fexec := &fakeexec.FakeExec{
CommandScript: []fakeexec.FakeCommandAction{
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
2018-06-09 08:00:54 +00:00
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
},
LookPathFunc: func(cmd string) (string, error) { return cmd, nil },
}
// initialize ipsetList with all sets we needed
ipsetList := make(map[string]*IPSet)
for _, is := range ipsetInfo {
ipsetList[is.name] = NewIPSet(ipset, is.name, is.setType, false, is.comment)
}
return &Proxier{
exec: fexec,
serviceMap: make(proxy.ServiceMap),
serviceChanges: proxy.NewServiceChangeTracker(newServiceInfo, nil, nil),
endpointsMap: make(proxy.EndpointsMap),
endpointsChanges: proxy.NewEndpointChangeTracker(testHostname, nil, nil, nil),
excludeCIDRs: make([]string, 0),
iptables: ipt,
ipvs: ipvs,
ipset: ipset,
clusterCIDR: "10.0.0.0/24",
hostname: testHostname,
portsMap: make(map[utilproxy.LocalPort]utilproxy.Closeable),
portMapper: &fakePortOpener{[]*utilproxy.LocalPort{}},
healthChecker: newFakeHealthChecker(),
ipvsScheduler: DefaultScheduler,
ipGetter: &fakeIPGetter{nodeIPs: nodeIPs},
iptablesData: bytes.NewBuffer(nil),
natChains: bytes.NewBuffer(nil),
natRules: bytes.NewBuffer(nil),
filterChains: bytes.NewBuffer(nil),
filterRules: bytes.NewBuffer(nil),
netlinkHandle: netlinktest.NewFakeNetlinkHandle(),
ipsetList: ipsetList,
nodePortAddresses: make([]string, 0),
networkInterfacer: proxyutiltest.NewFakeNetwork(),
sctpUserSpaceNode: false,
}
}
func makeNSN(namespace, name string) types.NamespacedName {
return types.NamespacedName{Namespace: namespace, Name: name}
}
2018-08-15 13:51:19 +00:00
func makeServiceMap(proxier *Proxier, allServices ...*v1.Service) {
for i := range allServices {
proxier.OnServiceAdd(allServices[i])
}
proxier.mu.Lock()
defer proxier.mu.Unlock()
proxier.servicesSynced = true
}
2018-08-15 13:51:19 +00:00
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{},
},
2018-08-15 13:51:19 +00:00
Spec: v1.ServiceSpec{},
Status: v1.ServiceStatus{},
}
svcFunc(svc)
return svc
}
2018-08-15 13:51:19 +00:00
func makeEndpointsMap(proxier *Proxier, allEndpoints ...*v1.Endpoints) {
for i := range allEndpoints {
proxier.OnEndpointsAdd(allEndpoints[i])
}
proxier.mu.Lock()
defer proxier.mu.Unlock()
proxier.endpointsSynced = true
}
2018-08-15 13:51:19 +00:00
func makeTestEndpoints(namespace, name string, eptFunc func(*v1.Endpoints)) *v1.Endpoints {
ept := &v1.Endpoints{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
},
}
eptFunc(ept)
return ept
}
2018-06-09 08:00:54 +00:00
func TestCleanupLeftovers(t *testing.T) {
ipt := iptablestest.NewFake()
ipvs := ipvstest.NewFake()
ipset := ipsettest.NewFake(testIPSetVersion)
fp := NewFakeProxier(ipt, ipvs, ipset, nil)
svcIP := "10.20.30.41"
svcPort := 80
svcNodePort := 3001
svcPortName := proxy.ServicePortName{
NamespacedName: makeNSN("ns1", "svc1"),
Port: "p80",
}
makeServiceMap(fp,
2018-08-15 13:51:19 +00:00
makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
2018-06-09 08:00:54 +00:00
svc.Spec.Type = "NodePort"
svc.Spec.ClusterIP = svcIP
2018-08-15 13:51:19 +00:00
svc.Spec.Ports = []v1.ServicePort{{
2018-06-09 08:00:54 +00:00
Name: svcPortName.Port,
Port: int32(svcPort),
2018-08-15 13:51:19 +00:00
Protocol: v1.ProtocolTCP,
2018-06-09 08:00:54 +00:00
NodePort: int32(svcNodePort),
}}
}),
)
epIP := "10.180.0.1"
makeEndpointsMap(fp,
2018-08-15 13:51:19 +00:00
makeTestEndpoints(svcPortName.Namespace, svcPortName.Name, func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
2018-06-09 08:00:54 +00:00
IP: epIP,
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
2018-06-09 08:00:54 +00:00
Name: svcPortName.Port,
Port: int32(svcPort),
}},
}}
}),
)
fp.syncProxyRules()
// test cleanup left over
if CleanupLeftovers(ipvs, ipt, ipset, true) {
t.Errorf("Cleanup leftovers failed")
}
}
2017-11-26 13:47:50 +00:00
func TestCanUseIPVSProxier(t *testing.T) {
testCases := []struct {
mods []string
kernelErr error
ipsetVersion string
ipsetErr error
ok bool
}{
// case 0, kernel error
{
mods: []string{"foo", "bar", "baz"},
kernelErr: fmt.Errorf("oops"),
ipsetVersion: "0.0",
ok: false,
},
// case 1, ipset error
{
mods: []string{"foo", "bar", "baz"},
ipsetVersion: MinIPSetCheckVersion,
ipsetErr: fmt.Errorf("oops"),
ok: false,
},
// case 2, missing required kernel modules and ipset version too low
{
mods: []string{"foo", "bar", "baz"},
ipsetVersion: "1.1",
ok: false,
},
// case 3, missing required ip_vs_* kernel modules
{
mods: []string{"ip_vs", "a", "bc", "def"},
ipsetVersion: MinIPSetCheckVersion,
ok: false,
},
// case 4, ipset version too low
{
mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
ipsetVersion: "4.3.0",
ok: false,
},
// case 5
{
mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
ipsetVersion: MinIPSetCheckVersion,
ok: true,
},
// case 6
{
mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4", "foo", "bar"},
ipsetVersion: "6.19",
ok: true,
},
}
for i := range testCases {
handle := &fakeKernelHandler{modules: testCases[i].mods}
versioner := &fakeIPSetVersioner{version: testCases[i].ipsetVersion, err: testCases[i].ipsetErr}
ok, _ := CanUseIPVSProxier(handle, versioner)
if ok != testCases[i].ok {
t.Errorf("Case [%d], expect %v, got %v", i, testCases[i].ok, ok)
}
}
}
2017-12-18 03:01:26 +00:00
func TestGetNodeIPs(t *testing.T) {
testCases := []struct {
devAddresses map[string][]string
expectIPs []string
}{
// case 0
{
devAddresses: map[string][]string{"eth0": {"1.2.3.4"}, "lo": {"127.0.0.1"}},
expectIPs: []string{"1.2.3.4", "127.0.0.1"},
},
// case 1
{
devAddresses: map[string][]string{"lo": {"127.0.0.1"}},
expectIPs: []string{"127.0.0.1"},
},
// case 2
{
devAddresses: map[string][]string{},
expectIPs: []string{},
},
// case 3
{
devAddresses: map[string][]string{"encap0": {"10.20.30.40"}, "lo": {"127.0.0.1"}, "docker0": {"172.17.0.1"}},
expectIPs: []string{"10.20.30.40", "127.0.0.1", "172.17.0.1"},
},
// case 4
{
devAddresses: map[string][]string{"encaps9": {"10.20.30.40"}, "lo": {"127.0.0.1"}, "encap7": {"10.20.30.31"}},
expectIPs: []string{"10.20.30.40", "127.0.0.1", "10.20.30.31"},
},
// case 5
{
devAddresses: map[string][]string{"kube-ipvs0": {"1.2.3.4"}, "lo": {"127.0.0.1"}, "encap7": {"10.20.30.31"}},
expectIPs: []string{"127.0.0.1", "10.20.30.31"},
},
// case 6
{
devAddresses: map[string][]string{"kube-ipvs0": {"1.2.3.4", "2.3.4.5"}, "lo": {"127.0.0.1"}},
expectIPs: []string{"127.0.0.1"},
},
// case 7
{
devAddresses: map[string][]string{"kube-ipvs0": {"1.2.3.4", "2.3.4.5"}},
expectIPs: []string{},
},
// case 8
{
devAddresses: map[string][]string{"kube-ipvs0": {"1.2.3.4", "2.3.4.5"}, "eth5": {"3.4.5.6"}, "lo": {"127.0.0.1"}},
expectIPs: []string{"127.0.0.1", "3.4.5.6"},
},
// case 9
{
devAddresses: map[string][]string{"ipvs0": {"1.2.3.4"}, "lo": {"127.0.0.1"}, "encap7": {"10.20.30.31"}},
expectIPs: []string{"127.0.0.1", "10.20.30.31", "1.2.3.4"},
},
}
for i := range testCases {
fake := netlinktest.NewFakeNetlinkHandle()
for dev, addresses := range testCases[i].devAddresses {
fake.SetLocalAddresses(dev, addresses...)
}
r := realIPGetter{nl: fake}
ips, err := r.NodeIPs()
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
ipStrs := sets.NewString()
for _, ip := range ips {
ipStrs.Insert(ip.String())
}
if !ipStrs.Equal(sets.NewString(testCases[i].expectIPs...)) {
t.Errorf("case[%d], unexpected mismatch, expected: %v, got: %v", i, testCases[i].expectIPs, ips)
}
}
}
2018-06-09 08:00:54 +00:00
func TestNodePortUDP(t *testing.T) {
nodeIP := net.ParseIP("100.101.102.103")
ipt := iptablestest.NewFake()
ipvs := ipvstest.NewFake()
ipset := ipsettest.NewFake(testIPSetVersion)
fp := NewFakeProxier(ipt, ipvs, ipset, []net.IP{nodeIP})
svcIP := "10.20.30.41"
svcPort := 80
svcNodePort := 3001
svcPortName := proxy.ServicePortName{
NamespacedName: makeNSN("ns1", "svc1"),
Port: "p80",
}
makeServiceMap(fp,
2018-08-15 13:51:19 +00:00
makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
2018-06-09 08:00:54 +00:00
svc.Spec.Type = "NodePort"
svc.Spec.ClusterIP = svcIP
2018-08-15 13:51:19 +00:00
svc.Spec.Ports = []v1.ServicePort{{
2018-06-09 08:00:54 +00:00
Name: svcPortName.Port,
Port: int32(svcPort),
2018-08-15 13:51:19 +00:00
Protocol: v1.ProtocolUDP,
2018-06-09 08:00:54 +00:00
NodePort: int32(svcNodePort),
}}
}),
)
epIP := "10.180.0.1"
makeEndpointsMap(fp,
2018-08-15 13:51:19 +00:00
makeTestEndpoints(svcPortName.Namespace, svcPortName.Name, func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
2018-06-09 08:00:54 +00:00
IP: epIP,
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
2018-06-09 08:00:54 +00:00
Name: svcPortName.Port,
Port: int32(svcPort),
}},
}}
}),
)
fp.nodePortAddresses = []string{"0.0.0.0/0"}
fp.syncProxyRules()
// Check ipvs service and destinations
epVS := &netlinktest.ExpectedVirtualServer{
2018-08-15 13:51:19 +00:00
VSNum: 2, IP: nodeIP.String(), Port: uint16(svcNodePort), Protocol: string(v1.ProtocolTCP),
2018-06-09 08:00:54 +00:00
RS: []netlinktest.ExpectedRealServer{{
IP: epIP, Port: uint16(svcPort),
}}}
checkIPVS(t, fp, epVS)
// check ipSet rules
epIPSet := netlinktest.ExpectedIPSet{
kubeNodePortSetUDP: {{
Port: svcNodePort,
2018-08-15 13:51:19 +00:00
Protocol: strings.ToLower(string(v1.ProtocolUDP)),
2018-06-09 08:00:54 +00:00
SetType: utilipset.BitmapPort,
}},
}
checkIPSet(t, fp, epIPSet)
// Check iptables chain and rules
epIpt := netlinktest.ExpectedIptablesChain{
string(KubeNodePortChain): {{
2018-07-04 09:33:31 +00:00
JumpChain: string(KubeMarkMasqChain), MatchSet: kubeNodePortSetUDP,
}},
string(kubeServicesChain): {{
JumpChain: string(KubeNodePortChain), MatchSet: "",
2018-06-09 08:00:54 +00:00
}},
}
checkIptables(t, ipt, epIpt)
}
func TestNodePort(t *testing.T) {
ipt := iptablestest.NewFake()
ipvs := ipvstest.NewFake()
2017-12-20 07:54:07 +00:00
ipset := ipsettest.NewFake(testIPSetVersion)
nodeIPv4 := net.ParseIP("100.101.102.103")
nodeIPv6 := net.ParseIP("2001:db8::1:1")
nodeIPs := sets.NewString(nodeIPv4.String(), nodeIPv6.String())
fp := NewFakeProxier(ipt, ipvs, ipset, []net.IP{nodeIPv4, nodeIPv6})
svcIP := "10.20.30.41"
svcPort := 80
svcNodePort := 3001
svcPortName := proxy.ServicePortName{
NamespacedName: makeNSN("ns1", "svc1"),
Port: "p80",
}
makeServiceMap(fp,
2018-08-15 13:51:19 +00:00
makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
svc.Spec.Type = "NodePort"
svc.Spec.ClusterIP = svcIP
2018-08-15 13:51:19 +00:00
svc.Spec.Ports = []v1.ServicePort{{
Name: svcPortName.Port,
Port: int32(svcPort),
2018-08-15 13:51:19 +00:00
Protocol: v1.ProtocolTCP,
NodePort: int32(svcNodePort),
}}
}),
)
epIPv4 := "10.180.0.1"
epIPv6 := "1002:ab8::2:10"
epIPs := sets.NewString(epIPv4, epIPv6)
makeEndpointsMap(fp,
2018-08-15 13:51:19 +00:00
makeTestEndpoints(svcPortName.Namespace, svcPortName.Name, func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: epIPv4,
}, {
IP: epIPv6,
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: svcPortName.Port,
Port: int32(svcPort),
}},
}}
}),
)
2018-01-17 02:30:33 +00:00
fp.nodePortAddresses = []string{"0.0.0.0/0"}
2017-09-06 08:46:09 +00:00
fp.syncProxyRules()
// Check ipvs service and destinations
services, err := ipvs.GetVirtualServers()
if err != nil {
t.Errorf("Failed to get ipvs services, err: %v", err)
}
if len(services) != 3 {
t.Errorf("Expect 3 ipvs services, got %d", len(services))
}
found := false
for _, svc := range services {
2018-08-15 13:51:19 +00:00
if nodeIPs.Has(svc.Address.String()) && svc.Port == uint16(svcNodePort) && svc.Protocol == string(v1.ProtocolTCP) {
found = true
destinations, err := ipvs.GetRealServers(svc)
if err != nil {
t.Errorf("Failed to get ipvs destinations, err: %v", err)
}
for _, dest := range destinations {
if !epIPs.Has(dest.Address.String()) || dest.Port != uint16(svcPort) {
t.Errorf("service Endpoint mismatch ipvs service destination")
}
}
break
}
}
if !found {
t.Errorf("Expect node port type service, got none")
}
}
func TestNodePortNoEndpoint(t *testing.T) {
ipt := iptablestest.NewFake()
ipvs := ipvstest.NewFake()
2017-12-20 07:54:07 +00:00
ipset := ipsettest.NewFake(testIPSetVersion)
nodeIP := net.ParseIP("100.101.102.103")
fp := NewFakeProxier(ipt, ipvs, ipset, []net.IP{nodeIP})
svcIP := "10.20.30.41"
svcPort := 80
svcNodePort := 3001
svcPortName := proxy.ServicePortName{
NamespacedName: makeNSN("ns1", "svc1"),
Port: "p80",
}
makeServiceMap(fp,
2018-08-15 13:51:19 +00:00
makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
svc.Spec.Type = "NodePort"
svc.Spec.ClusterIP = svcIP
2018-08-15 13:51:19 +00:00
svc.Spec.Ports = []v1.ServicePort{{
Name: svcPortName.Port,
Port: int32(svcPort),
2018-08-15 13:51:19 +00:00
Protocol: v1.ProtocolTCP,
NodePort: int32(svcNodePort),
}}
}),
)
makeEndpointsMap(fp)
2018-01-17 02:30:33 +00:00
fp.nodePortAddresses = []string{"0.0.0.0/0"}
2017-09-06 08:46:09 +00:00
fp.syncProxyRules()
// Check ipvs service and destinations
services, err := ipvs.GetVirtualServers()
if err != nil {
t.Errorf("Failed to get ipvs services, err: %v", err)
}
if len(services) != 2 {
t.Errorf("Expect 2 ipvs services, got %d", len(services))
}
found := false
for _, svc := range services {
2018-08-15 13:51:19 +00:00
if svc.Address.Equal(nodeIP) && svc.Port == uint16(svcNodePort) && svc.Protocol == string(v1.ProtocolTCP) {
found = true
destinations, _ := ipvs.GetRealServers(svc)
if len(destinations) != 0 {
t.Errorf("Unexpected %d destinations, expect 0 destinations", len(destinations))
}
break
}
}
if !found {
t.Errorf("Expect node port type service, got none")
}
}
func TestClusterIPNoEndpoint(t *testing.T) {
ipt := iptablestest.NewFake()
ipvs := ipvstest.NewFake()
2017-12-20 07:54:07 +00:00
ipset := ipsettest.NewFake(testIPSetVersion)
fp := NewFakeProxier(ipt, ipvs, ipset, nil)
svcIP := "10.20.30.41"
svcPort := 80
svcPortName := proxy.ServicePortName{
NamespacedName: makeNSN("ns1", "svc1"),
Port: "p80",
}
makeServiceMap(fp,
2018-08-15 13:51:19 +00:00
makeTestService(svcPortName.Namespace, svcPortName.Namespace, func(svc *v1.Service) {
svc.Spec.ClusterIP = svcIP
2018-08-15 13:51:19 +00:00
svc.Spec.Ports = []v1.ServicePort{{
Name: svcPortName.Port,
Port: int32(svcPort),
2018-08-15 13:51:19 +00:00
Protocol: v1.ProtocolTCP,
}}
}),
)
makeEndpointsMap(fp)
2017-09-06 08:46:09 +00:00
fp.syncProxyRules()
// check ipvs service and destinations
services, err := ipvs.GetVirtualServers()
if err != nil {
t.Errorf("Failed to get ipvs services, err: %v", err)
}
if len(services) != 1 {
t.Errorf("Expect 1 ipvs services, got %d", len(services))
} else {
2018-08-15 13:51:19 +00:00
if services[0].Address.String() != svcIP || services[0].Port != uint16(svcPort) || services[0].Protocol != string(v1.ProtocolTCP) {
t.Errorf("Unexpected mismatch service")
} else {
destinations, _ := ipvs.GetRealServers(services[0])
if len(destinations) != 0 {
t.Errorf("Unexpected %d destinations, expect 0 destinations", len(destinations))
}
}
}
}
func TestClusterIP(t *testing.T) {
ipt := iptablestest.NewFake()
ipvs := ipvstest.NewFake()
2017-12-20 07:54:07 +00:00
ipset := ipsettest.NewFake(testIPSetVersion)
fp := NewFakeProxier(ipt, ipvs, ipset, nil)
svcIPv4 := "10.20.30.41"
svcPortV4 := 80
svcPortNameV4 := proxy.ServicePortName{
NamespacedName: makeNSN("ns1", "svc1"),
Port: "p80",
}
svcIPv6 := "1002:ab8::2:1"
svcPortV6 := 8080
svcPortNameV6 := proxy.ServicePortName{
NamespacedName: makeNSN("ns2", "svc2"),
Port: "p8080",
}
makeServiceMap(fp,
2018-08-15 13:51:19 +00:00
makeTestService(svcPortNameV4.Namespace, svcPortNameV4.Name, func(svc *v1.Service) {
svc.Spec.ClusterIP = svcIPv4
2018-08-15 13:51:19 +00:00
svc.Spec.Ports = []v1.ServicePort{{
Name: svcPortNameV4.Port,
Port: int32(svcPortV4),
2018-08-15 13:51:19 +00:00
Protocol: v1.ProtocolTCP,
}}
}),
2018-08-15 13:51:19 +00:00
makeTestService(svcPortNameV6.Namespace, svcPortNameV6.Name, func(svc *v1.Service) {
svc.Spec.ClusterIP = svcIPv6
2018-08-15 13:51:19 +00:00
svc.Spec.Ports = []v1.ServicePort{{
Name: svcPortNameV6.Port,
Port: int32(svcPortV6),
2018-08-15 13:51:19 +00:00
Protocol: v1.ProtocolTCP,
}}
}),
)
epIPv4 := "10.180.0.1"
epIPv6 := "1009:ab8::5:6"
makeEndpointsMap(fp,
2018-08-15 13:51:19 +00:00
makeTestEndpoints(svcPortNameV4.Namespace, svcPortNameV4.Name, func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: epIPv4,
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: svcPortNameV4.Port,
Port: int32(svcPortV4),
}},
}}
}),
2018-08-15 13:51:19 +00:00
makeTestEndpoints(svcPortNameV6.Namespace, svcPortNameV6.Name, func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: epIPv6,
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: svcPortNameV6.Port,
Port: int32(svcPortV6),
}},
}}
}),
)
2017-09-06 08:46:09 +00:00
fp.syncProxyRules()
// check ipvs service and destinations
services, err := ipvs.GetVirtualServers()
if err != nil {
t.Errorf("Failed to get ipvs services, err: %v", err)
}
if len(services) != 2 {
t.Errorf("Expect 2 ipvs services, got %d", len(services))
}
for i := range services {
// Check services
if services[i].Address.String() == svcIPv4 {
2018-08-15 13:51:19 +00:00
if services[i].Port != uint16(svcPortV4) || services[i].Protocol != string(v1.ProtocolTCP) {
t.Errorf("Unexpected mismatch service")
}
// Check destinations
destinations, _ := ipvs.GetRealServers(services[i])
if len(destinations) != 1 {
t.Errorf("Expected 1 destinations, got %d destinations", len(destinations))
continue
}
if destinations[0].Address.String() != epIPv4 || destinations[0].Port != uint16(svcPortV4) {
t.Errorf("Unexpected mismatch destinations")
}
}
if services[i].Address.String() == svcIPv6 {
2018-08-15 13:51:19 +00:00
if services[i].Port != uint16(svcPortV6) || services[i].Protocol != string(v1.ProtocolTCP) {
t.Errorf("Unexpected mismatch service")
}
// Check destinations
destinations, _ := ipvs.GetRealServers(services[i])
if len(destinations) != 1 {
t.Errorf("Expected 1 destinations, got %d destinations", len(destinations))
continue
}
if destinations[0].Address.String() != epIPv6 || destinations[0].Port != uint16(svcPortV6) {
t.Errorf("Unexpected mismatch destinations")
}
}
}
}
func TestExternalIPsNoEndpoint(t *testing.T) {
ipt := iptablestest.NewFake()
ipvs := ipvstest.NewFake()
2017-12-20 07:54:07 +00:00
ipset := ipsettest.NewFake(testIPSetVersion)
fp := NewFakeProxier(ipt, ipvs, ipset, nil)
svcIP := "10.20.30.41"
svcPort := 80
svcExternalIPs := "50.60.70.81"
svcPortName := proxy.ServicePortName{
NamespacedName: makeNSN("ns1", "svc1"),
Port: "p80",
}
makeServiceMap(fp,
2018-08-15 13:51:19 +00:00
makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
svc.Spec.Type = "ClusterIP"
svc.Spec.ClusterIP = svcIP
svc.Spec.ExternalIPs = []string{svcExternalIPs}
2018-08-15 13:51:19 +00:00
svc.Spec.Ports = []v1.ServicePort{{
Name: svcPortName.Port,
Port: int32(svcPort),
2018-08-15 13:51:19 +00:00
Protocol: v1.ProtocolTCP,
TargetPort: intstr.FromInt(svcPort),
}}
}),
)
makeEndpointsMap(fp)
2017-09-06 08:46:09 +00:00
fp.syncProxyRules()
// check ipvs service and destinations
services, err := ipvs.GetVirtualServers()
if err != nil {
t.Errorf("Failed to get ipvs services, err: %v", err)
}
if len(services) != 2 {
t.Errorf("Expect 2 ipvs services, got %d", len(services))
}
found := false
for _, svc := range services {
2018-08-15 13:51:19 +00:00
if svc.Address.String() == svcExternalIPs && svc.Port == uint16(svcPort) && svc.Protocol == string(v1.ProtocolTCP) {
found = true
destinations, _ := ipvs.GetRealServers(svc)
if len(destinations) != 0 {
t.Errorf("Unexpected %d destinations, expect 0 destinations", len(destinations))
}
break
}
}
if !found {
t.Errorf("Expect external ip type service, got none")
}
}
func TestExternalIPs(t *testing.T) {
ipt := iptablestest.NewFake()
ipvs := ipvstest.NewFake()
2017-12-20 07:54:07 +00:00
ipset := ipsettest.NewFake(testIPSetVersion)
fp := NewFakeProxier(ipt, ipvs, ipset, nil)
svcIP := "10.20.30.41"
svcPort := 80
2018-06-09 08:00:54 +00:00
svcExternalIPs := sets.NewString("50.60.70.81", "2012::51", "127.0.0.1")
svcPortName := proxy.ServicePortName{
NamespacedName: makeNSN("ns1", "svc1"),
Port: "p80",
}
makeServiceMap(fp,
2018-08-15 13:51:19 +00:00
makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
svc.Spec.Type = "ClusterIP"
svc.Spec.ClusterIP = svcIP
svc.Spec.ExternalIPs = svcExternalIPs.UnsortedList()
2018-08-15 13:51:19 +00:00
svc.Spec.Ports = []v1.ServicePort{{
Name: svcPortName.Port,
Port: int32(svcPort),
2018-08-15 13:51:19 +00:00
Protocol: v1.ProtocolTCP,
TargetPort: intstr.FromInt(svcPort),
}}
}),
)
epIP := "10.180.0.1"
makeEndpointsMap(fp,
2018-08-15 13:51:19 +00:00
makeTestEndpoints(svcPortName.Namespace, svcPortName.Name, func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: epIP,
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: svcPortName.Port,
Port: int32(svcPort),
}},
}}
}),
)
2017-09-06 08:46:09 +00:00
fp.syncProxyRules()
// check ipvs service and destinations
services, err := ipvs.GetVirtualServers()
if err != nil {
t.Errorf("Failed to get ipvs services, err: %v", err)
}
2018-06-09 08:00:54 +00:00
if len(services) != 4 {
t.Errorf("Expect 4 ipvs services, got %d", len(services))
}
found := false
for _, svc := range services {
2018-08-15 13:51:19 +00:00
if svcExternalIPs.Has(svc.Address.String()) && svc.Port == uint16(svcPort) && svc.Protocol == string(v1.ProtocolTCP) {
found = true
destinations, _ := ipvs.GetRealServers(svc)
for _, dest := range destinations {
if dest.Address.String() != epIP || dest.Port != uint16(svcPort) {
t.Errorf("service Endpoint mismatch ipvs service destination")
}
}
break
}
}
if !found {
t.Errorf("Expect external ip type service, got none")
}
}
func TestLoadBalancer(t *testing.T) {
2018-06-09 08:00:54 +00:00
ipt, fp := buildFakeProxier()
svcIP := "10.20.30.41"
svcPort := 80
svcNodePort := 3001
svcLBIP := "1.2.3.4"
svcPortName := proxy.ServicePortName{
NamespacedName: makeNSN("ns1", "svc1"),
Port: "p80",
}
makeServiceMap(fp,
2018-08-15 13:51:19 +00:00
makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
svc.Spec.Type = "LoadBalancer"
svc.Spec.ClusterIP = svcIP
2018-08-15 13:51:19 +00:00
svc.Spec.Ports = []v1.ServicePort{{
Name: svcPortName.Port,
Port: int32(svcPort),
2018-08-15 13:51:19 +00:00
Protocol: v1.ProtocolTCP,
NodePort: int32(svcNodePort),
}}
2018-08-15 13:51:19 +00:00
svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{
IP: svcLBIP,
}}
}),
)
epIP := "10.180.0.1"
makeEndpointsMap(fp,
2018-08-15 13:51:19 +00:00
makeTestEndpoints(svcPortName.Namespace, svcPortName.Name, func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: epIP,
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: svcPortName.Port,
Port: int32(svcPort),
}},
}}
}),
)
2017-09-06 08:46:09 +00:00
fp.syncProxyRules()
2018-06-09 08:00:54 +00:00
// Expect 2 services and 1 destination
epVS := &netlinktest.ExpectedVirtualServer{
2018-08-15 13:51:19 +00:00
VSNum: 2, IP: svcLBIP, Port: uint16(svcNodePort), Protocol: string(v1.ProtocolTCP),
2018-06-09 08:00:54 +00:00
RS: []netlinktest.ExpectedRealServer{{
IP: epIP, Port: uint16(svcPort),
}}}
checkIPVS(t, fp, epVS)
// check ipSet rules
epIPSet := netlinktest.ExpectedIPSet{
kubeLoadBalancerSet: {{
IP: svcLBIP,
Port: svcPort,
2018-08-15 13:51:19 +00:00
Protocol: strings.ToLower(string(v1.ProtocolTCP)),
2018-06-09 08:00:54 +00:00
SetType: utilipset.HashIPPort,
}},
}
checkIPSet(t, fp, epIPSet)
// Check iptables chain and rules
epIpt := netlinktest.ExpectedIptablesChain{
string(kubeServicesChain): {{
JumpChain: string(KubeLoadBalancerChain), MatchSet: kubeLoadBalancerSet,
}},
string(kubeLoadBalancerSet): {{
JumpChain: string(KubeMarkMasqChain), MatchSet: "",
}},
}
checkIptables(t, ipt, epIpt)
}
func TestOnlyLocalNodePorts(t *testing.T) {
nodeIP := net.ParseIP("100.101.102.103")
ipt, fp := buildFakeProxier()
2018-03-27 11:40:14 +00:00
svcIP := "10.20.30.41"
svcPort := 80
svcNodePort := 3001
svcPortName := proxy.ServicePortName{
NamespacedName: makeNSN("ns1", "svc1"),
Port: "p80",
}
makeServiceMap(fp,
2018-08-15 13:51:19 +00:00
makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
svc.Spec.Type = "NodePort"
svc.Spec.ClusterIP = svcIP
2018-08-15 13:51:19 +00:00
svc.Spec.Ports = []v1.ServicePort{{
Name: svcPortName.Port,
Port: int32(svcPort),
2018-08-15 13:51:19 +00:00
Protocol: v1.ProtocolTCP,
NodePort: int32(svcNodePort),
}}
2018-08-15 13:51:19 +00:00
svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyTypeLocal
}),
)
2018-03-27 11:40:14 +00:00
epIP := "10.180.0.1"
epIP1 := "10.180.1.1"
thisHostname := testHostname
otherHostname := "other-hostname"
makeEndpointsMap(fp,
2018-08-15 13:51:19 +00:00
makeTestEndpoints(svcPortName.Namespace, svcPortName.Name, func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{
{ // **local** endpoint address, should be added as RS
2018-08-15 13:51:19 +00:00
Addresses: []v1.EndpointAddress{{
IP: epIP,
NodeName: &thisHostname,
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: svcPortName.Port,
Port: int32(svcPort),
}}},
{ // **remote** endpoint address, should not be added as RS
2018-08-15 13:51:19 +00:00
Addresses: []v1.EndpointAddress{{
IP: epIP1,
NodeName: &otherHostname,
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: svcPortName.Port,
Port: int32(svcPort),
}},
}}
}),
)
2018-01-17 02:30:33 +00:00
itf := net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0}
addrs := []net.Addr{proxyutiltest.AddrStruct{Val: "100.101.102.103/24"}}
itf1 := net.Interface{Index: 1, MTU: 0, Name: "eth1", HardwareAddr: nil, Flags: 0}
addrs1 := []net.Addr{proxyutiltest.AddrStruct{Val: "2001:db8::0/64"}}
fp.networkInterfacer.(*proxyutiltest.FakeNetwork).AddInterfaceAddr(&itf, addrs)
fp.networkInterfacer.(*proxyutiltest.FakeNetwork).AddInterfaceAddr(&itf1, addrs1)
fp.nodePortAddresses = []string{"100.101.102.0/24", "2001:db8::0/64"}
2017-09-06 08:46:09 +00:00
fp.syncProxyRules()
2018-01-17 02:30:33 +00:00
// Expect 3 services and 1 destination
2018-03-27 11:40:14 +00:00
epVS := &netlinktest.ExpectedVirtualServer{
2018-08-15 13:51:19 +00:00
VSNum: 3, IP: nodeIP.String(), Port: uint16(svcNodePort), Protocol: string(v1.ProtocolTCP),
2018-03-27 11:40:14 +00:00
RS: []netlinktest.ExpectedRealServer{{
IP: epIP, Port: uint16(svcPort),
}}}
checkIPVS(t, fp, epVS)
// check ipSet rules
epEntry := &utilipset.Entry{
Port: svcNodePort,
2018-08-15 13:51:19 +00:00
Protocol: strings.ToLower(string(v1.ProtocolTCP)),
2018-03-27 11:40:14 +00:00
SetType: utilipset.BitmapPort,
}
2018-03-27 11:40:14 +00:00
epIPSet := netlinktest.ExpectedIPSet{
kubeNodePortSetTCP: {epEntry},
kubeNodePortLocalSetTCP: {epEntry},
}
2018-03-27 11:40:14 +00:00
checkIPSet(t, fp, epIPSet)
// Check iptables chain and rules
epIpt := netlinktest.ExpectedIptablesChain{
string(kubeServicesChain): {{
2018-07-04 09:33:31 +00:00
JumpChain: string(KubeNodePortChain), MatchSet: "",
2018-03-27 11:40:14 +00:00
}},
string(KubeNodePortChain): {{
JumpChain: "RETURN", MatchSet: kubeNodePortLocalSetTCP,
2018-03-27 11:40:14 +00:00
}, {
2018-07-04 09:33:31 +00:00
JumpChain: string(KubeMarkMasqChain), MatchSet: kubeNodePortSetTCP,
2018-03-27 11:40:14 +00:00
}},
}
2018-03-27 11:40:14 +00:00
checkIptables(t, ipt, epIpt)
}
2018-03-20 09:03:36 +00:00
func TestLoadBalanceSourceRanges(t *testing.T) {
ipt, fp := buildFakeProxier()
2018-03-27 11:40:14 +00:00
2018-03-20 09:03:36 +00:00
svcIP := "10.20.30.41"
svcPort := 80
svcLBIP := "1.2.3.4"
svcLBSource := "10.0.0.0/8"
svcPortName := proxy.ServicePortName{
NamespacedName: makeNSN("ns1", "svc1"),
Port: "p80",
}
epIP := "10.180.0.1"
makeServiceMap(fp,
2018-08-15 13:51:19 +00:00
makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
2018-03-20 09:03:36 +00:00
svc.Spec.Type = "LoadBalancer"
svc.Spec.ClusterIP = svcIP
2018-08-15 13:51:19 +00:00
svc.Spec.Ports = []v1.ServicePort{{
2018-03-20 09:03:36 +00:00
Name: svcPortName.Port,
Port: int32(svcPort),
2018-08-15 13:51:19 +00:00
Protocol: v1.ProtocolTCP,
2018-03-20 09:03:36 +00:00
}}
2018-08-15 13:51:19 +00:00
svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{
2018-03-20 09:03:36 +00:00
IP: svcLBIP,
}}
svc.Spec.LoadBalancerSourceRanges = []string{
svcLBSource,
}
}),
)
makeEndpointsMap(fp,
2018-08-15 13:51:19 +00:00
makeTestEndpoints(svcPortName.Namespace, svcPortName.Name, func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
2018-03-20 09:03:36 +00:00
IP: epIP,
2018-03-27 11:40:14 +00:00
NodeName: nil,
2018-03-20 09:03:36 +00:00
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
2018-03-20 09:03:36 +00:00
Name: svcPortName.Port,
Port: int32(svcPort),
}},
}}
}),
)
fp.syncProxyRules()
// Check ipvs service and destinations
2018-03-27 11:40:14 +00:00
epVS := &netlinktest.ExpectedVirtualServer{
2018-08-15 13:51:19 +00:00
VSNum: 2, IP: svcLBIP, Port: uint16(svcPort), Protocol: string(v1.ProtocolTCP),
2018-03-27 11:40:14 +00:00
RS: []netlinktest.ExpectedRealServer{{
IP: epIP, Port: uint16(svcPort),
}}}
checkIPVS(t, fp, epVS)
2018-03-20 09:03:36 +00:00
// Check ipset entry
2018-03-27 11:40:14 +00:00
epIPSet := netlinktest.ExpectedIPSet{
kubeLoadBalancerSet: {{
2018-03-20 09:03:36 +00:00
IP: svcLBIP,
Port: svcPort,
2018-08-15 13:51:19 +00:00
Protocol: strings.ToLower(string(v1.ProtocolTCP)),
2018-03-20 09:03:36 +00:00
SetType: utilipset.HashIPPort,
2018-03-27 11:40:14 +00:00
}},
kubeLoadbalancerFWSet: {{
2018-04-17 11:32:32 +00:00
IP: svcLBIP,
Port: svcPort,
2018-08-15 13:51:19 +00:00
Protocol: strings.ToLower(string(v1.ProtocolTCP)),
2018-04-17 11:32:32 +00:00
SetType: utilipset.HashIPPort,
}},
kubeLoadBalancerSourceCIDRSet: {{
2018-03-20 09:03:36 +00:00
IP: svcLBIP,
Port: svcPort,
2018-08-15 13:51:19 +00:00
Protocol: strings.ToLower(string(v1.ProtocolTCP)),
2018-03-20 09:03:36 +00:00
Net: svcLBSource,
SetType: utilipset.HashIPPortNet,
2018-03-27 11:40:14 +00:00
}},
2018-03-20 09:03:36 +00:00
}
2018-03-27 11:40:14 +00:00
checkIPSet(t, fp, epIPSet)
2018-03-20 09:03:36 +00:00
// Check iptables chain and rules
2018-03-27 11:40:14 +00:00
epIpt := netlinktest.ExpectedIptablesChain{
string(kubeServicesChain): {{
JumpChain: string(KubeLoadBalancerChain), MatchSet: kubeLoadBalancerSet,
2018-04-17 11:32:32 +00:00
}},
string(KubeLoadBalancerChain): {{
JumpChain: string(KubeFireWallChain), MatchSet: kubeLoadbalancerFWSet,
2018-04-17 11:32:32 +00:00
}, {
JumpChain: string(KubeMarkMasqChain), MatchSet: "",
2018-03-27 11:40:14 +00:00
}},
string(KubeFireWallChain): {{
JumpChain: "RETURN", MatchSet: kubeLoadBalancerSourceCIDRSet,
2018-03-27 11:40:14 +00:00
}, {
JumpChain: string(KubeMarkDropChain), MatchSet: "",
}},
2018-03-20 09:03:36 +00:00
}
2018-03-27 11:40:14 +00:00
checkIptables(t, ipt, epIpt)
2018-03-20 09:03:36 +00:00
}
2018-04-17 06:56:48 +00:00
func TestAcceptIPVSTraffic(t *testing.T) {
ipt, fp := buildFakeProxier()
2018-04-17 06:56:48 +00:00
ingressIP := "1.2.3.4"
externalIP := []string{"5.6.7.8"}
svcInfos := []struct {
2018-08-15 13:51:19 +00:00
svcType v1.ServiceType
2018-04-17 06:56:48 +00:00
svcIP string
svcName string
epIP string
}{
2018-08-15 13:51:19 +00:00
{v1.ServiceTypeClusterIP, "10.20.30.40", "svc1", "10.180.0.1"},
{v1.ServiceTypeLoadBalancer, "10.20.30.41", "svc2", "10.180.0.2"},
{v1.ServiceTypeNodePort, "10.20.30.42", "svc3", "10.180.0.3"},
2018-04-17 06:56:48 +00:00
}
for _, svcInfo := range svcInfos {
makeServiceMap(fp,
2018-08-15 13:51:19 +00:00
makeTestService("ns1", svcInfo.svcName, func(svc *v1.Service) {
2018-04-17 06:56:48 +00:00
svc.Spec.Type = svcInfo.svcType
svc.Spec.ClusterIP = svcInfo.svcIP
2018-08-15 13:51:19 +00:00
svc.Spec.Ports = []v1.ServicePort{{
2018-04-17 06:56:48 +00:00
Name: "p80",
Port: 80,
2018-08-15 13:51:19 +00:00
Protocol: v1.ProtocolTCP,
2018-04-17 06:56:48 +00:00
NodePort: 80,
}}
2018-08-15 13:51:19 +00:00
if svcInfo.svcType == v1.ServiceTypeLoadBalancer {
svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{
2018-04-17 06:56:48 +00:00
IP: ingressIP,
}}
}
2018-08-15 13:51:19 +00:00
if svcInfo.svcType == v1.ServiceTypeClusterIP {
2018-04-17 06:56:48 +00:00
svc.Spec.ExternalIPs = externalIP
}
}),
)
makeEndpointsMap(fp,
2018-08-15 13:51:19 +00:00
makeTestEndpoints("ns1", "p80", func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
2018-04-17 06:56:48 +00:00
IP: svcInfo.epIP,
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
2018-04-17 06:56:48 +00:00
Name: "p80",
Port: 80,
}},
}}
}),
)
}
fp.syncProxyRules()
// Check iptables chain and rules
epIpt := netlinktest.ExpectedIptablesChain{
string(kubeServicesChain): {
{JumpChain: "ACCEPT", MatchSet: kubeClusterIPSet},
{JumpChain: "ACCEPT", MatchSet: kubeLoadBalancerSet},
{JumpChain: "ACCEPT", MatchSet: kubeExternalIPSet},
2018-04-17 06:56:48 +00:00
},
}
checkIptables(t, ipt, epIpt)
}
func TestOnlyLocalLoadBalancing(t *testing.T) {
ipt, fp := buildFakeProxier()
2018-03-27 11:40:14 +00:00
svcIP := "10.20.30.41"
svcPort := 80
svcNodePort := 3001
svcLBIP := "1.2.3.4"
svcPortName := proxy.ServicePortName{
NamespacedName: makeNSN("ns1", "svc1"),
Port: "p80",
}
makeServiceMap(fp,
2018-08-15 13:51:19 +00:00
makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
svc.Spec.Type = "LoadBalancer"
svc.Spec.ClusterIP = svcIP
2018-08-15 13:51:19 +00:00
svc.Spec.Ports = []v1.ServicePort{{
Name: svcPortName.Port,
Port: int32(svcPort),
2018-08-15 13:51:19 +00:00
Protocol: v1.ProtocolTCP,
NodePort: int32(svcNodePort),
}}
2018-08-15 13:51:19 +00:00
svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{
IP: svcLBIP,
}}
2018-08-15 13:51:19 +00:00
svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyTypeLocal
}),
)
2018-03-27 11:40:14 +00:00
epIP := "10.180.0.1"
makeEndpointsMap(fp,
2018-08-15 13:51:19 +00:00
makeTestEndpoints(svcPortName.Namespace, svcPortName.Name, func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
2018-03-27 11:40:14 +00:00
IP: epIP,
NodeName: nil,
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: svcPortName.Port,
Port: int32(svcPort),
}},
}}
}),
)
2017-09-06 08:46:09 +00:00
fp.syncProxyRules()
2018-03-27 11:40:14 +00:00
// Expect 2 services and 1 destination
epVS := &netlinktest.ExpectedVirtualServer{
2018-08-15 13:51:19 +00:00
VSNum: 2, IP: svcLBIP, Port: uint16(svcPort), Protocol: string(v1.ProtocolTCP),
2018-03-27 11:40:14 +00:00
RS: []netlinktest.ExpectedRealServer{{
IP: epIP, Port: uint16(svcPort),
}}}
checkIPVS(t, fp, epVS)
// check ipSet rules
epIPSet := netlinktest.ExpectedIPSet{
kubeLoadBalancerSet: {{
2018-03-27 11:40:14 +00:00
IP: svcLBIP,
Port: svcPort,
2018-08-15 13:51:19 +00:00
Protocol: strings.ToLower(string(v1.ProtocolTCP)),
2018-03-27 11:40:14 +00:00
SetType: utilipset.HashIPPort,
}},
kubeLoadBalancerLocalSet: {{
2018-03-27 11:40:14 +00:00
IP: svcLBIP,
Port: svcPort,
2018-08-15 13:51:19 +00:00
Protocol: strings.ToLower(string(v1.ProtocolTCP)),
2018-03-27 11:40:14 +00:00
SetType: utilipset.HashIPPort,
}},
}
checkIPSet(t, fp, epIPSet)
// Check iptables chain and rules
epIpt := netlinktest.ExpectedIptablesChain{
string(kubeServicesChain): {{
JumpChain: string(KubeLoadBalancerChain), MatchSet: kubeLoadBalancerSet,
2018-03-27 11:40:14 +00:00
}},
2018-04-17 11:32:32 +00:00
string(KubeLoadBalancerChain): {{
JumpChain: "RETURN", MatchSet: kubeLoadBalancerLocalSet,
2018-03-27 11:40:14 +00:00
}, {
JumpChain: string(KubeMarkMasqChain), MatchSet: "",
}},
}
checkIptables(t, ipt, epIpt)
}
2018-08-15 13:51:19 +00:00
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 TestBuildServiceMapAddRemove(t *testing.T) {
ipt := iptablestest.NewFake()
ipvs := ipvstest.NewFake()
2017-12-20 07:54:07 +00:00
ipset := ipsettest.NewFake(testIPSetVersion)
fp := NewFakeProxier(ipt, ipvs, ipset, nil)
2018-08-15 13:51:19 +00:00
services := []*v1.Service{
makeTestService("somewhere-else", "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, "something", "UDP", 1234, 4321, 0)
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "somethingelse", "UDP", 1235, 5321, 0)
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "somesctp", "SCTP", 1236, 6321, 0)
}),
2018-08-15 13:51:19 +00:00
makeTestService("somewhere-else", "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, "blahblah", "UDP", 345, 678, 0)
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "moreblahblah", "TCP", 344, 677, 0)
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "sctpblah", "SCTP", 343, 676, 0)
}),
2018-08-15 13:51:19 +00:00
makeTestService("somewhere", "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.Spec.Ports = addTestPort(svc.Spec.Ports, "sctpfoo", "SCTP", 8677, 30063, 7002)
svc.Status.LoadBalancer = api.LoadBalancerStatus{
Ingress: []api.LoadBalancerIngress{
{IP: "10.1.2.4"},
},
}
}),
2018-08-15 13:51:19 +00:00
makeTestService("somewhere", "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.Spec.Ports = addTestPort(svc.Spec.Ports, "sctpbaz", "SCTP", 8679, 30065, 7004)
svc.Status.LoadBalancer = api.LoadBalancerStatus{
Ingress: []api.LoadBalancerIngress{
{IP: "10.1.2.3"},
},
}
2018-08-15 13:51:19 +00:00
svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyTypeLocal
svc.Spec.HealthCheckNodePort = 345
}),
}
for i := range services {
fp.OnServiceAdd(services[i])
}
2018-02-03 09:51:17 +00:00
result := proxy.UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
if len(fp.serviceMap) != 12 {
t.Errorf("expected service map length 12, got %v", fp.serviceMap)
}
// The only-local-loadbalancer ones get added
2018-02-03 09:51:17 +00:00
if len(result.HCServiceNodePorts) != 1 {
t.Errorf("expected 1 healthcheck port, got %v", result.HCServiceNodePorts)
} else {
nsn := makeNSN("somewhere", "only-local-load-balancer")
2018-02-03 09:51:17 +00:00
if port, found := result.HCServiceNodePorts[nsn]; !found || port != 345 {
t.Errorf("expected healthcheck port [%q]=345: got %v", nsn, result.HCServiceNodePorts)
}
}
2018-02-03 09:51:17 +00:00
if len(result.UDPStaleClusterIP) != 0 {
// Services only added, so nothing stale yet
2018-02-03 09:51:17 +00:00
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.
2018-08-15 13:51:19 +00:00
oneService := makeTestService("somewhere-else", "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, "somethingelse", "UDP", 1235, 5321, 0)
})
fp.OnServiceUpdate(services[0], oneService)
fp.OnServiceDelete(services[1])
fp.OnServiceDelete(services[2])
fp.OnServiceDelete(services[3])
2018-02-03 09:51:17 +00:00
result = proxy.UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
if len(fp.serviceMap) != 1 {
t.Errorf("expected service map length 1, got %v", fp.serviceMap)
}
2018-02-03 09:51:17 +00:00
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"}
2018-02-03 09:51:17 +00:00
if len(result.UDPStaleClusterIP) != len(expectedStaleUDPServices) {
t.Errorf("expected stale UDP services length %d, got %v", len(expectedStaleUDPServices), result.UDPStaleClusterIP.List())
}
for _, ip := range expectedStaleUDPServices {
2018-02-03 09:51:17 +00:00
if !result.UDPStaleClusterIP.Has(ip) {
t.Errorf("expected stale UDP service service %s", ip)
}
}
}
func TestBuildServiceMapServiceHeadless(t *testing.T) {
ipt := iptablestest.NewFake()
ipvs := ipvstest.NewFake()
2017-12-20 07:54:07 +00:00
ipset := ipsettest.NewFake(testIPSetVersion)
fp := NewFakeProxier(ipt, ipvs, ipset, nil)
makeServiceMap(fp,
2018-08-15 13:51:19 +00:00
makeTestService("somewhere-else", "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)
}),
2018-08-15 13:51:19 +00:00
makeTestService("somewhere-else", "headless-without-port", func(svc *v1.Service) {
svc.Spec.Type = v1.ServiceTypeClusterIP
svc.Spec.ClusterIP = v1.ClusterIPNone
2017-09-06 08:46:09 +00:00
}),
makeTestService("somewhere-else", "headless-sctp", func(svc *api.Service) {
svc.Spec.Type = api.ServiceTypeClusterIP
svc.Spec.ClusterIP = api.ClusterIPNone
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "sip", "SCTP", 1235, 0, 0)
}),
)
// Headless service should be ignored
2018-02-03 09:51:17 +00:00
result := proxy.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
2018-02-03 09:51:17 +00:00
if len(result.HCServiceNodePorts) != 0 {
t.Errorf("expected healthcheck ports length 0, got %d", len(result.HCServiceNodePorts))
}
2018-02-03 09:51:17 +00:00
if len(result.UDPStaleClusterIP) != 0 {
t.Errorf("expected stale UDP services length 0, got %d", len(result.UDPStaleClusterIP))
}
}
func TestBuildServiceMapServiceTypeExternalName(t *testing.T) {
ipt := iptablestest.NewFake()
ipvs := ipvstest.NewFake()
2017-12-20 07:54:07 +00:00
ipset := ipsettest.NewFake(testIPSetVersion)
fp := NewFakeProxier(ipt, ipvs, ipset, nil)
makeServiceMap(fp,
2018-08-15 13:51:19 +00:00
makeTestService("somewhere-else", "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)
}),
)
2018-02-03 09:51:17 +00:00
result := proxy.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
2018-02-03 09:51:17 +00:00
if len(result.HCServiceNodePorts) != 0 {
t.Errorf("expected healthcheck ports length 0, got %v", result.HCServiceNodePorts)
}
2018-02-03 09:51:17 +00:00
if len(result.UDPStaleClusterIP) != 0 {
t.Errorf("expected stale UDP services length 0, got %v", result.UDPStaleClusterIP)
}
}
func TestBuildServiceMapServiceUpdate(t *testing.T) {
ipt := iptablestest.NewFake()
ipvs := ipvstest.NewFake()
2017-12-20 07:54:07 +00:00
ipset := ipsettest.NewFake(testIPSetVersion)
fp := NewFakeProxier(ipt, ipvs, ipset, nil)
2018-08-15 13:51:19 +00:00
servicev1 := makeTestService("somewhere", "some-service", func(svc *v1.Service) {
svc.Spec.Type = v1.ServiceTypeClusterIP
svc.Spec.ClusterIP = "172.16.55.4"
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "something", "UDP", 1234, 4321, 0)
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "somethingelse", "TCP", 1235, 5321, 0)
})
2018-08-15 13:51:19 +00:00
servicev2 := makeTestService("somewhere", "some-service", 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, "something", "UDP", 1234, 4321, 7002)
svc.Spec.Ports = addTestPort(svc.Spec.Ports, "somethingelse", "TCP", 1235, 5321, 7003)
2018-08-15 13:51:19 +00:00
svc.Status.LoadBalancer = v1.LoadBalancerStatus{
Ingress: []v1.LoadBalancerIngress{
{IP: "10.1.2.3"},
},
}
2018-08-15 13:51:19 +00:00
svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyTypeLocal
svc.Spec.HealthCheckNodePort = 345
})
fp.OnServiceAdd(servicev1)
2018-02-03 09:51:17 +00:00
result := proxy.UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
if len(fp.serviceMap) != 2 {
t.Errorf("expected service map length 2, got %v", fp.serviceMap)
}
2018-02-03 09:51:17 +00:00
if len(result.HCServiceNodePorts) != 0 {
t.Errorf("expected healthcheck ports length 0, got %v", result.HCServiceNodePorts)
}
2018-02-03 09:51:17 +00:00
if len(result.UDPStaleClusterIP) != 0 {
// Services only added, so nothing stale yet
2018-02-03 09:51:17 +00:00
t.Errorf("expected stale UDP services length 0, got %d", len(result.UDPStaleClusterIP))
}
// Change service to load-balancer
fp.OnServiceUpdate(servicev1, servicev2)
2018-02-03 09:51:17 +00:00
result = proxy.UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
if len(fp.serviceMap) != 2 {
t.Errorf("expected service map length 2, got %v", fp.serviceMap)
}
2018-02-03 09:51:17 +00:00
if len(result.HCServiceNodePorts) != 1 {
t.Errorf("expected healthcheck ports length 1, got %v", result.HCServiceNodePorts)
}
2018-02-03 09:51:17 +00:00
if len(result.UDPStaleClusterIP) != 0 {
t.Errorf("expected stale UDP services length 0, got %v", result.UDPStaleClusterIP.List())
}
// No change; make sure the service map stays the same and there are
// no health-check changes
fp.OnServiceUpdate(servicev2, servicev2)
2018-02-03 09:51:17 +00:00
result = proxy.UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
if len(fp.serviceMap) != 2 {
t.Errorf("expected service map length 2, got %v", fp.serviceMap)
}
2018-02-03 09:51:17 +00:00
if len(result.HCServiceNodePorts) != 1 {
t.Errorf("expected healthcheck ports length 1, got %v", result.HCServiceNodePorts)
}
2018-02-03 09:51:17 +00:00
if len(result.UDPStaleClusterIP) != 0 {
t.Errorf("expected stale UDP services length 0, got %v", result.UDPStaleClusterIP.List())
}
// And back to ClusterIP
fp.OnServiceUpdate(servicev2, servicev1)
2018-02-03 09:51:17 +00:00
result = proxy.UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
if len(fp.serviceMap) != 2 {
t.Errorf("expected service map length 2, got %v", fp.serviceMap)
}
2018-02-03 09:51:17 +00:00
if len(result.HCServiceNodePorts) != 0 {
t.Errorf("expected healthcheck ports length 0, got %v", result.HCServiceNodePorts)
}
2018-02-03 09:51:17 +00:00
if len(result.UDPStaleClusterIP) != 0 {
// Services only added, so nothing stale yet
2018-02-03 09:51:17 +00:00
t.Errorf("expected stale UDP services length 0, got %d", len(result.UDPStaleClusterIP))
}
}
func TestSessionAffinity(t *testing.T) {
ipt := iptablestest.NewFake()
ipvs := ipvstest.NewFake()
2017-12-20 07:54:07 +00:00
ipset := ipsettest.NewFake(testIPSetVersion)
nodeIP := net.ParseIP("100.101.102.103")
fp := NewFakeProxier(ipt, ipvs, ipset, []net.IP{nodeIP})
svcIP := "10.20.30.41"
svcPort := 80
svcNodePort := 3001
svcExternalIPs := "50.60.70.81"
svcPortName := proxy.ServicePortName{
NamespacedName: makeNSN("ns1", "svc1"),
Port: "p80",
}
2018-08-15 13:51:19 +00:00
timeoutSeconds := v1.DefaultClientIPServiceAffinitySeconds
makeServiceMap(fp,
2018-08-15 13:51:19 +00:00
makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
svc.Spec.Type = "NodePort"
svc.Spec.ClusterIP = svcIP
svc.Spec.ExternalIPs = []string{svcExternalIPs}
2018-08-15 13:51:19 +00:00
svc.Spec.SessionAffinity = v1.ServiceAffinityClientIP
svc.Spec.SessionAffinityConfig = &v1.SessionAffinityConfig{
ClientIP: &v1.ClientIPConfig{
TimeoutSeconds: &timeoutSeconds,
},
}
2018-08-15 13:51:19 +00:00
svc.Spec.Ports = []v1.ServicePort{{
Name: svcPortName.Port,
Port: int32(svcPort),
2018-08-15 13:51:19 +00:00
Protocol: v1.ProtocolTCP,
NodePort: int32(svcNodePort),
}}
}),
)
makeEndpointsMap(fp)
2017-09-06 08:46:09 +00:00
fp.syncProxyRules()
// check ipvs service and destinations
services, err := ipvs.GetVirtualServers()
if err != nil {
t.Errorf("Failed to get ipvs services, err: %v", err)
}
for _, svc := range services {
2018-08-15 13:51:19 +00:00
if svc.Timeout != uint32(v1.DefaultClientIPServiceAffinitySeconds) {
t.Errorf("Unexpected mismatch ipvs service session affinity timeout: %d, expected: %d", svc.Timeout, v1.DefaultClientIPServiceAffinitySeconds)
}
}
}
func makeServicePortName(ns, name, port string) proxy.ServicePortName {
return proxy.ServicePortName{
NamespacedName: makeNSN(ns, name),
Port: port,
}
}
func Test_updateEndpointsMap(t *testing.T) {
2017-09-06 08:46:09 +00:00
var nodeName = testHostname
2018-08-15 13:51:19 +00:00
emptyEndpoint := func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{}
2017-09-06 08:46:09 +00:00
}
2018-08-15 13:51:19 +00:00
unnamedPort := func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: "1.1.1.1",
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Port: 11,
}},
}}
}
2018-08-15 13:51:19 +00:00
unnamedPortLocal := func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: "1.1.1.1",
NodeName: &nodeName,
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Port: 11,
}},
}}
}
2018-08-15 13:51:19 +00:00
namedPortLocal := func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: "1.1.1.1",
NodeName: &nodeName,
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: "p11",
Port: 11,
}},
}}
}
2018-08-15 13:51:19 +00:00
namedPort := func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: "1.1.1.1",
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: "p11",
Port: 11,
}},
}}
}
2018-08-15 13:51:19 +00:00
namedPortRenamed := func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: "1.1.1.1",
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: "p11-2",
Port: 11,
}},
}}
}
2018-08-15 13:51:19 +00:00
namedPortRenumbered := func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: "1.1.1.1",
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: "p11",
Port: 22,
}},
}}
}
2018-08-15 13:51:19 +00:00
namedPortsLocalNoLocal := func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: "1.1.1.1",
}, {
IP: "1.1.1.2",
NodeName: &nodeName,
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: "p11",
Port: 11,
}, {
Name: "p12",
Port: 12,
}},
}}
}
2018-08-15 13:51:19 +00:00
multipleSubsets := func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: "1.1.1.1",
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: "p11",
Port: 11,
}},
}, {
2018-08-15 13:51:19 +00:00
Addresses: []v1.EndpointAddress{{
IP: "1.1.1.2",
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: "p12",
Port: 12,
}},
}}
}
2018-08-15 13:51:19 +00:00
multipleSubsetsWithLocal := func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: "1.1.1.1",
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: "p11",
Port: 11,
}},
}, {
2018-08-15 13:51:19 +00:00
Addresses: []v1.EndpointAddress{{
IP: "1.1.1.2",
NodeName: &nodeName,
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: "p12",
Port: 12,
}},
}}
}
2018-08-15 13:51:19 +00:00
multipleSubsetsMultiplePortsLocal := func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: "1.1.1.1",
NodeName: &nodeName,
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: "p11",
Port: 11,
}, {
Name: "p12",
Port: 12,
}},
}, {
2018-08-15 13:51:19 +00:00
Addresses: []v1.EndpointAddress{{
IP: "1.1.1.3",
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: "p13",
Port: 13,
}},
}}
}
2018-08-15 13:51:19 +00:00
multipleSubsetsIPsPorts1 := func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: "1.1.1.1",
}, {
IP: "1.1.1.2",
NodeName: &nodeName,
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: "p11",
Port: 11,
}, {
Name: "p12",
Port: 12,
}},
}, {
2018-08-15 13:51:19 +00:00
Addresses: []v1.EndpointAddress{{
IP: "1.1.1.3",
}, {
IP: "1.1.1.4",
NodeName: &nodeName,
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: "p13",
Port: 13,
}, {
Name: "p14",
Port: 14,
}},
}}
}
2018-08-15 13:51:19 +00:00
multipleSubsetsIPsPorts2 := func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: "2.2.2.1",
}, {
IP: "2.2.2.2",
NodeName: &nodeName,
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: "p21",
Port: 21,
}, {
Name: "p22",
Port: 22,
}},
}}
}
2018-08-15 13:51:19 +00:00
complexBefore1 := func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: "1.1.1.1",
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: "p11",
Port: 11,
}},
}}
}
2018-08-15 13:51:19 +00:00
complexBefore2 := func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: "2.2.2.2",
NodeName: &nodeName,
}, {
IP: "2.2.2.22",
NodeName: &nodeName,
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: "p22",
Port: 22,
}},
}, {
2018-08-15 13:51:19 +00:00
Addresses: []v1.EndpointAddress{{
IP: "2.2.2.3",
NodeName: &nodeName,
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: "p23",
Port: 23,
}},
}}
}
2018-08-15 13:51:19 +00:00
complexBefore4 := func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: "4.4.4.4",
NodeName: &nodeName,
}, {
IP: "4.4.4.5",
NodeName: &nodeName,
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: "p44",
Port: 44,
}},
}, {
2018-08-15 13:51:19 +00:00
Addresses: []v1.EndpointAddress{{
IP: "4.4.4.6",
NodeName: &nodeName,
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: "p45",
Port: 45,
}},
}}
}
2018-08-15 13:51:19 +00:00
complexAfter1 := func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: "1.1.1.1",
}, {
IP: "1.1.1.11",
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: "p11",
Port: 11,
}},
}, {
2018-08-15 13:51:19 +00:00
Addresses: []v1.EndpointAddress{{
IP: "1.1.1.2",
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: "p12",
Port: 12,
}, {
Name: "p122",
Port: 122,
}},
}}
}
2018-08-15 13:51:19 +00:00
complexAfter3 := func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: "3.3.3.3",
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: "p33",
Port: 33,
}},
}}
}
2018-08-15 13:51:19 +00:00
complexAfter4 := func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: "4.4.4.4",
NodeName: &nodeName,
}},
2018-08-15 13:51:19 +00:00
Ports: []v1.EndpointPort{{
Name: "p44",
Port: 44,
}},
}}
}
testCases := []struct {
// previousEndpoints and currentEndpoints are used to call appropriate
// handlers OnEndpoints* (based on whether corresponding values are nil
// or non-nil) and must be of equal length.
2018-08-15 13:51:19 +00:00
previousEndpoints []*v1.Endpoints
currentEndpoints []*v1.Endpoints
oldEndpoints map[proxy.ServicePortName][]*proxy.BaseEndpointInfo
expectedResult map[proxy.ServicePortName][]*proxy.BaseEndpointInfo
2018-02-03 09:51:17 +00:00
expectedStaleEndpoints []proxy.ServiceEndpoint
2017-09-06 08:46:09 +00:00
expectedStaleServiceNames map[proxy.ServicePortName]bool
expectedHealthchecks map[types.NamespacedName]int
}{{
// Case[0]: nothing
oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{},
expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{},
2018-02-03 09:51:17 +00:00
expectedStaleEndpoints: []proxy.ServiceEndpoint{},
2017-09-06 08:46:09 +00:00
expectedStaleServiceNames: map[proxy.ServicePortName]bool{},
expectedHealthchecks: map[types.NamespacedName]int{},
}, {
// Case[1]: no change, unnamed port
2018-08-15 13:51:19 +00:00
previousEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", unnamedPort),
},
2018-08-15 13:51:19 +00:00
currentEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", unnamedPort),
},
oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", ""): {
{Endpoint: "1.1.1.1:11", IsLocal: false},
},
},
expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", ""): {
{Endpoint: "1.1.1.1:11", IsLocal: false},
},
},
2018-02-03 09:51:17 +00:00
expectedStaleEndpoints: []proxy.ServiceEndpoint{},
2017-09-06 08:46:09 +00:00
expectedStaleServiceNames: map[proxy.ServicePortName]bool{},
expectedHealthchecks: map[types.NamespacedName]int{},
}, {
// Case[2]: no change, named port, local
2018-08-15 13:51:19 +00:00
previousEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", namedPortLocal),
},
2018-08-15 13:51:19 +00:00
currentEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", namedPortLocal),
},
oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", "p11"): {
{Endpoint: "1.1.1.1:11", IsLocal: true},
},
},
expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", "p11"): {
{Endpoint: "1.1.1.1:11", IsLocal: true},
},
},
2018-02-03 09:51:17 +00:00
expectedStaleEndpoints: []proxy.ServiceEndpoint{},
2017-09-06 08:46:09 +00:00
expectedStaleServiceNames: map[proxy.ServicePortName]bool{},
expectedHealthchecks: map[types.NamespacedName]int{
makeNSN("ns1", "ep1"): 1,
},
}, {
// Case[3]: no change, multiple subsets
2018-08-15 13:51:19 +00:00
previousEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", multipleSubsets),
},
2018-08-15 13:51:19 +00:00
currentEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", multipleSubsets),
},
oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", "p11"): {
{Endpoint: "1.1.1.1:11", IsLocal: false},
},
makeServicePortName("ns1", "ep1", "p12"): {
{Endpoint: "1.1.1.2:12", IsLocal: false},
},
},
expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", "p11"): {
{Endpoint: "1.1.1.1:11", IsLocal: false},
},
makeServicePortName("ns1", "ep1", "p12"): {
{Endpoint: "1.1.1.2:12", IsLocal: false},
},
},
2018-02-03 09:51:17 +00:00
expectedStaleEndpoints: []proxy.ServiceEndpoint{},
2017-09-06 08:46:09 +00:00
expectedStaleServiceNames: map[proxy.ServicePortName]bool{},
expectedHealthchecks: map[types.NamespacedName]int{},
}, {
// Case[4]: no change, multiple subsets, multiple ports, local
2018-08-15 13:51:19 +00:00
previousEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", multipleSubsetsMultiplePortsLocal),
},
2018-08-15 13:51:19 +00:00
currentEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", multipleSubsetsMultiplePortsLocal),
},
oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", "p11"): {
{Endpoint: "1.1.1.1:11", IsLocal: true},
},
makeServicePortName("ns1", "ep1", "p12"): {
{Endpoint: "1.1.1.1:12", IsLocal: true},
},
makeServicePortName("ns1", "ep1", "p13"): {
{Endpoint: "1.1.1.3:13", IsLocal: false},
},
},
expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", "p11"): {
{Endpoint: "1.1.1.1:11", IsLocal: true},
},
makeServicePortName("ns1", "ep1", "p12"): {
{Endpoint: "1.1.1.1:12", IsLocal: true},
},
makeServicePortName("ns1", "ep1", "p13"): {
{Endpoint: "1.1.1.3:13", IsLocal: false},
},
},
2018-02-03 09:51:17 +00:00
expectedStaleEndpoints: []proxy.ServiceEndpoint{},
2017-09-06 08:46:09 +00:00
expectedStaleServiceNames: map[proxy.ServicePortName]bool{},
expectedHealthchecks: map[types.NamespacedName]int{
makeNSN("ns1", "ep1"): 1,
},
}, {
2017-09-06 08:46:09 +00:00
// Case[5]: no change, multiple endpoints, subsets, IPs, and ports
2018-08-15 13:51:19 +00:00
previousEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", multipleSubsetsIPsPorts1),
makeTestEndpoints("ns2", "ep2", multipleSubsetsIPsPorts2),
},
2018-08-15 13:51:19 +00:00
currentEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", multipleSubsetsIPsPorts1),
makeTestEndpoints("ns2", "ep2", multipleSubsetsIPsPorts2),
},
oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", "p11"): {
{Endpoint: "1.1.1.1:11", IsLocal: false},
{Endpoint: "1.1.1.2:11", IsLocal: true},
},
makeServicePortName("ns1", "ep1", "p12"): {
{Endpoint: "1.1.1.1:12", IsLocal: false},
{Endpoint: "1.1.1.2:12", IsLocal: true},
},
makeServicePortName("ns1", "ep1", "p13"): {
{Endpoint: "1.1.1.3:13", IsLocal: false},
{Endpoint: "1.1.1.4:13", IsLocal: true},
},
makeServicePortName("ns1", "ep1", "p14"): {
{Endpoint: "1.1.1.3:14", IsLocal: false},
{Endpoint: "1.1.1.4:14", IsLocal: true},
},
makeServicePortName("ns2", "ep2", "p21"): {
{Endpoint: "2.2.2.1:21", IsLocal: false},
{Endpoint: "2.2.2.2:21", IsLocal: true},
},
makeServicePortName("ns2", "ep2", "p22"): {
{Endpoint: "2.2.2.1:22", IsLocal: false},
{Endpoint: "2.2.2.2:22", IsLocal: true},
},
},
expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", "p11"): {
{Endpoint: "1.1.1.1:11", IsLocal: false},
{Endpoint: "1.1.1.2:11", IsLocal: true},
},
makeServicePortName("ns1", "ep1", "p12"): {
{Endpoint: "1.1.1.1:12", IsLocal: false},
{Endpoint: "1.1.1.2:12", IsLocal: true},
},
makeServicePortName("ns1", "ep1", "p13"): {
{Endpoint: "1.1.1.3:13", IsLocal: false},
{Endpoint: "1.1.1.4:13", IsLocal: true},
},
makeServicePortName("ns1", "ep1", "p14"): {
{Endpoint: "1.1.1.3:14", IsLocal: false},
{Endpoint: "1.1.1.4:14", IsLocal: true},
},
makeServicePortName("ns2", "ep2", "p21"): {
{Endpoint: "2.2.2.1:21", IsLocal: false},
{Endpoint: "2.2.2.2:21", IsLocal: true},
},
makeServicePortName("ns2", "ep2", "p22"): {
{Endpoint: "2.2.2.1:22", IsLocal: false},
{Endpoint: "2.2.2.2:22", IsLocal: true},
},
},
2018-02-03 09:51:17 +00:00
expectedStaleEndpoints: []proxy.ServiceEndpoint{},
2017-09-06 08:46:09 +00:00
expectedStaleServiceNames: map[proxy.ServicePortName]bool{},
expectedHealthchecks: map[types.NamespacedName]int{
makeNSN("ns1", "ep1"): 2,
makeNSN("ns2", "ep2"): 1,
},
}, {
// Case[6]: add an Endpoints
2018-08-15 13:51:19 +00:00
previousEndpoints: []*v1.Endpoints{
nil,
},
2018-08-15 13:51:19 +00:00
currentEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", unnamedPortLocal),
},
oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{},
expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", ""): {
{Endpoint: "1.1.1.1:11", IsLocal: true},
},
},
2018-02-03 09:51:17 +00:00
expectedStaleEndpoints: []proxy.ServiceEndpoint{},
2017-09-06 08:46:09 +00:00
expectedStaleServiceNames: map[proxy.ServicePortName]bool{
makeServicePortName("ns1", "ep1", ""): true,
},
expectedHealthchecks: map[types.NamespacedName]int{
makeNSN("ns1", "ep1"): 1,
},
}, {
// Case[7]: remove an Endpoints
2018-08-15 13:51:19 +00:00
previousEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", unnamedPortLocal),
},
2018-08-15 13:51:19 +00:00
currentEndpoints: []*v1.Endpoints{
nil,
},
oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", ""): {
{Endpoint: "1.1.1.1:11", IsLocal: true},
},
},
expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{},
2018-02-03 09:51:17 +00:00
expectedStaleEndpoints: []proxy.ServiceEndpoint{{
Endpoint: "1.1.1.1:11",
ServicePortName: makeServicePortName("ns1", "ep1", ""),
}},
2017-09-06 08:46:09 +00:00
expectedStaleServiceNames: map[proxy.ServicePortName]bool{},
expectedHealthchecks: map[types.NamespacedName]int{},
}, {
// Case[8]: add an IP and port
2018-08-15 13:51:19 +00:00
previousEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", namedPort),
},
2018-08-15 13:51:19 +00:00
currentEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", namedPortsLocalNoLocal),
},
oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", "p11"): {
{Endpoint: "1.1.1.1:11", IsLocal: false},
},
},
expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", "p11"): {
{Endpoint: "1.1.1.1:11", IsLocal: false},
{Endpoint: "1.1.1.2:11", IsLocal: true},
},
makeServicePortName("ns1", "ep1", "p12"): {
{Endpoint: "1.1.1.1:12", IsLocal: false},
{Endpoint: "1.1.1.2:12", IsLocal: true},
},
},
2018-02-03 09:51:17 +00:00
expectedStaleEndpoints: []proxy.ServiceEndpoint{},
2017-09-06 08:46:09 +00:00
expectedStaleServiceNames: map[proxy.ServicePortName]bool{
makeServicePortName("ns1", "ep1", "p12"): true,
},
expectedHealthchecks: map[types.NamespacedName]int{
makeNSN("ns1", "ep1"): 1,
},
}, {
// Case[9]: remove an IP and port
2018-08-15 13:51:19 +00:00
previousEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", namedPortsLocalNoLocal),
},
2018-08-15 13:51:19 +00:00
currentEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", namedPort),
},
oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", "p11"): {
{Endpoint: "1.1.1.1:11", IsLocal: false},
{Endpoint: "1.1.1.2:11", IsLocal: true},
},
makeServicePortName("ns1", "ep1", "p12"): {
{Endpoint: "1.1.1.1:12", IsLocal: false},
{Endpoint: "1.1.1.2:12", IsLocal: true},
},
},
expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", "p11"): {
{Endpoint: "1.1.1.1:11", IsLocal: false},
},
},
2018-02-03 09:51:17 +00:00
expectedStaleEndpoints: []proxy.ServiceEndpoint{{
Endpoint: "1.1.1.2:11",
ServicePortName: makeServicePortName("ns1", "ep1", "p11"),
}, {
2018-02-03 09:51:17 +00:00
Endpoint: "1.1.1.1:12",
ServicePortName: makeServicePortName("ns1", "ep1", "p12"),
}, {
2018-02-03 09:51:17 +00:00
Endpoint: "1.1.1.2:12",
ServicePortName: makeServicePortName("ns1", "ep1", "p12"),
}},
2017-09-06 08:46:09 +00:00
expectedStaleServiceNames: map[proxy.ServicePortName]bool{},
expectedHealthchecks: map[types.NamespacedName]int{},
}, {
// Case[10]: add a subset
2018-08-15 13:51:19 +00:00
previousEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", namedPort),
},
2018-08-15 13:51:19 +00:00
currentEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", multipleSubsetsWithLocal),
},
oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", "p11"): {
{Endpoint: "1.1.1.1:11", IsLocal: false},
},
},
expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", "p11"): {
{Endpoint: "1.1.1.1:11", IsLocal: false},
},
makeServicePortName("ns1", "ep1", "p12"): {
{Endpoint: "1.1.1.2:12", IsLocal: true},
},
},
2018-02-03 09:51:17 +00:00
expectedStaleEndpoints: []proxy.ServiceEndpoint{},
2017-09-06 08:46:09 +00:00
expectedStaleServiceNames: map[proxy.ServicePortName]bool{
makeServicePortName("ns1", "ep1", "p12"): true,
},
expectedHealthchecks: map[types.NamespacedName]int{
makeNSN("ns1", "ep1"): 1,
},
}, {
// Case[11]: remove a subset
2018-08-15 13:51:19 +00:00
previousEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", multipleSubsets),
},
2018-08-15 13:51:19 +00:00
currentEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", namedPort),
},
oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", "p11"): {
{Endpoint: "1.1.1.1:11", IsLocal: false},
},
makeServicePortName("ns1", "ep1", "p12"): {
{Endpoint: "1.1.1.2:12", IsLocal: false},
},
},
expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", "p11"): {
{Endpoint: "1.1.1.1:11", IsLocal: false},
},
},
2018-02-03 09:51:17 +00:00
expectedStaleEndpoints: []proxy.ServiceEndpoint{{
Endpoint: "1.1.1.2:12",
ServicePortName: makeServicePortName("ns1", "ep1", "p12"),
}},
2017-09-06 08:46:09 +00:00
expectedStaleServiceNames: map[proxy.ServicePortName]bool{},
expectedHealthchecks: map[types.NamespacedName]int{},
}, {
// Case[12]: rename a port
2018-08-15 13:51:19 +00:00
previousEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", namedPort),
},
2018-08-15 13:51:19 +00:00
currentEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", namedPortRenamed),
},
oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", "p11"): {
{Endpoint: "1.1.1.1:11", IsLocal: false},
},
},
expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", "p11-2"): {
{Endpoint: "1.1.1.1:11", IsLocal: false},
},
},
2018-02-03 09:51:17 +00:00
expectedStaleEndpoints: []proxy.ServiceEndpoint{{
Endpoint: "1.1.1.1:11",
ServicePortName: makeServicePortName("ns1", "ep1", "p11"),
}},
2017-09-06 08:46:09 +00:00
expectedStaleServiceNames: map[proxy.ServicePortName]bool{
makeServicePortName("ns1", "ep1", "p11-2"): true,
},
expectedHealthchecks: map[types.NamespacedName]int{},
}, {
// Case[13]: renumber a port
2018-08-15 13:51:19 +00:00
previousEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", namedPort),
},
2018-08-15 13:51:19 +00:00
currentEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", namedPortRenumbered),
},
oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", "p11"): {
{Endpoint: "1.1.1.1:11", IsLocal: false},
},
},
expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", "p11"): {
{Endpoint: "1.1.1.1:22", IsLocal: false},
},
},
2018-02-03 09:51:17 +00:00
expectedStaleEndpoints: []proxy.ServiceEndpoint{{
Endpoint: "1.1.1.1:11",
ServicePortName: makeServicePortName("ns1", "ep1", "p11"),
}},
2017-09-06 08:46:09 +00:00
expectedStaleServiceNames: map[proxy.ServicePortName]bool{},
expectedHealthchecks: map[types.NamespacedName]int{},
}, {
// Case[14]: complex add and remove
2018-08-15 13:51:19 +00:00
previousEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", complexBefore1),
makeTestEndpoints("ns2", "ep2", complexBefore2),
nil,
makeTestEndpoints("ns4", "ep4", complexBefore4),
},
2018-08-15 13:51:19 +00:00
currentEndpoints: []*v1.Endpoints{
makeTestEndpoints("ns1", "ep1", complexAfter1),
nil,
makeTestEndpoints("ns3", "ep3", complexAfter3),
makeTestEndpoints("ns4", "ep4", complexAfter4),
},
oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", "p11"): {
{Endpoint: "1.1.1.1:11", IsLocal: false},
},
makeServicePortName("ns2", "ep2", "p22"): {
{Endpoint: "2.2.2.2:22", IsLocal: true},
{Endpoint: "2.2.2.22:22", IsLocal: true},
},
makeServicePortName("ns2", "ep2", "p23"): {
{Endpoint: "2.2.2.3:23", IsLocal: true},
},
makeServicePortName("ns4", "ep4", "p44"): {
{Endpoint: "4.4.4.4:44", IsLocal: true},
{Endpoint: "4.4.4.5:44", IsLocal: true},
},
makeServicePortName("ns4", "ep4", "p45"): {
{Endpoint: "4.4.4.6:45", IsLocal: true},
},
},
expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
makeServicePortName("ns1", "ep1", "p11"): {
{Endpoint: "1.1.1.1:11", IsLocal: false},
{Endpoint: "1.1.1.11:11", IsLocal: false},
},
makeServicePortName("ns1", "ep1", "p12"): {
{Endpoint: "1.1.1.2:12", IsLocal: false},
},
makeServicePortName("ns1", "ep1", "p122"): {
{Endpoint: "1.1.1.2:122", IsLocal: false},
},
makeServicePortName("ns3", "ep3", "p33"): {
{Endpoint: "3.3.3.3:33", IsLocal: false},
},
makeServicePortName("ns4", "ep4", "p44"): {
{Endpoint: "4.4.4.4:44", IsLocal: true},
},
},
2018-02-03 09:51:17 +00:00
expectedStaleEndpoints: []proxy.ServiceEndpoint{{
Endpoint: "2.2.2.2:22",
ServicePortName: makeServicePortName("ns2", "ep2", "p22"),
}, {
2018-02-03 09:51:17 +00:00
Endpoint: "2.2.2.22:22",
ServicePortName: makeServicePortName("ns2", "ep2", "p22"),
}, {
2018-02-03 09:51:17 +00:00
Endpoint: "2.2.2.3:23",
ServicePortName: makeServicePortName("ns2", "ep2", "p23"),
}, {
2018-02-03 09:51:17 +00:00
Endpoint: "4.4.4.5:44",
ServicePortName: makeServicePortName("ns4", "ep4", "p44"),
}, {
2018-02-03 09:51:17 +00:00
Endpoint: "4.4.4.6:45",
ServicePortName: makeServicePortName("ns4", "ep4", "p45"),
}},
2017-09-06 08:46:09 +00:00
expectedStaleServiceNames: map[proxy.ServicePortName]bool{
makeServicePortName("ns1", "ep1", "p12"): true,
makeServicePortName("ns1", "ep1", "p122"): true,
makeServicePortName("ns3", "ep3", "p33"): true,
},
expectedHealthchecks: map[types.NamespacedName]int{
makeNSN("ns4", "ep4"): 1,
},
2017-09-06 08:46:09 +00:00
}, {
// Case[15]: change from 0 endpoint address to 1 unnamed port
2018-08-15 13:51:19 +00:00
previousEndpoints: []*v1.Endpoints{
2017-09-06 08:46:09 +00:00
makeTestEndpoints("ns1", "ep1", emptyEndpoint),
},
2018-08-15 13:51:19 +00:00
currentEndpoints: []*v1.Endpoints{
2017-09-06 08:46:09 +00:00
makeTestEndpoints("ns1", "ep1", unnamedPort),
},
oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{},
expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{
2017-09-06 08:46:09 +00:00
makeServicePortName("ns1", "ep1", ""): {
{Endpoint: "1.1.1.1:11", IsLocal: false},
2017-09-06 08:46:09 +00:00
},
},
2018-02-03 09:51:17 +00:00
expectedStaleEndpoints: []proxy.ServiceEndpoint{},
2017-09-06 08:46:09 +00:00
expectedStaleServiceNames: map[proxy.ServicePortName]bool{
makeServicePortName("ns1", "ep1", ""): true,
},
expectedHealthchecks: map[types.NamespacedName]int{},
},
}
for tci, tc := range testCases {
ipt := iptablestest.NewFake()
ipvs := ipvstest.NewFake()
2017-12-20 07:54:07 +00:00
ipset := ipsettest.NewFake(testIPSetVersion)
fp := NewFakeProxier(ipt, ipvs, ipset, nil)
fp.hostname = nodeName
2017-09-06 08:46:09 +00:00
// First check that after adding all previous versions of endpoints,
// the fp.oldEndpoints is as we expect.
for i := range tc.previousEndpoints {
if tc.previousEndpoints[i] != nil {
fp.OnEndpointsAdd(tc.previousEndpoints[i])
}
}
2018-02-03 09:51:17 +00:00
proxy.UpdateEndpointsMap(fp.endpointsMap, fp.endpointsChanges)
compareEndpointsMaps(t, tci, fp.endpointsMap, tc.oldEndpoints)
// Now let's call appropriate handlers to get to state we want to be.
if len(tc.previousEndpoints) != len(tc.currentEndpoints) {
2017-09-06 08:46:09 +00:00
t.Fatalf("[%d] different lengths of previous and current endpoints", tci)
continue
}
for i := range tc.previousEndpoints {
prev, curr := tc.previousEndpoints[i], tc.currentEndpoints[i]
switch {
case prev == nil:
fp.OnEndpointsAdd(curr)
case curr == nil:
fp.OnEndpointsDelete(prev)
default:
fp.OnEndpointsUpdate(prev, curr)
}
}
2018-02-03 09:51:17 +00:00
result := proxy.UpdateEndpointsMap(fp.endpointsMap, fp.endpointsChanges)
newMap := fp.endpointsMap
compareEndpointsMaps(t, tci, newMap, tc.expectedResult)
2018-02-03 09:51:17 +00:00
if len(result.StaleEndpoints) != len(tc.expectedStaleEndpoints) {
t.Errorf("[%d] expected %d staleEndpoints, got %d: %v", tci, len(tc.expectedStaleEndpoints), len(result.StaleEndpoints), result.StaleEndpoints)
2017-09-06 08:46:09 +00:00
}
for _, x := range tc.expectedStaleEndpoints {
2018-02-03 09:51:17 +00:00
found := false
for _, stale := range result.StaleEndpoints {
if stale == x {
found = true
break
}
}
if !found {
t.Errorf("[%d] expected staleEndpoints[%v], but didn't find it: %v", tci, x, result.StaleEndpoints)
2017-09-06 08:46:09 +00:00
}
}
2018-02-03 09:51:17 +00:00
if len(result.StaleServiceNames) != len(tc.expectedStaleServiceNames) {
t.Errorf("[%d] expected %d staleServiceNames, got %d: %v", tci, len(tc.expectedStaleServiceNames), len(result.StaleServiceNames), result.StaleServiceNames)
}
2017-09-06 08:46:09 +00:00
for svcName := range tc.expectedStaleServiceNames {
2018-02-03 09:51:17 +00:00
found := false
for _, stale := range result.StaleServiceNames {
if stale == svcName {
found = true
break
}
}
if !found {
t.Errorf("[%d] expected staleServiceNames[%v], but didn't find it: %v", tci, svcName, result.StaleServiceNames)
}
}
2018-02-03 09:51:17 +00:00
if !reflect.DeepEqual(result.HCEndpointsLocalIPSize, tc.expectedHealthchecks) {
t.Errorf("[%d] expected healthchecks %v, got %v", tci, tc.expectedHealthchecks, result.HCEndpointsLocalIPSize)
}
}
}
func compareEndpointsMaps(t *testing.T, tci int, newMap proxy.EndpointsMap, expected map[proxy.ServicePortName][]*proxy.BaseEndpointInfo) {
if len(newMap) != len(expected) {
t.Errorf("[%d] expected %d results, got %d: %v", tci, len(expected), len(newMap), newMap)
}
for x := range expected {
if len(newMap[x]) != len(expected[x]) {
2018-02-03 09:51:17 +00:00
t.Errorf("[%d] expected %d endpoints for %v, got %d", tci, len(expected[x]), x, len(newMap[x]))
} else {
for i := range expected[x] {
newEp, ok := newMap[x][i].(*proxy.BaseEndpointInfo)
2018-02-03 09:51:17 +00:00
if !ok {
t.Errorf("Failed to cast proxy.BaseEndpointInfo")
2018-02-03 09:51:17 +00:00
continue
}
2018-02-03 09:51:17 +00:00
if *newEp != *(expected[x][i]) {
t.Errorf("[%d] expected new[%v][%d] to be %v, got %v", tci, x, i, expected[x][i], newEp)
}
}
}
}
}
2017-12-29 06:30:11 +00:00
func Test_syncService(t *testing.T) {
testCases := []struct {
oldVirtualServer *utilipvs.VirtualServer
svcName string
newVirtualServer *utilipvs.VirtualServer
bindAddr bool
}{
{
// case 0, old virtual server is same as new virtual server
oldVirtualServer: &utilipvs.VirtualServer{
Address: net.ParseIP("1.2.3.4"),
2018-08-15 13:51:19 +00:00
Protocol: string(v1.ProtocolTCP),
2017-12-29 06:30:11 +00:00
Port: 80,
Scheduler: "rr",
Flags: utilipvs.FlagHashed,
},
svcName: "foo",
newVirtualServer: &utilipvs.VirtualServer{
Address: net.ParseIP("1.2.3.4"),
2018-08-15 13:51:19 +00:00
Protocol: string(v1.ProtocolTCP),
2017-12-29 06:30:11 +00:00
Port: 80,
Scheduler: "rr",
Flags: utilipvs.FlagHashed,
},
bindAddr: false,
},
{
// case 1, old virtual server is different from new virtual server
oldVirtualServer: &utilipvs.VirtualServer{
Address: net.ParseIP("1.2.3.4"),
2018-08-15 13:51:19 +00:00
Protocol: string(v1.ProtocolTCP),
2017-12-29 06:30:11 +00:00
Port: 8080,
Scheduler: "rr",
Flags: utilipvs.FlagHashed,
},
svcName: "bar",
newVirtualServer: &utilipvs.VirtualServer{
Address: net.ParseIP("1.2.3.4"),
2018-08-15 13:51:19 +00:00
Protocol: string(v1.ProtocolTCP),
2017-12-29 06:30:11 +00:00
Port: 8080,
Scheduler: "rr",
Flags: utilipvs.FlagPersistent,
},
bindAddr: false,
},
{
// case 2, old virtual server is different from new virtual server
oldVirtualServer: &utilipvs.VirtualServer{
Address: net.ParseIP("1.2.3.4"),
2018-08-15 13:51:19 +00:00
Protocol: string(v1.ProtocolTCP),
2017-12-29 06:30:11 +00:00
Port: 8080,
Scheduler: "rr",
Flags: utilipvs.FlagHashed,
},
svcName: "bar",
newVirtualServer: &utilipvs.VirtualServer{
Address: net.ParseIP("1.2.3.4"),
2018-08-15 13:51:19 +00:00
Protocol: string(v1.ProtocolTCP),
2017-12-29 06:30:11 +00:00
Port: 8080,
Scheduler: "wlc",
Flags: utilipvs.FlagHashed,
},
bindAddr: false,
},
{
// case 3, old virtual server is nil, and create new virtual server
oldVirtualServer: nil,
svcName: "baz",
newVirtualServer: &utilipvs.VirtualServer{
Address: net.ParseIP("1.2.3.4"),
2018-08-15 13:51:19 +00:00
Protocol: string(v1.ProtocolUDP),
2017-12-29 06:30:11 +00:00
Port: 53,
Scheduler: "rr",
Flags: utilipvs.FlagHashed,
},
bindAddr: true,
},
{
// case 4, SCTP, old virtual server is same as new virtual server
oldVirtualServer: &utilipvs.VirtualServer{
Address: net.ParseIP("1.2.3.4"),
Protocol: string(api.ProtocolSCTP),
Port: 80,
Scheduler: "rr",
Flags: utilipvs.FlagHashed,
},
svcName: "foo",
newVirtualServer: &utilipvs.VirtualServer{
Address: net.ParseIP("1.2.3.4"),
Protocol: string(api.ProtocolSCTP),
Port: 80,
Scheduler: "rr",
Flags: utilipvs.FlagHashed,
},
bindAddr: false,
},
{
// case 5, old virtual server is different from new virtual server
oldVirtualServer: &utilipvs.VirtualServer{
Address: net.ParseIP("1.2.3.4"),
Protocol: string(api.ProtocolSCTP),
Port: 8080,
Scheduler: "rr",
Flags: utilipvs.FlagHashed,
},
svcName: "bar",
newVirtualServer: &utilipvs.VirtualServer{
Address: net.ParseIP("1.2.3.4"),
Protocol: string(api.ProtocolSCTP),
Port: 8080,
Scheduler: "rr",
Flags: utilipvs.FlagPersistent,
},
bindAddr: false,
},
{
// case 6, old virtual server is different from new virtual server
oldVirtualServer: &utilipvs.VirtualServer{
Address: net.ParseIP("1.2.3.4"),
Protocol: string(api.ProtocolSCTP),
Port: 8080,
Scheduler: "rr",
Flags: utilipvs.FlagHashed,
},
svcName: "bar",
newVirtualServer: &utilipvs.VirtualServer{
Address: net.ParseIP("1.2.3.4"),
Protocol: string(api.ProtocolSCTP),
Port: 8080,
Scheduler: "wlc",
Flags: utilipvs.FlagHashed,
},
bindAddr: false,
},
{
// case 7, old virtual server is nil, and create new virtual server
oldVirtualServer: nil,
svcName: "baz",
newVirtualServer: &utilipvs.VirtualServer{
Address: net.ParseIP("1.2.3.4"),
Protocol: string(api.ProtocolSCTP),
Port: 53,
Scheduler: "rr",
Flags: utilipvs.FlagHashed,
},
bindAddr: true,
},
2017-12-29 06:30:11 +00:00
}
for i := range testCases {
ipt := iptablestest.NewFake()
ipvs := ipvstest.NewFake()
ipset := ipsettest.NewFake(testIPSetVersion)
proxier := NewFakeProxier(ipt, ipvs, ipset, nil)
if testCases[i].oldVirtualServer != nil {
if err := proxier.ipvs.AddVirtualServer(testCases[i].oldVirtualServer); err != nil {
t.Errorf("Case [%d], unexpected add IPVS virtual server error: %v", i, err)
}
}
if err := proxier.syncService(testCases[i].svcName, testCases[i].newVirtualServer, testCases[i].bindAddr); err != nil {
2018-02-09 06:53:53 +00:00
t.Errorf("Case [%d], unexpected sync IPVS virtual server error: %v", i, err)
2017-12-29 06:30:11 +00:00
}
// check
list, err := proxier.ipvs.GetVirtualServers()
if err != nil {
t.Errorf("Case [%d], unexpected list IPVS virtual server error: %v", i, err)
}
if len(list) != 1 {
t.Errorf("Case [%d], expect %d virtual servers, got %d", i, 1, len(list))
continue
}
if !list[0].Equal(testCases[i].newVirtualServer) {
t.Errorf("Case [%d], unexpected mismatch, expect: %#v, got: %#v", i, testCases[i].newVirtualServer, list[0])
}
}
}
2018-03-20 09:03:36 +00:00
func buildFakeProxier() (*iptablestest.FakeIPTables, *Proxier) {
2018-03-27 11:40:14 +00:00
ipt := iptablestest.NewFake()
ipvs := ipvstest.NewFake()
ipset := ipsettest.NewFake(testIPSetVersion)
return ipt, NewFakeProxier(ipt, ipvs, ipset, nil)
}
2018-03-20 09:03:36 +00:00
func hasJump(rules []iptablestest.Rule, destChain, ipSet string) bool {
for _, r := range rules {
if r[iptablestest.Jump] == destChain {
2018-03-27 11:40:14 +00:00
if ipSet == "" {
return true
}
if strings.Contains(r[iptablestest.MatchSet], ipSet) {
return true
}
}
}
return false
}
// checkIptabless to check expected iptables chain and rules
func checkIptables(t *testing.T, ipt *iptablestest.FakeIPTables, epIpt netlinktest.ExpectedIptablesChain) {
for epChain, epRules := range epIpt {
rules := ipt.GetRules(epChain)
for _, epRule := range epRules {
if !hasJump(rules, epRule.JumpChain, epRule.MatchSet) {
t.Errorf("Didn't find jump from chain %v match set %v to %v", epChain, epRule.MatchSet, epRule.JumpChain)
}
}
}
}
// checkIPSet to check expected ipset and entries
func checkIPSet(t *testing.T, fp *Proxier, ipSet netlinktest.ExpectedIPSet) {
for set, entries := range ipSet {
ents, err := fp.ipset.ListEntries(set)
if err != nil || len(ents) != len(entries) {
2018-04-17 11:32:32 +00:00
t.Errorf("Check ipset entries failed for ipset: %q, expect %d, got %d", set, len(entries), len(ents))
2018-03-27 11:40:14 +00:00
continue
}
if len(entries) == 1 {
if ents[0] != entries[0].String() {
t.Errorf("Check ipset entries failed for ipset: %q", set)
}
}
}
}
// checkIPVS to check expected ipvs service and destination
func checkIPVS(t *testing.T, fp *Proxier, vs *netlinktest.ExpectedVirtualServer) {
services, err := fp.ipvs.GetVirtualServers()
if err != nil {
t.Errorf("Failed to get ipvs services, err: %v", err)
}
if len(services) != vs.VSNum {
t.Errorf("Expect %d ipvs services, got %d", vs.VSNum, len(services))
}
for _, svc := range services {
if svc.Address.String() == vs.IP && svc.Port == vs.Port && svc.Protocol == vs.Protocol {
destinations, _ := fp.ipvs.GetRealServers(svc)
if len(destinations) != len(vs.RS) {
t.Errorf("Expected %d destinations, got %d destinations", len(vs.RS), len(destinations))
}
if len(vs.RS) == 1 {
if destinations[0].Address.String() != vs.RS[0].IP || destinations[0].Port != vs.RS[0].Port {
t.Errorf("Unexpected mismatch destinations")
2018-03-20 09:03:36 +00:00
}
}
}
}
}
func TestCleanLegacyService(t *testing.T) {
execer := exec.New()
ipt := iptablestest.NewFake()
ipvs := ipvstest.NewFake()
ipset := ipsettest.NewFake(testIPSetVersion)
excludeCIDRs := []string{"3.3.3.0/24", "4.4.4.0/24"}
proxier, err := NewProxier(
ipt,
ipvs,
ipset,
NewFakeSysctl(),
execer,
250*time.Millisecond,
100*time.Millisecond,
excludeCIDRs,
false,
0,
"10.0.0.0/24",
testHostname,
net.ParseIP("127.0.0.1"),
nil,
nil,
DefaultScheduler,
make([]string, 0),
false,
)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
// All ipvs services that were processed in the latest sync loop.
activeServices := map[string]bool{"ipvs0": true, "ipvs1": true}
// All ipvs services in the system.
currentServices := map[string]*utilipvs.VirtualServer{
// Created by kube-proxy.
"ipvs0": {
Address: net.ParseIP("1.1.1.1"),
2018-08-15 13:51:19 +00:00
Protocol: string(v1.ProtocolUDP),
Port: 53,
Scheduler: "rr",
Flags: utilipvs.FlagHashed,
},
// Created by kube-proxy.
"ipvs1": {
Address: net.ParseIP("2.2.2.2"),
2018-08-15 13:51:19 +00:00
Protocol: string(v1.ProtocolUDP),
Port: 54,
Scheduler: "rr",
Flags: utilipvs.FlagHashed,
},
// Created by an external party.
"ipvs2": {
Address: net.ParseIP("3.3.3.3"),
2018-08-15 13:51:19 +00:00
Protocol: string(v1.ProtocolUDP),
Port: 55,
Scheduler: "rr",
Flags: utilipvs.FlagHashed,
},
// Created by an external party.
"ipvs3": {
Address: net.ParseIP("4.4.4.4"),
2018-08-15 13:51:19 +00:00
Protocol: string(v1.ProtocolUDP),
Port: 56,
Scheduler: "rr",
Flags: utilipvs.FlagHashed,
},
// Created by an external party.
"ipvs4": {
Address: net.ParseIP("5.5.5.5"),
2018-08-15 13:51:19 +00:00
Protocol: string(v1.ProtocolUDP),
Port: 57,
Scheduler: "rr",
Flags: utilipvs.FlagHashed,
},
// Created by kube-proxy, but now stale.
"ipvs5": {
Address: net.ParseIP("6.6.6.6"),
2018-08-15 13:51:19 +00:00
Protocol: string(v1.ProtocolUDP),
Port: 58,
Scheduler: "rr",
Flags: utilipvs.FlagHashed,
},
}
for v := range currentServices {
proxier.ipvs.AddVirtualServer(currentServices[v])
}
proxier.cleanLegacyService(activeServices, currentServices)
// ipvs4 and ipvs5 should have been cleaned.
remainingVirtualServers, _ := proxier.ipvs.GetVirtualServers()
if len(remainingVirtualServers) != 4 {
t.Errorf("Expected number of remaining IPVS services after cleanup to be %v. Got %v", 4, len(remainingVirtualServers))
}
for _, vs := range remainingVirtualServers {
// Checking that ipvs4 and ipvs5 were removed.
if vs.Port == 57 {
t.Errorf("Expected ipvs4 to be removed after cleanup. It still remains")
}
if vs.Port == 58 {
t.Errorf("Expected ipvs5 to be removed after cleanup. It still remains")
}
}
}