func main() { config := HollowNodeConfig{} config.addFlags(pflag.CommandLine) flag.InitFlags() if !knownMorphs.Has(config.Morph) { glog.Fatalf("Unknown morph: %v. Allowed values: %v", config.Morph, knownMorphs.List()) } // create a client to communicate with API server. clientConfig, err := config.createClientConfigFromFile() if err != nil { glog.Fatalf("Failed to create a ClientConfig: %v. Exiting.", err) } cl, err := client.New(clientConfig) if err != nil { glog.Fatalf("Failed to create a Client: %v. Exiting.", err) } clientset, err := internalclientset.NewForConfig(clientConfig) if err != nil { glog.Fatalf("Failed to create a ClientSet: %v. Exiting.", err) } if config.Morph == "kubelet" { cadvisorInterface := new(cadvisortest.Fake) containerManager := cm.NewStubContainerManager() fakeDockerClient := dockertools.NewFakeDockerClient() fakeDockerClient.EnableSleep = true hollowKubelet := kubemark.NewHollowKubelet( config.NodeName, clientset, cadvisorInterface, fakeDockerClient, config.KubeletPort, config.KubeletReadOnlyPort, containerManager, maxPods, podsPerCore, ) hollowKubelet.Run() } if config.Morph == "proxy" { eventBroadcaster := record.NewBroadcaster() recorder := eventBroadcaster.NewRecorder(api.EventSource{Component: "kube-proxy", Host: config.NodeName}) iptInterface := fakeiptables.NewFake() serviceConfig := proxyconfig.NewServiceConfig() serviceConfig.RegisterHandler(&kubemark.FakeProxyHandler{}) endpointsConfig := proxyconfig.NewEndpointsConfig() endpointsConfig.RegisterHandler(&kubemark.FakeProxyHandler{}) hollowProxy := kubemark.NewHollowProxyOrDie(config.NodeName, cl, endpointsConfig, serviceConfig, iptInterface, eventBroadcaster, recorder) hollowProxy.Run() } }
func TestTCPProxy(t *testing.T) { lb := NewLoadBalancerRR() service := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: "testnamespace", Name: "echo"}, Port: "p"} lb.OnEndpointsUpdate([]api.Endpoints{ { ObjectMeta: api.ObjectMeta{Name: service.Name, Namespace: service.Namespace}, Subsets: []api.EndpointSubset{{ Addresses: []api.EndpointAddress{{IP: "127.0.0.1"}}, Ports: []api.EndpointPort{{Name: "p", Port: tcpServerPort}}, }}, }, }) fexec := makeFakeExec() p, err := createProxier(lb, net.ParseIP("0.0.0.0"), ipttest.NewFake(), fexec, net.ParseIP("127.0.0.1"), nil, time.Minute, udpIdleTimeoutForTest, NewProxySocket) if err != nil { t.Fatal(err) } waitForNumProxyLoops(t, p, 0) serviceRef := api.ObjectReference{Name: service.Name, Namespace: service.Namespace, Kind: "Service", APIVersion: "v1"} svcInfo, err := p.addServiceOnPort(service, serviceRef, "TCP", 0, time.Second) if err != nil { t.Fatalf("error adding new service: %#v", err) } testEchoTCP(t, "127.0.0.1", svcInfo.proxyPort) waitForNumProxyLoops(t, p, 1) }
func TestUDPProxy(t *testing.T) { lb := NewLoadBalancerRR() service := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: "testnamespace", Name: "echo"}, Port: "p"} lb.OnEndpointsUpdate([]api.Endpoints{ { ObjectMeta: api.ObjectMeta{Name: service.Name, Namespace: service.Namespace}, Subsets: []api.EndpointSubset{{ Addresses: []api.EndpointAddress{{IP: "127.0.0.1"}}, Ports: []api.EndpointPort{{Name: "p", Port: udpServerPort}}, }}, }, }) p, err := createProxier(lb, net.ParseIP("0.0.0.0"), ipttest.NewFake(), net.ParseIP("127.0.0.1"), nil, time.Minute, time.Second, udpIdleTimeoutForTest) if err != nil { t.Fatal(err) } waitForNumProxyLoops(t, p, 0) svcInfo, err := p.addServiceOnPort(service, "UDP", 0, time.Second) if err != nil { t.Fatalf("error adding new service: %#v", err) } testEchoUDP(t, "127.0.0.1", svcInfo.proxyPort) waitForNumProxyLoops(t, p, 1) }
func TestClusterIPEndpointsJump(t *testing.T) { ipt := iptablestest.NewFake() fp := NewFakeProxier(ipt) svcName := "svc1" svcIP := net.IPv4(10, 20, 30, 41) svc := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: "ns1", Name: svcName}, Port: "80"} fp.serviceMap[svc] = newFakeServiceInfo(svc, svcIP, 80, api.ProtocolTCP, true) ep := "10.180.0.1:80" fp.endpointsMap[svc] = []*endpointsInfo{{ep, false}} fp.syncProxyRules() svcChain := string(servicePortChainName(svc, strings.ToLower(string(api.ProtocolTCP)))) epChain := string(servicePortEndpointChainName(svc, strings.ToLower(string(api.ProtocolTCP)), ep)) kubeSvcRules := ipt.GetRules(string(kubeServicesChain)) if !hasJump(kubeSvcRules, svcChain, svcIP.String(), "80") { errorf(fmt.Sprintf("Failed to find jump from KUBE-SERVICES to %v chain", svcChain), kubeSvcRules, t) } svcRules := ipt.GetRules(svcChain) if !hasJump(svcRules, epChain, "", "") { errorf(fmt.Sprintf("Failed to jump to ep chain %v", epChain), svcRules, t) } epRules := ipt.GetRules(epChain) if !hasDNAT(epRules, ep) { errorf(fmt.Sprintf("Endpoint chain %v lacks DNAT to %v", epChain, ep), epRules, t) } }
func TestLoadBalancer(t *testing.T) { ipt := iptablestest.NewFake() fp := NewFakeProxier(ipt) svcName := "svc1" svcIP := net.IPv4(10, 20, 30, 41) svc := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: "ns1", Name: svcName}, Port: "80"} svcInfo := newFakeServiceInfo(svc, svcIP, 80, api.ProtocolTCP, false) fp.serviceMap[svc] = typeLoadBalancer(svcInfo) ep1 := "10.180.0.1:80" fp.endpointsMap[svc] = []*endpointsInfo{{ep1, false}} fp.syncProxyRules() proto := strings.ToLower(string(api.ProtocolTCP)) fwChain := string(serviceFirewallChainName(svc, proto)) svcChain := string(servicePortChainName(svc, strings.ToLower(string(api.ProtocolTCP)))) //lbChain := string(serviceLBChainName(svc, proto)) kubeSvcRules := ipt.GetRules(string(kubeServicesChain)) if !hasJump(kubeSvcRules, fwChain, svcInfo.loadBalancerStatus.Ingress[0].IP, "80") { errorf(fmt.Sprintf("Failed to find jump to firewall chain %v", fwChain), kubeSvcRules, t) } fwRules := ipt.GetRules(fwChain) if !hasJump(fwRules, svcChain, "", "") || !hasJump(fwRules, string(KubeMarkMasqChain), "", "") { errorf(fmt.Sprintf("Failed to find jump from firewall chain %v to svc chain %v", fwChain, svcChain), fwRules, t) } }
func TestUDPProxyTimeout(t *testing.T) { lb := NewLoadBalancerRR() service := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: "testnamespace", Name: "echo"}, Port: "p"} lb.OnEndpointsUpdate([]api.Endpoints{ { ObjectMeta: api.ObjectMeta{Name: service.Name, Namespace: service.Namespace}, Subsets: []api.EndpointSubset{{ Addresses: []api.EndpointAddress{{IP: "127.0.0.1"}}, Ports: []api.EndpointPort{{Name: "p", Port: udpServerPort}}, }}, }, }) p, err := createProxier(lb, net.ParseIP("0.0.0.0"), ipttest.NewFake(), net.ParseIP("127.0.0.1"), nil, time.Minute, time.Second, udpIdleTimeoutForTest) if err != nil { t.Fatal(err) } waitForNumProxyLoops(t, p, 0) svcInfo, err := p.addServiceOnPort(service, "UDP", 0, time.Second) if err != nil { t.Fatalf("error adding new service: %#v", err) } waitForNumProxyLoops(t, p, 1) testEchoUDP(t, "127.0.0.1", svcInfo.proxyPort) // When connecting to a UDP service endpoint, there should be a Conn for proxy. waitForNumProxyClients(t, svcInfo, 1, time.Second) // If conn has no activity for serviceInfo.timeout since last Read/Write, it should be closed because of timeout. waitForNumProxyClients(t, svcInfo, 0, 2*time.Second) }
// TestTeardownBeforeSetUp tests that a `TearDown` call does call // `shaper.Reset` func TestTeardownCallsShaper(t *testing.T) { fexec := &exec.FakeExec{ CommandScript: []exec.FakeCommandAction{}, LookPathFunc: func(file string) (string, error) { return fmt.Sprintf("/fake-bin/%s", file), nil }, } fhost := nettest.NewFakeHost(nil) fshaper := &bandwidth.FakeShaper{} mockcni := &mock_cni.MockCNI{} kubenet := newFakeKubenetPlugin(map[kubecontainer.ContainerID]string{}, fexec, fhost) kubenet.cniConfig = mockcni kubenet.iptables = ipttest.NewFake() kubenet.bandwidthShaper = fshaper kubenet.hostportHandler = hostporttest.NewFakeHostportHandler() mockcni.On("DelNetwork", mock.AnythingOfType("*libcni.NetworkConfig"), mock.AnythingOfType("*libcni.RuntimeConf")).Return(nil) details := make(map[string]interface{}) details[network.NET_PLUGIN_EVENT_POD_CIDR_CHANGE_DETAIL_CIDR] = "10.0.0.1/24" kubenet.Event(network.NET_PLUGIN_EVENT_POD_CIDR_CHANGE, details) existingContainerID := kubecontainer.BuildContainerID("docker", "123") kubenet.podIPs[existingContainerID] = "10.0.0.1" if err := kubenet.TearDownPod("namespace", "name", existingContainerID); err != nil { t.Fatalf("Unexpected error in TearDownPod: %v", err) } assert.Equal(t, []string{"10.0.0.1/32"}, fshaper.ResetCIDRs, "shaper.Reset should have been called") mockcni.AssertExpectations(t) }
func TestOnlyLocalNodePortsNoClusterCIDR(t *testing.T) { ipt := iptablestest.NewFake() fp := NewFakeProxier(ipt) // set cluster CIDR to empty before test fp.clusterCIDR = "" onlyLocalNodePorts(t, fp, ipt) }
// TestInvocationWithoutRuntime invokes the plugin without a runtime. // This is how kubenet is invoked from the cri. func TestTearDownWithoutRuntime(t *testing.T) { fhost := nettest.NewFakeHost(nil) fhost.Legacy = false fhost.Runtime = nil mockcni := &mock_cni.MockCNI{} fexec := &exec.FakeExec{ CommandScript: []exec.FakeCommandAction{}, LookPathFunc: func(file string) (string, error) { return fmt.Sprintf("/fake-bin/%s", file), nil }, } kubenet := newFakeKubenetPlugin(map[kubecontainer.ContainerID]string{}, fexec, fhost) kubenet.cniConfig = mockcni kubenet.iptables = ipttest.NewFake() details := make(map[string]interface{}) details[network.NET_PLUGIN_EVENT_POD_CIDR_CHANGE_DETAIL_CIDR] = "10.0.0.1/24" kubenet.Event(network.NET_PLUGIN_EVENT_POD_CIDR_CHANGE, details) existingContainerID := kubecontainer.BuildContainerID("docker", "123") kubenet.podIPs[existingContainerID] = "10.0.0.1" mockcni.On("DelNetwork", mock.AnythingOfType("*libcni.NetworkConfig"), mock.AnythingOfType("*libcni.RuntimeConf")).Return(nil) if err := kubenet.TearDownPod("namespace", "name", existingContainerID); err != nil { t.Fatalf("Unexpected error in TearDownPod: %v", err) } // Assert that the CNI DelNetwork made it through and we didn't crash // without a runtime. mockcni.AssertExpectations(t) }
func main() { runtime.GOMAXPROCS(runtime.NumCPU()) config := HollowNodeConfig{} config.addFlags(pflag.CommandLine) util.InitFlags() if !knownMorphs.Has(config.Morph) { glog.Fatalf("Unknown morph: %v. Allowed values: %v", config.Morph, knownMorphs.List()) } // create a client to communicate with API server. cl, err := createClientFromFile(config.KubeconfigPath) clientset := clientset.FromUnversionedClient(cl) if err != nil { glog.Fatal("Failed to create a Client. Exiting.") } if config.Morph == "kubelet" { cadvisorInterface := new(cadvisortest.Fake) containerManager := cm.NewStubContainerManager() fakeDockerClient := dockertools.NewFakeDockerClient() fakeDockerClient.VersionInfo = docker.Env{"Version=1.1.3", "ApiVersion=1.18"} fakeDockerClient.EnableSleep = true hollowKubelet := kubemark.NewHollowKubelet( config.NodeName, clientset, cadvisorInterface, fakeDockerClient, config.KubeletPort, config.KubeletReadOnlyPort, containerManager, maxPods, ) hollowKubelet.Run() } if config.Morph == "proxy" { eventBroadcaster := record.NewBroadcaster() recorder := eventBroadcaster.NewRecorder(api.EventSource{Component: "kube-proxy", Host: config.NodeName}) iptInterface := fakeiptables.NewFake() serviceConfig := proxyconfig.NewServiceConfig() serviceConfig.RegisterHandler(&kubemark.FakeProxyHandler{}) endpointsConfig := proxyconfig.NewEndpointsConfig() endpointsConfig.RegisterHandler(&kubemark.FakeProxyHandler{}) hollowProxy := kubemark.NewHollowProxyOrDie(config.NodeName, cl, endpointsConfig, serviceConfig, iptInterface, eventBroadcaster, recorder) hollowProxy.Run() } }
func TestProxyUpdatePublicIPs(t *testing.T) { lb := NewLoadBalancerRR() service := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: "testnamespace", Name: "echo"}, Port: "p"} lb.OnEndpointsUpdate([]api.Endpoints{ { ObjectMeta: api.ObjectMeta{Name: service.Name, Namespace: service.Namespace}, Subsets: []api.EndpointSubset{{ Addresses: []api.EndpointAddress{{IP: "127.0.0.1"}}, Ports: []api.EndpointPort{{Name: "p", Port: tcpServerPort}}, }}, }, }) fexec := makeFakeExec() p, err := createProxier(lb, net.ParseIP("0.0.0.0"), ipttest.NewFake(), fexec, net.ParseIP("127.0.0.1"), nil, time.Minute, udpIdleTimeoutForTest, NewProxySocket) if err != nil { t.Fatal(err) } waitForNumProxyLoops(t, p, 0) serviceRef := api.ObjectReference{Name: service.Name, Namespace: service.Namespace, Kind: "Service", APIVersion: "v1"} svcInfo, err := p.addServiceOnPort(service, serviceRef, "TCP", 0, time.Second) if err != nil { t.Fatalf("error adding new service: %#v", err) } testEchoTCP(t, "127.0.0.1", svcInfo.proxyPort) waitForNumProxyLoops(t, p, 1) p.OnServiceUpdate([]api.Service{{ ObjectMeta: api.ObjectMeta{Name: service.Name, Namespace: service.Namespace}, Spec: api.ServiceSpec{ Ports: []api.ServicePort{{ Name: "p", Port: int32(svcInfo.portal.port), Protocol: "TCP", }}, ClusterIP: svcInfo.portal.ip.String(), ExternalIPs: []string{"4.3.2.1"}, }, }}) // Wait for the socket to actually get free. if err = waitForClosedPortTCP(p, svcInfo.proxyPort); err != nil { t.Fatalf(err.Error()) } svcInfo, exists := p.getServiceInfo(service) if !exists { t.Fatalf("can't find serviceInfo") } testEchoTCP(t, "127.0.0.1", svcInfo.proxyPort) // This is a bit async, but this should be sufficient. time.Sleep(500 * time.Millisecond) waitForNumProxyLoops(t, p, 1) }
func TestUDPProxyUpdateDeleteUpdate(t *testing.T) { lb := NewLoadBalancerRR() service := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: "testnamespace", Name: "echo"}, Port: "p"} lb.OnEndpointsUpdate([]api.Endpoints{ { ObjectMeta: api.ObjectMeta{Name: service.Name, Namespace: service.Namespace}, Subsets: []api.EndpointSubset{{ Addresses: []api.EndpointAddress{{IP: "127.0.0.1"}}, Ports: []api.EndpointPort{{Name: "p", Port: udpServerPort}}, }}, }, }) fexec := makeFakeExec() p, err := createProxier(lb, net.ParseIP("0.0.0.0"), ipttest.NewFake(), fexec, net.ParseIP("127.0.0.1"), nil, time.Minute, udpIdleTimeoutForTest, NewProxySocket) if err != nil { t.Fatal(err) } waitForNumProxyLoops(t, p, 0) serviceRef := api.ObjectReference{Name: service.Name, Namespace: service.Namespace, Kind: "Service", APIVersion: "v1"} svcInfo, err := p.addServiceOnPort(service, serviceRef, "UDP", 0, time.Second) if err != nil { t.Fatalf("error adding new service: %#v", err) } conn, err := net.Dial("udp", joinHostPort("", svcInfo.proxyPort)) if err != nil { t.Fatalf("error connecting to proxy: %v", err) } conn.Close() waitForNumProxyLoops(t, p, 1) p.OnServiceUpdate([]api.Service{}) if err = waitForClosedPortUDP(p, svcInfo.proxyPort); err != nil { t.Fatalf(err.Error()) } waitForNumProxyLoops(t, p, 0) p.OnServiceUpdate([]api.Service{{ ObjectMeta: api.ObjectMeta{Name: service.Name, Namespace: service.Namespace}, Spec: api.ServiceSpec{ClusterIP: "1.2.3.4", Ports: []api.ServicePort{{ Name: "p", Port: int32(svcInfo.proxyPort), Protocol: "UDP", }}}, }}) svcInfo, exists := p.getServiceInfo(service) if !exists { t.Fatalf("can't find serviceInfo") } testEchoUDP(t, "127.0.0.1", svcInfo.proxyPort) waitForNumProxyLoops(t, p, 1) }
func TestTCPProxyUpdateDeleteUpdate(t *testing.T) { lb := NewLoadBalancerRR() service := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: "testnamespace", Name: "echo"}, Port: "p"} endpoint := api.Endpoints{ ObjectMeta: api.ObjectMeta{Name: service.Name, Namespace: service.Namespace}, Subsets: []api.EndpointSubset{{ Addresses: []api.EndpointAddress{{IP: "127.0.0.1"}}, Ports: []api.EndpointPort{{Name: "p", Port: tcpServerPort}}, }}, } lb.OnEndpointsUpdate([]api.Endpoints{endpoint}) p, err := createProxier(lb, net.ParseIP("0.0.0.0"), ipttest.NewFake(), net.ParseIP("127.0.0.1"), nil, time.Minute, time.Second, udpIdleTimeoutForTest) if err != nil { t.Fatal(err) } waitForNumProxyLoops(t, p, 0) svcInfo, err := p.addServiceOnPort(service, "TCP", 0, time.Second) if err != nil { t.Fatalf("error adding new service: %#v", err) } conn, err := net.Dial("tcp", joinHostPort("", svcInfo.proxyPort)) if err != nil { t.Fatalf("error connecting to proxy: %v", err) } conn.Close() waitForNumProxyLoops(t, p, 1) p.OnServiceUpdate([]api.Service{}) if err := waitForClosedPortTCP(p, svcInfo.proxyPort); err != nil { t.Fatalf(err.Error()) } waitForNumProxyLoops(t, p, 0) // need to add endpoint here because it got clean up during service delete lb.OnEndpointsUpdate([]api.Endpoints{endpoint}) p.OnServiceUpdate([]api.Service{{ ObjectMeta: api.ObjectMeta{Name: service.Name, Namespace: service.Namespace}, Spec: api.ServiceSpec{ClusterIP: "1.2.3.4", Ports: []api.ServicePort{{ Name: "p", Port: int32(svcInfo.proxyPort), Protocol: "TCP", }}}, }}) svcInfo, exists := p.getServiceInfo(service) if !exists { t.Fatalf("can't find serviceInfo for %s", service) } testEchoTCP(t, "127.0.0.1", svcInfo.proxyPort) waitForNumProxyLoops(t, p, 1) }
func TestMultiPortOnServiceUpdate(t *testing.T) { lb := NewLoadBalancerRR() serviceP := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: "testnamespace", Name: "echo"}, Port: "p"} serviceQ := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: "testnamespace", Name: "echo"}, Port: "q"} serviceX := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: "testnamespace", Name: "echo"}, Port: "x"} fexec := makeFakeExec() p, err := createProxier(lb, net.ParseIP("0.0.0.0"), ipttest.NewFake(), fexec, net.ParseIP("127.0.0.1"), nil, time.Minute, udpIdleTimeoutForTest, NewProxySocket) if err != nil { t.Fatal(err) } waitForNumProxyLoops(t, p, 0) p.OnServiceUpdate([]api.Service{{ ObjectMeta: api.ObjectMeta{Name: serviceP.Name, Namespace: serviceP.Namespace}, Spec: api.ServiceSpec{ClusterIP: "1.2.3.4", Ports: []api.ServicePort{{ Name: "p", Port: 80, Protocol: "TCP", }, { Name: "q", Port: 81, Protocol: "UDP", }}}, }}) waitForNumProxyLoops(t, p, 2) svcInfo, exists := p.getServiceInfo(serviceP) if !exists { t.Fatalf("can't find serviceInfo for %s", serviceP) } if svcInfo.portal.ip.String() != "1.2.3.4" || svcInfo.portal.port != 80 || svcInfo.protocol != "TCP" { t.Errorf("unexpected serviceInfo for %s: %#v", serviceP, svcInfo) } svcInfo, exists = p.getServiceInfo(serviceQ) if !exists { t.Fatalf("can't find serviceInfo for %s", serviceQ) } if svcInfo.portal.ip.String() != "1.2.3.4" || svcInfo.portal.port != 81 || svcInfo.protocol != "UDP" { t.Errorf("unexpected serviceInfo for %s: %#v", serviceQ, svcInfo) } svcInfo, exists = p.getServiceInfo(serviceX) if exists { t.Fatalf("found unwanted serviceInfo for %s: %#v", serviceX, svcInfo) } }
func TestTCPProxyUpdatePort(t *testing.T) { lb := NewLoadBalancerRR(nil, false) service := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: "testnamespace", Name: "echo"}, Port: "p"} lb.OnEndpointsUpdate([]api.Endpoints{ { ObjectMeta: api.ObjectMeta{Name: service.Name, Namespace: service.Namespace}, Subsets: []api.EndpointSubset{{ Addresses: []api.EndpointAddress{{IP: "127.0.0.1"}}, Ports: []api.EndpointPort{{Name: "p", Port: tcpServerPort}}, }}, }, }) p, err := createProxier(lb, net.ParseIP("0.0.0.0"), ipttest.NewFake(), net.ParseIP("127.0.0.1"), nil, time.Minute, udpIdleTimeoutForTest, nil, false) if err != nil { t.Fatal(err) } waitForNumProxyLoops(t, p, 0) svcInfo, err := p.addServiceOnPort(service, "TCP", 0, time.Second) if err != nil { t.Fatalf("error adding new service: %#v", err) } testEchoTCP(t, "127.0.0.1", svcInfo.proxyPort) waitForNumProxyLoops(t, p, 1) p.OnServiceUpdate([]api.Service{{ ObjectMeta: api.ObjectMeta{Name: service.Name, Namespace: service.Namespace}, Spec: api.ServiceSpec{ClusterIP: "1.2.3.4", Ports: []api.ServicePort{{ Name: "p", Port: 99, Protocol: "TCP", }}}, }}) // Wait for the socket to actually get free. if err := waitForClosedPortTCP(p, svcInfo.proxyPort); err != nil { t.Fatalf(err.Error()) } svcInfo, exists := p.getServiceInfo(service) if !exists { t.Fatalf("can't find serviceInfo") } testEchoTCP(t, "127.0.0.1", svcInfo.proxyPort) // This is a bit async, but this should be sufficient. time.Sleep(500 * time.Millisecond) waitForNumProxyLoops(t, p, 1) }
func TestTCPProxyStop(t *testing.T) { lb := NewLoadBalancerRR() service := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: "testnamespace", Name: "echo"}, Port: "p"} lb.OnEndpointsUpdate([]api.Endpoints{ { ObjectMeta: api.ObjectMeta{Namespace: service.Namespace, Name: service.Name}, Subsets: []api.EndpointSubset{{ Addresses: []api.EndpointAddress{{IP: "127.0.0.1"}}, Ports: []api.EndpointPort{{Name: "p", Port: tcpServerPort}}, }}, }, }) fexec := makeFakeExec() p, err := createProxier(lb, net.ParseIP("0.0.0.0"), ipttest.NewFake(), fexec, net.ParseIP("127.0.0.1"), nil, time.Minute, udpIdleTimeoutForTest, NewProxySocket) if err != nil { t.Fatal(err) } waitForNumProxyLoops(t, p, 0) serviceRef := api.ObjectReference{Name: service.Name, Namespace: service.Namespace, Kind: "Service", APIVersion: "v1"} svcInfo, err := p.addServiceOnPort(service, serviceRef, "TCP", 0, time.Second) if err != nil { t.Fatalf("error adding new service: %#v", err) } if !svcInfo.IsAlive() { t.Fatalf("wrong value for IsAlive(): expected true") } conn, err := net.Dial("tcp", joinHostPort("", svcInfo.proxyPort)) if err != nil { t.Fatalf("error connecting to proxy: %v", err) } conn.Close() waitForNumProxyLoops(t, p, 1) stopProxyByName(p, service) if svcInfo.IsAlive() { t.Fatalf("wrong value for IsAlive(): expected false") } // Wait for the port to really close. if err = waitForClosedPortTCP(p, svcInfo.proxyPort); err != nil { t.Fatalf(err.Error()) } waitForNumProxyLoops(t, p, 0) }
func TestOnlyLocalLoadBalancing(t *testing.T) { ipt := iptablestest.NewFake() fp := NewFakeProxier(ipt) svcName := "svc1" svcIP := net.IPv4(10, 20, 30, 41) svc := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: "ns1", Name: svcName}, Port: "80"} svcInfo := newFakeServiceInfo(svc, svcIP, 80, api.ProtocolTCP, true) fp.serviceMap[svc] = typeLoadBalancer(svcInfo) nonLocalEp := "10.180.0.1:80" localEp := "10.180.2.1:80" fp.endpointsMap[svc] = []*endpointsInfo{{nonLocalEp, false}, {localEp, true}} fp.syncProxyRules() proto := strings.ToLower(string(api.ProtocolTCP)) fwChain := string(serviceFirewallChainName(svc, proto)) lbChain := string(serviceLBChainName(svc, proto)) nonLocalEpChain := string(servicePortEndpointChainName(svc, strings.ToLower(string(api.ProtocolTCP)), nonLocalEp)) localEpChain := string(servicePortEndpointChainName(svc, strings.ToLower(string(api.ProtocolTCP)), localEp)) kubeSvcRules := ipt.GetRules(string(kubeServicesChain)) if !hasJump(kubeSvcRules, fwChain, svcInfo.loadBalancerStatus.Ingress[0].IP, "") { errorf(fmt.Sprintf("Failed to find jump to firewall chain %v", fwChain), kubeSvcRules, t) } fwRules := ipt.GetRules(fwChain) if !hasJump(fwRules, lbChain, "", "") { errorf(fmt.Sprintf("Failed to find jump from firewall chain %v to svc chain %v", fwChain, lbChain), fwRules, t) } if hasJump(fwRules, string(KubeMarkMasqChain), "", "") { errorf(fmt.Sprintf("Found jump from fw chain %v to MASQUERADE", fwChain), fwRules, t) } lbRules := ipt.GetRules(lbChain) if hasJump(lbRules, nonLocalEpChain, "", "") { errorf(fmt.Sprintf("Found jump from lb chain %v to non-local ep %v", lbChain, nonLocalEp), lbRules, t) } if !hasJump(lbRules, localEpChain, "", "") { errorf(fmt.Sprintf("Didn't find jump from lb chain %v to local ep %v", lbChain, nonLocalEp), lbRules, t) } }
func TestClusterIPReject(t *testing.T) { ipt := iptablestest.NewFake() fp := NewFakeProxier(ipt) svcName := "svc1" svcIP := net.IPv4(10, 20, 30, 41) svc := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: "ns1", Name: svcName}, Port: "80"} fp.serviceMap[svc] = newFakeServiceInfo(svc, svcIP, 80, api.ProtocolTCP, false) fp.syncProxyRules() svcChain := string(servicePortChainName(svc, strings.ToLower(string(api.ProtocolTCP)))) svcRules := ipt.GetRules(svcChain) if len(svcRules) != 0 { errorf(fmt.Sprintf("Unexpected rule for chain %v service %v without endpoints", svcChain, svcName), svcRules, t) } kubeSvcRules := ipt.GetRules(string(kubeServicesChain)) if !hasJump(kubeSvcRules, iptablestest.Reject, svcIP.String(), "80") { errorf(fmt.Sprintf("Failed to find a %v rule for service %v with no endpoints", iptablestest.Reject, svcName), kubeSvcRules, t) } }
// TestInit tests that a `Init` call with an MTU sets the MTU func TestInit_MTU(t *testing.T) { var fakeCmds []exec.FakeCommandAction { // modprobe br-netfilter fCmd := exec.FakeCmd{ CombinedOutputScript: []exec.FakeCombinedOutputAction{ func() ([]byte, error) { return make([]byte, 0), nil }, }, } fakeCmds = append(fakeCmds, func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fCmd, cmd, args...) }) } fexec := &exec.FakeExec{ CommandScript: fakeCmds, LookPathFunc: func(file string) (string, error) { return fmt.Sprintf("/fake-bin/%s", file), nil }, } fhost := nettest.NewFakeHost(nil) kubenet := newFakeKubenetPlugin(map[kubecontainer.ContainerID]string{}, fexec, fhost) kubenet.iptables = ipttest.NewFake() sysctl := sysctltest.NewFake() sysctl.Settings["net/bridge/bridge-nf-call-iptables"] = 0 kubenet.sysctl = sysctl if err := kubenet.Init(nettest.NewFakeHost(nil), componentconfig.HairpinNone, "10.0.0.0/8", 1234); err != nil { t.Fatalf("Unexpected error in Init: %v", err) } assert.Equal(t, 1234, kubenet.mtu, "kubenet.mtu should have been set") assert.Equal(t, 1, sysctl.Settings["net/bridge/bridge-nf-call-iptables"], "net/bridge/bridge-nf-call-iptables sysctl should have been set") }
func TestUDPProxyStop(t *testing.T) { lb := NewLoadBalancerRR() service := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: "testnamespace", Name: "echo"}, Port: "p"} lb.OnEndpointsUpdate([]api.Endpoints{ { ObjectMeta: api.ObjectMeta{Namespace: service.Namespace, Name: service.Name}, Subsets: []api.EndpointSubset{{ Addresses: []api.EndpointAddress{{IP: "127.0.0.1"}}, Ports: []api.EndpointPort{{Name: "p", Port: udpServerPort}}, }}, }, }) p, err := createProxier(lb, net.ParseIP("0.0.0.0"), ipttest.NewFake(), net.ParseIP("127.0.0.1"), nil, time.Minute, time.Second, udpIdleTimeoutForTest) if err != nil { t.Fatal(err) } waitForNumProxyLoops(t, p, 0) svcInfo, err := p.addServiceOnPort(service, "UDP", 0, time.Second) if err != nil { t.Fatalf("error adding new service: %#v", err) } conn, err := net.Dial("udp", joinHostPort("", svcInfo.proxyPort)) if err != nil { t.Fatalf("error connecting to proxy: %v", err) } conn.Close() waitForNumProxyLoops(t, p, 1) stopProxyByName(p, service) // Wait for the port to really close. if err := waitForClosedPortUDP(p, svcInfo.proxyPort); err != nil { t.Fatalf(err.Error()) } waitForNumProxyLoops(t, p, 0) }
func TestOnlyLocalNodePorts(t *testing.T) { ipt := iptablestest.NewFake() fp := NewFakeProxier(ipt) svcName := "svc1" svcIP := net.IPv4(10, 20, 30, 41) svc := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: "ns1", Name: svcName}, Port: "80"} svcInfo := newFakeServiceInfo(svc, svcIP, api.ProtocolTCP, true) svcInfo.nodePort = 3001 fp.serviceMap[svc] = svcInfo nonLocalEp := "10.180.0.1:80" localEp := "10.180.2.1:80" fp.endpointsMap[svc] = []*endpointsInfo{{nonLocalEp, false}, {localEp, true}} fp.syncProxyRules() proto := strings.ToLower(string(api.ProtocolTCP)) lbChain := string(serviceLBChainName(svc, proto)) nonLocalEpChain := string(servicePortEndpointChainName(svc, strings.ToLower(string(api.ProtocolTCP)), nonLocalEp)) localEpChain := string(servicePortEndpointChainName(svc, strings.ToLower(string(api.ProtocolTCP)), localEp)) kubeNodePortRules := ipt.GetRules(string(kubeNodePortsChain)) if !hasJump(kubeNodePortRules, lbChain, "", fmt.Sprintf("%v", svcInfo.nodePort)) { errorf(fmt.Sprintf("Failed to find jump to lb chain %v", lbChain), kubeNodePortRules, t) } lbRules := ipt.GetRules(lbChain) if hasJump(lbRules, nonLocalEpChain, "", "") { errorf(fmt.Sprintf("Found jump from lb chain %v to non-local ep %v", lbChain, nonLocalEp), lbRules, t) } if !hasJump(lbRules, localEpChain, "", "") { errorf(fmt.Sprintf("Didn't find jump from lb chain %v to local ep %v", lbChain, nonLocalEp), lbRules, t) } }
func TestNodePort(t *testing.T) { ipt := iptablestest.NewFake() fp := NewFakeProxier(ipt) svcName := "svc1" svcIP := net.IPv4(10, 20, 30, 41) svc := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: "ns1", Name: svcName}, Port: "80"} svcInfo := newFakeServiceInfo(svc, svcIP, 80, api.ProtocolTCP, false) svcInfo.nodePort = 3001 fp.serviceMap[svc] = svcInfo ep1 := "10.180.0.1:80" fp.endpointsMap[svc] = []*endpointsInfo{{ep1, false}} fp.syncProxyRules() proto := strings.ToLower(string(api.ProtocolTCP)) svcChain := string(servicePortChainName(svc, strings.ToLower(proto))) kubeNodePortRules := ipt.GetRules(string(kubeNodePortsChain)) if !hasJump(kubeNodePortRules, svcChain, "", fmt.Sprintf("%v", svcInfo.nodePort)) { errorf(fmt.Sprintf("Failed to find jump to svc chain %v", svcChain), kubeNodePortRules, t) } }
func TestProxyUpdatePortal(t *testing.T) { lb := NewLoadBalancerRR() service := proxy.ServicePortName{NamespacedName: types.NamespacedName{Namespace: "testnamespace", Name: "echo"}, Port: "p"} endpoint := api.Endpoints{ ObjectMeta: api.ObjectMeta{Name: service.Name, Namespace: service.Namespace}, Subsets: []api.EndpointSubset{{ Addresses: []api.EndpointAddress{{IP: "127.0.0.1"}}, Ports: []api.EndpointPort{{Name: "p", Port: tcpServerPort}}, }}, } lb.OnEndpointsUpdate([]api.Endpoints{endpoint}) p, err := createProxier(lb, net.ParseIP("0.0.0.0"), ipttest.NewFake(), net.ParseIP("127.0.0.1"), nil, time.Minute, time.Second, udpIdleTimeoutForTest) if err != nil { t.Fatal(err) } waitForNumProxyLoops(t, p, 0) svcInfo, err := p.addServiceOnPort(service, "TCP", 0, time.Second) if err != nil { t.Fatalf("error adding new service: %#v", err) } testEchoTCP(t, "127.0.0.1", svcInfo.proxyPort) waitForNumProxyLoops(t, p, 1) p.OnServiceUpdate([]api.Service{{ ObjectMeta: api.ObjectMeta{Name: service.Name, Namespace: service.Namespace}, Spec: api.ServiceSpec{ClusterIP: "", Ports: []api.ServicePort{{ Name: "p", Port: int32(svcInfo.proxyPort), Protocol: "TCP", }}}, }}) _, exists := p.getServiceInfo(service) if exists { t.Fatalf("service with empty ClusterIP should not be included in the proxy") } p.OnServiceUpdate([]api.Service{{ ObjectMeta: api.ObjectMeta{Name: service.Name, Namespace: service.Namespace}, Spec: api.ServiceSpec{ClusterIP: "None", Ports: []api.ServicePort{{ Name: "p", Port: int32(svcInfo.proxyPort), Protocol: "TCP", }}}, }}) _, exists = p.getServiceInfo(service) if exists { t.Fatalf("service with 'None' as ClusterIP should not be included in the proxy") } p.OnServiceUpdate([]api.Service{{ ObjectMeta: api.ObjectMeta{Name: service.Name, Namespace: service.Namespace}, Spec: api.ServiceSpec{ClusterIP: "1.2.3.4", Ports: []api.ServicePort{{ Name: "p", Port: int32(svcInfo.proxyPort), Protocol: "TCP", }}}, }}) lb.OnEndpointsUpdate([]api.Endpoints{endpoint}) svcInfo, exists = p.getServiceInfo(service) if !exists { t.Fatalf("service with ClusterIP set not found in the proxy") } testEchoTCP(t, "127.0.0.1", svcInfo.proxyPort) waitForNumProxyLoops(t, p, 1) }
func TestOnlyLocalNodePorts(t *testing.T) { ipt := iptablestest.NewFake() fp := NewFakeProxier(ipt) onlyLocalNodePorts(t, fp, ipt) }