1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254 |
- /*
- Copyright 2015 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 iptables
- import (
- "bytes"
- "fmt"
- "net"
- "reflect"
- "strconv"
- "strings"
- "testing"
- "time"
- "k8s.io/klog"
- "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"
- utilproxy "k8s.io/kubernetes/pkg/proxy/util"
- utilproxytest "k8s.io/kubernetes/pkg/proxy/util/testing"
- "k8s.io/kubernetes/pkg/util/async"
- "k8s.io/kubernetes/pkg/util/conntrack"
- utiliptables "k8s.io/kubernetes/pkg/util/iptables"
- iptablestest "k8s.io/kubernetes/pkg/util/iptables/testing"
- "k8s.io/utils/exec"
- fakeexec "k8s.io/utils/exec/testing"
- utilpointer "k8s.io/utils/pointer"
- )
- func checkAllLines(t *testing.T, table utiliptables.Table, save []byte, expectedLines map[utiliptables.Chain]string) {
- chainLines := utiliptables.GetChainLines(table, save)
- for chain, lineBytes := range chainLines {
- line := string(lineBytes)
- if expected, exists := expectedLines[chain]; exists {
- if expected != line {
- t.Errorf("getChainLines expected chain line not present. For chain: %s Expected: %s Got: %s", chain, expected, line)
- }
- } else {
- t.Errorf("getChainLines expected chain not present: %s", chain)
- }
- }
- }
- func TestGetChainLines(t *testing.T) {
- iptablesSave := `# Generated by iptables-save v1.4.7 on Wed Oct 29 14:56:01 2014
- *nat
- :PREROUTING ACCEPT [2136997:197881818]
- :POSTROUTING ACCEPT [4284525:258542680]
- :OUTPUT ACCEPT [5901660:357267963]
- -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
- COMMIT
- # Completed on Wed Oct 29 14:56:01 2014`
- expected := map[utiliptables.Chain]string{
- utiliptables.ChainPrerouting: ":PREROUTING ACCEPT [2136997:197881818]",
- utiliptables.ChainPostrouting: ":POSTROUTING ACCEPT [4284525:258542680]",
- utiliptables.ChainOutput: ":OUTPUT ACCEPT [5901660:357267963]",
- }
- checkAllLines(t, utiliptables.TableNAT, []byte(iptablesSave), expected)
- }
- func TestGetChainLinesMultipleTables(t *testing.T) {
- iptablesSave := `# Generated by iptables-save v1.4.21 on Fri Aug 7 14:47:37 2015
- *nat
- :PREROUTING ACCEPT [2:138]
- :INPUT ACCEPT [0:0]
- :OUTPUT ACCEPT [0:0]
- :POSTROUTING ACCEPT [0:0]
- :DOCKER - [0:0]
- :KUBE-NODEPORT-CONTAINER - [0:0]
- :KUBE-NODEPORT-HOST - [0:0]
- :KUBE-PORTALS-CONTAINER - [0:0]
- :KUBE-PORTALS-HOST - [0:0]
- :KUBE-SVC-1111111111111111 - [0:0]
- :KUBE-SVC-2222222222222222 - [0:0]
- :KUBE-SVC-3333333333333333 - [0:0]
- :KUBE-SVC-4444444444444444 - [0:0]
- :KUBE-SVC-5555555555555555 - [0:0]
- :KUBE-SVC-6666666666666666 - [0:0]
- -A PREROUTING -m comment --comment "handle ClusterIPs; NOTE: this must be before the NodePort rules" -j KUBE-PORTALS-CONTAINER
- -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
- -A PREROUTING -m addrtype --dst-type LOCAL -m comment --comment "handle service NodePorts; NOTE: this must be the last rule in the chain" -j KUBE-NODEPORT-CONTAINER
- -A OUTPUT -m comment --comment "handle ClusterIPs; NOTE: this must be before the NodePort rules" -j KUBE-PORTALS-HOST
- -A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
- -A OUTPUT -m addrtype --dst-type LOCAL -m comment --comment "handle service NodePorts; NOTE: this must be the last rule in the chain" -j KUBE-NODEPORT-HOST
- -A POSTROUTING -s 10.246.1.0/24 ! -o cbr0 -j MASQUERADE
- -A POSTROUTING -s 10.0.2.15/32 -d 10.0.2.15/32 -m comment --comment "handle pod connecting to self" -j MASQUERADE
- -A KUBE-PORTALS-CONTAINER -d 10.247.0.1/32 -p tcp -m comment --comment "portal for default/kubernetes:" -m state --state NEW -m tcp --dport 443 -j KUBE-SVC-5555555555555555
- -A KUBE-PORTALS-CONTAINER -d 10.247.0.10/32 -p udp -m comment --comment "portal for kube-system/kube-dns:dns" -m state --state NEW -m udp --dport 53 -j KUBE-SVC-6666666666666666
- -A KUBE-PORTALS-CONTAINER -d 10.247.0.10/32 -p tcp -m comment --comment "portal for kube-system/kube-dns:dns-tcp" -m state --state NEW -m tcp --dport 53 -j KUBE-SVC-2222222222222222
- -A KUBE-PORTALS-HOST -d 10.247.0.1/32 -p tcp -m comment --comment "portal for default/kubernetes:" -m state --state NEW -m tcp --dport 443 -j KUBE-SVC-5555555555555555
- -A KUBE-PORTALS-HOST -d 10.247.0.10/32 -p udp -m comment --comment "portal for kube-system/kube-dns:dns" -m state --state NEW -m udp --dport 53 -j KUBE-SVC-6666666666666666
- -A KUBE-PORTALS-HOST -d 10.247.0.10/32 -p tcp -m comment --comment "portal for kube-system/kube-dns:dns-tcp" -m state --state NEW -m tcp --dport 53 -j KUBE-SVC-2222222222222222
- -A KUBE-SVC-1111111111111111 -p udp -m comment --comment "kube-system/kube-dns:dns" -m recent --set --name KUBE-SVC-1111111111111111 --mask 255.255.255.255 --rsource -j DNAT --to-destination 10.246.1.2:53
- -A KUBE-SVC-2222222222222222 -m comment --comment "kube-system/kube-dns:dns-tcp" -j KUBE-SVC-3333333333333333
- -A KUBE-SVC-3333333333333333 -p tcp -m comment --comment "kube-system/kube-dns:dns-tcp" -m recent --set --name KUBE-SVC-3333333333333333 --mask 255.255.255.255 --rsource -j DNAT --to-destination 10.246.1.2:53
- -A KUBE-SVC-4444444444444444 -p tcp -m comment --comment "default/kubernetes:" -m recent --set --name KUBE-SVC-4444444444444444 --mask 255.255.255.255 --rsource -j DNAT --to-destination 10.245.1.2:443
- -A KUBE-SVC-5555555555555555 -m comment --comment "default/kubernetes:" -j KUBE-SVC-4444444444444444
- -A KUBE-SVC-6666666666666666 -m comment --comment "kube-system/kube-dns:dns" -j KUBE-SVC-1111111111111111
- COMMIT
- # Completed on Fri Aug 7 14:47:37 2015
- # Generated by iptables-save v1.4.21 on Fri Aug 7 14:47:37 2015
- *filter
- :INPUT ACCEPT [17514:83115836]
- :FORWARD ACCEPT [0:0]
- :OUTPUT ACCEPT [8909:688225]
- :DOCKER - [0:0]
- -A FORWARD -o cbr0 -j DOCKER
- -A FORWARD -o cbr0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
- -A FORWARD -i cbr0 ! -o cbr0 -j ACCEPT
- -A FORWARD -i cbr0 -o cbr0 -j ACCEPT
- COMMIT
- `
- expected := map[utiliptables.Chain]string{
- utiliptables.ChainPrerouting: ":PREROUTING ACCEPT [2:138]",
- utiliptables.Chain("INPUT"): ":INPUT ACCEPT [0:0]",
- utiliptables.Chain("OUTPUT"): ":OUTPUT ACCEPT [0:0]",
- utiliptables.ChainPostrouting: ":POSTROUTING ACCEPT [0:0]",
- utiliptables.Chain("DOCKER"): ":DOCKER - [0:0]",
- utiliptables.Chain("KUBE-NODEPORT-CONTAINER"): ":KUBE-NODEPORT-CONTAINER - [0:0]",
- utiliptables.Chain("KUBE-NODEPORT-HOST"): ":KUBE-NODEPORT-HOST - [0:0]",
- utiliptables.Chain("KUBE-PORTALS-CONTAINER"): ":KUBE-PORTALS-CONTAINER - [0:0]",
- utiliptables.Chain("KUBE-PORTALS-HOST"): ":KUBE-PORTALS-HOST - [0:0]",
- utiliptables.Chain("KUBE-SVC-1111111111111111"): ":KUBE-SVC-1111111111111111 - [0:0]",
- utiliptables.Chain("KUBE-SVC-2222222222222222"): ":KUBE-SVC-2222222222222222 - [0:0]",
- utiliptables.Chain("KUBE-SVC-3333333333333333"): ":KUBE-SVC-3333333333333333 - [0:0]",
- utiliptables.Chain("KUBE-SVC-4444444444444444"): ":KUBE-SVC-4444444444444444 - [0:0]",
- utiliptables.Chain("KUBE-SVC-5555555555555555"): ":KUBE-SVC-5555555555555555 - [0:0]",
- utiliptables.Chain("KUBE-SVC-6666666666666666"): ":KUBE-SVC-6666666666666666 - [0:0]",
- }
- checkAllLines(t, utiliptables.TableNAT, []byte(iptablesSave), expected)
- }
- func newFakeServiceInfo(service proxy.ServicePortName, ip net.IP, port int, protocol v1.Protocol, onlyNodeLocalEndpoints bool) *serviceInfo {
- return &serviceInfo{
- BaseServiceInfo: &proxy.BaseServiceInfo{
- SessionAffinityType: v1.ServiceAffinityNone, // default
- StickyMaxAgeSeconds: int(v1.DefaultClientIPServiceAffinitySeconds), // default
- ClusterIP: ip,
- Port: port,
- Protocol: protocol,
- OnlyNodeLocalEndpoints: onlyNodeLocalEndpoints,
- },
- }
- }
- func TestDeleteEndpointConnections(t *testing.T) {
- const (
- UDP = v1.ProtocolUDP
- TCP = v1.ProtocolTCP
- SCTP = v1.ProtocolSCTP
- )
- testCases := []struct {
- description string
- svcName string
- svcIP string
- svcPort int
- protocol v1.Protocol
- endpoint string // IP:port endpoint
- epSvcPair proxy.ServiceEndpoint // Will be generated by test
- simulatedErr string
- }{
- {
- description: "V4 UDP",
- svcName: "v4-udp",
- svcIP: "10.96.1.1",
- svcPort: 80,
- protocol: UDP,
- endpoint: "10.240.0.3:80",
- }, {
- description: "V4 TCP",
- svcName: "v4-tcp",
- svcIP: "10.96.2.2",
- svcPort: 80,
- protocol: TCP,
- endpoint: "10.240.0.4:80",
- }, {
- description: "V4 SCTP",
- svcName: "v4-sctp",
- svcIP: "10.96.3.3",
- svcPort: 80,
- protocol: SCTP,
- endpoint: "10.240.0.5:80",
- }, {
- description: "V4 UDP, nothing to delete, benign error",
- svcName: "v4-udp-nothing-to-delete",
- svcIP: "10.96.1.1",
- svcPort: 80,
- protocol: UDP,
- endpoint: "10.240.0.3:80",
- simulatedErr: conntrack.NoConnectionToDelete,
- }, {
- description: "V4 UDP, unexpected error, should be glogged",
- svcName: "v4-udp-simulated-error",
- svcIP: "10.96.1.1",
- svcPort: 80,
- protocol: UDP,
- endpoint: "10.240.0.3:80",
- simulatedErr: "simulated error",
- }, {
- description: "V6 UDP",
- svcName: "v6-udp",
- svcIP: "fd00:1234::20",
- svcPort: 80,
- protocol: UDP,
- endpoint: "[2001:db8::2]:80",
- }, {
- description: "V6 TCP",
- svcName: "v6-tcp",
- svcIP: "fd00:1234::30",
- svcPort: 80,
- protocol: TCP,
- endpoint: "[2001:db8::3]:80",
- }, {
- description: "V6 SCTP",
- svcName: "v6-sctp",
- svcIP: "fd00:1234::40",
- svcPort: 80,
- protocol: SCTP,
- endpoint: "[2001:db8::4]:80",
- },
- }
- // Create a service map that has service info entries for all test cases
- // and generate an endpoint service pair for each test case
- serviceMap := make(map[proxy.ServicePortName]proxy.ServicePort)
- for i, tc := range testCases {
- svc := proxy.ServicePortName{
- NamespacedName: types.NamespacedName{Namespace: "ns1", Name: tc.svcName},
- Port: "p80",
- }
- serviceMap[svc] = newFakeServiceInfo(svc, net.ParseIP(tc.svcIP), 80, tc.protocol, false)
- testCases[i].epSvcPair = proxy.ServiceEndpoint{
- Endpoint: tc.endpoint,
- ServicePortName: svc,
- }
- }
- // Create a fake executor for the conntrack utility. This should only be
- // invoked for UDP connections, since no conntrack cleanup is needed for TCP
- fcmd := fakeexec.FakeCmd{}
- fexec := fakeexec.FakeExec{
- LookPathFunc: func(cmd string) (string, error) { return cmd, nil },
- }
- execFunc := func(cmd string, args ...string) exec.Cmd {
- return fakeexec.InitFakeCmd(&fcmd, cmd, args...)
- }
- for _, tc := range testCases {
- if tc.protocol == UDP {
- var cmdOutput string
- var simErr error
- if tc.simulatedErr == "" {
- cmdOutput = "1 flow entries have been deleted"
- } else {
- simErr = fmt.Errorf(tc.simulatedErr)
- }
- cmdFunc := func() ([]byte, error) { return []byte(cmdOutput), simErr }
- fcmd.CombinedOutputScript = append(fcmd.CombinedOutputScript, cmdFunc)
- fexec.CommandScript = append(fexec.CommandScript, execFunc)
- }
- }
- // Create a proxier using the fake conntrack executor and service map
- fakeProxier := Proxier{exec: &fexec, serviceMap: serviceMap}
- // Run the test cases
- for _, tc := range testCases {
- priorExecs := fexec.CommandCalls
- priorGlogErrs := klog.Stats.Error.Lines()
- input := []proxy.ServiceEndpoint{tc.epSvcPair}
- fakeProxier.deleteEndpointConnections(input)
- // For UDP connections, check the executed conntrack command
- var expExecs int
- if tc.protocol == UDP {
- isIPv6 := func(ip string) bool {
- netIP := net.ParseIP(ip)
- if netIP.To4() == nil {
- return true
- }
- return false
- }
- endpointIP := utilproxy.IPPart(tc.endpoint)
- expectCommand := fmt.Sprintf("conntrack -D --orig-dst %s --dst-nat %s -p udp", tc.svcIP, endpointIP)
- if isIPv6(endpointIP) {
- expectCommand += " -f ipv6"
- }
- actualCommand := strings.Join(fcmd.CombinedOutputLog[fexec.CommandCalls-1], " ")
- if actualCommand != expectCommand {
- t.Errorf("%s: Expected command: %s, but executed %s", tc.description, expectCommand, actualCommand)
- }
- expExecs = 1
- }
- // Check the number of times conntrack was executed
- execs := fexec.CommandCalls - priorExecs
- if execs != expExecs {
- t.Errorf("%s: Expected conntrack to be executed %d times, but got %d", tc.description, expExecs, execs)
- }
- // Check the number of new glog errors
- var expGlogErrs int64
- if tc.simulatedErr != "" && tc.simulatedErr != conntrack.NoConnectionToDelete {
- expGlogErrs = 1
- }
- glogErrs := klog.Stats.Error.Lines() - priorGlogErrs
- if glogErrs != expGlogErrs {
- t.Errorf("%s: Expected %d glogged errors, but got %d", tc.description, expGlogErrs, glogErrs)
- }
- }
- }
- // 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
- }
- 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{},
- }
- }
- 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
- }
- const testHostname = "test-hostname"
- func NewFakeProxier(ipt utiliptables.Interface) *Proxier {
- // TODO: Call NewProxier after refactoring out the goroutine
- // invocation into a Run() method.
- p := &Proxier{
- exec: &fakeexec.FakeExec{},
- serviceMap: make(proxy.ServiceMap),
- serviceChanges: proxy.NewServiceChangeTracker(newServiceInfo, nil, nil),
- endpointsMap: make(proxy.EndpointsMap),
- endpointsChanges: proxy.NewEndpointChangeTracker(testHostname, newEndpointInfo, nil, nil),
- iptables: ipt,
- clusterCIDR: "10.0.0.0/24",
- hostname: testHostname,
- portsMap: make(map[utilproxy.LocalPort]utilproxy.Closeable),
- portMapper: &fakePortOpener{[]*utilproxy.LocalPort{}},
- healthChecker: newFakeHealthChecker(),
- precomputedProbabilities: make([]string, 0, 1001),
- iptablesData: bytes.NewBuffer(nil),
- existingFilterChainsData: bytes.NewBuffer(nil),
- filterChains: bytes.NewBuffer(nil),
- filterRules: bytes.NewBuffer(nil),
- natChains: bytes.NewBuffer(nil),
- natRules: bytes.NewBuffer(nil),
- nodePortAddresses: make([]string, 0),
- networkInterfacer: utilproxytest.NewFakeNetwork(),
- }
- p.syncRunner = async.NewBoundedFrequencyRunner("test-sync-runner", p.syncProxyRules, 0, time.Minute, 1)
- return p
- }
- func hasSessionAffinityRule(rules []iptablestest.Rule) bool {
- for _, r := range rules {
- if _, ok := r[iptablestest.Recent]; ok {
- return true
- }
- }
- return false
- }
- func hasJump(rules []iptablestest.Rule, destChain, destIP string, destPort int) bool {
- destPortStr := strconv.Itoa(destPort)
- match := false
- for _, r := range rules {
- if r[iptablestest.Jump] == destChain {
- match = true
- if destIP != "" {
- if strings.Contains(r[iptablestest.Destination], destIP) && (strings.Contains(r[iptablestest.DPort], destPortStr) || r[iptablestest.DPort] == "") {
- return true
- }
- match = false
- }
- if destPort != 0 {
- if strings.Contains(r[iptablestest.DPort], destPortStr) && (strings.Contains(r[iptablestest.Destination], destIP) || r[iptablestest.Destination] == "") {
- return true
- }
- match = false
- }
- }
- }
- return match
- }
- func hasSrcType(rules []iptablestest.Rule, srcType string) bool {
- for _, r := range rules {
- if r[iptablestest.SrcType] != srcType {
- continue
- }
- return true
- }
- return false
- }
- func TestHasJump(t *testing.T) {
- testCases := map[string]struct {
- rules []iptablestest.Rule
- destChain string
- destIP string
- destPort int
- expected bool
- }{
- "case 1": {
- // Match the 1st rule(both dest IP and dest Port)
- rules: []iptablestest.Rule{
- {"-d ": "10.20.30.41/32", "--dport ": "80", "-p ": "tcp", "-j ": "REJECT"},
- {"--dport ": "3001", "-p ": "tcp", "-j ": "KUBE-MARK-MASQ"},
- },
- destChain: "REJECT",
- destIP: "10.20.30.41",
- destPort: 80,
- expected: true,
- },
- "case 2": {
- // Match the 2nd rule(dest Port)
- rules: []iptablestest.Rule{
- {"-d ": "10.20.30.41/32", "-p ": "tcp", "-j ": "REJECT"},
- {"--dport ": "3001", "-p ": "tcp", "-j ": "REJECT"},
- },
- destChain: "REJECT",
- destIP: "",
- destPort: 3001,
- expected: true,
- },
- "case 3": {
- // Match both dest IP and dest Port
- rules: []iptablestest.Rule{
- {"-d ": "1.2.3.4/32", "--dport ": "80", "-p ": "tcp", "-j ": "KUBE-XLB-GF53O3C2HZEXL2XN"},
- },
- destChain: "KUBE-XLB-GF53O3C2HZEXL2XN",
- destIP: "1.2.3.4",
- destPort: 80,
- expected: true,
- },
- "case 4": {
- // Match dest IP but doesn't match dest Port
- rules: []iptablestest.Rule{
- {"-d ": "1.2.3.4/32", "--dport ": "80", "-p ": "tcp", "-j ": "KUBE-XLB-GF53O3C2HZEXL2XN"},
- },
- destChain: "KUBE-XLB-GF53O3C2HZEXL2XN",
- destIP: "1.2.3.4",
- destPort: 8080,
- expected: false,
- },
- "case 5": {
- // Match dest Port but doesn't match dest IP
- rules: []iptablestest.Rule{
- {"-d ": "1.2.3.4/32", "--dport ": "80", "-p ": "tcp", "-j ": "KUBE-XLB-GF53O3C2HZEXL2XN"},
- },
- destChain: "KUBE-XLB-GF53O3C2HZEXL2XN",
- destIP: "10.20.30.40",
- destPort: 80,
- expected: false,
- },
- "case 6": {
- // Match the 2nd rule(dest IP)
- rules: []iptablestest.Rule{
- {"-d ": "10.20.30.41/32", "-p ": "tcp", "-j ": "REJECT"},
- {"-d ": "1.2.3.4/32", "-p ": "tcp", "-j ": "REJECT"},
- {"--dport ": "3001", "-p ": "tcp", "-j ": "REJECT"},
- },
- destChain: "REJECT",
- destIP: "1.2.3.4",
- destPort: 8080,
- expected: true,
- },
- "case 7": {
- // Match the 2nd rule(dest Port)
- rules: []iptablestest.Rule{
- {"-d ": "10.20.30.41/32", "-p ": "tcp", "-j ": "REJECT"},
- {"--dport ": "3001", "-p ": "tcp", "-j ": "REJECT"},
- },
- destChain: "REJECT",
- destIP: "1.2.3.4",
- destPort: 3001,
- expected: true,
- },
- "case 8": {
- // Match the 1st rule(dest IP)
- rules: []iptablestest.Rule{
- {"-d ": "10.20.30.41/32", "-p ": "tcp", "-j ": "REJECT"},
- {"--dport ": "3001", "-p ": "tcp", "-j ": "REJECT"},
- },
- destChain: "REJECT",
- destIP: "10.20.30.41",
- destPort: 8080,
- expected: true,
- },
- "case 9": {
- rules: []iptablestest.Rule{
- {"-j ": "KUBE-SEP-LWSOSDSHMKPJHHJV"},
- },
- destChain: "KUBE-SEP-LWSOSDSHMKPJHHJV",
- destIP: "",
- destPort: 0,
- expected: true,
- },
- "case 10": {
- rules: []iptablestest.Rule{
- {"-j ": "KUBE-SEP-FOO"},
- },
- destChain: "KUBE-SEP-BAR",
- destIP: "",
- destPort: 0,
- expected: false,
- },
- }
- for k, tc := range testCases {
- if got := hasJump(tc.rules, tc.destChain, tc.destIP, tc.destPort); got != tc.expected {
- t.Errorf("%v: expected %v, got %v", k, tc.expected, got)
- }
- }
- }
- func hasDNAT(rules []iptablestest.Rule, endpoint string) bool {
- for _, r := range rules {
- if r[iptablestest.ToDest] == endpoint {
- return true
- }
- }
- return false
- }
- func errorf(msg string, rules []iptablestest.Rule, t *testing.T) {
- for _, r := range rules {
- t.Logf("%q", r)
- }
- t.Errorf("%v", msg)
- }
- func TestClusterIPReject(t *testing.T) {
- ipt := iptablestest.NewFake()
- fp := NewFakeProxier(ipt)
- svcIP := "10.20.30.41"
- svcPort := 80
- svcPortName := proxy.ServicePortName{
- NamespacedName: makeNSN("ns1", "svc1"),
- Port: "p80",
- }
- makeServiceMap(fp,
- makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
- svc.Spec.ClusterIP = svcIP
- svc.Spec.Ports = []v1.ServicePort{{
- Name: svcPortName.Port,
- Port: int32(svcPort),
- Protocol: v1.ProtocolTCP,
- }}
- }),
- )
- makeEndpointsMap(fp)
- fp.syncProxyRules()
- svcChain := string(servicePortChainName(svcPortName.String(), strings.ToLower(string(v1.ProtocolTCP))))
- svcRules := ipt.GetRules(svcChain)
- if len(svcRules) != 0 {
- errorf(fmt.Sprintf("Unexpected rule for chain %v service %v without endpoints", svcChain, svcPortName), svcRules, t)
- }
- kubeSvcRules := ipt.GetRules(string(kubeServicesChain))
- if !hasJump(kubeSvcRules, iptablestest.Reject, svcIP, svcPort) {
- errorf(fmt.Sprintf("Failed to find a %v rule for service %v with no endpoints", iptablestest.Reject, svcPortName), kubeSvcRules, t)
- }
- }
- func TestClusterIPEndpointsJump(t *testing.T) {
- ipt := iptablestest.NewFake()
- fp := NewFakeProxier(ipt)
- svcIP := "10.20.30.41"
- svcPort := 80
- svcPortName := proxy.ServicePortName{
- NamespacedName: makeNSN("ns1", "svc1"),
- Port: "p80",
- }
- makeServiceMap(fp,
- makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
- svc.Spec.ClusterIP = svcIP
- svc.Spec.Ports = []v1.ServicePort{{
- Name: svcPortName.Port,
- Port: int32(svcPort),
- Protocol: v1.ProtocolTCP,
- }}
- }),
- )
- epIP := "10.180.0.1"
- makeEndpointsMap(fp,
- makeTestEndpoints(svcPortName.Namespace, svcPortName.Name, func(ept *v1.Endpoints) {
- ept.Subsets = []v1.EndpointSubset{{
- Addresses: []v1.EndpointAddress{{
- IP: epIP,
- }},
- Ports: []v1.EndpointPort{{
- Name: svcPortName.Port,
- Port: int32(svcPort),
- }},
- }}
- }),
- )
- fp.syncProxyRules()
- epStr := fmt.Sprintf("%s:%d", epIP, svcPort)
- svcChain := string(servicePortChainName(svcPortName.String(), strings.ToLower(string(v1.ProtocolTCP))))
- epChain := string(servicePortEndpointChainName(svcPortName.String(), strings.ToLower(string(v1.ProtocolTCP)), epStr))
- kubeSvcRules := ipt.GetRules(string(kubeServicesChain))
- if !hasJump(kubeSvcRules, svcChain, svcIP, svcPort) {
- errorf(fmt.Sprintf("Failed to find jump from KUBE-SERVICES to %v chain", svcChain), kubeSvcRules, t)
- }
- svcRules := ipt.GetRules(svcChain)
- if !hasJump(svcRules, epChain, "", 0) {
- errorf(fmt.Sprintf("Failed to jump to ep chain %v", epChain), svcRules, t)
- }
- epRules := ipt.GetRules(epChain)
- if !hasDNAT(epRules, epStr) {
- errorf(fmt.Sprintf("Endpoint chain %v lacks DNAT to %v", epChain, epStr), epRules, t)
- }
- }
- func TestLoadBalancer(t *testing.T) {
- ipt := iptablestest.NewFake()
- fp := NewFakeProxier(ipt)
- 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,
- makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
- svc.Spec.Type = "LoadBalancer"
- svc.Spec.ClusterIP = svcIP
- svc.Spec.Ports = []v1.ServicePort{{
- Name: svcPortName.Port,
- Port: int32(svcPort),
- Protocol: v1.ProtocolTCP,
- NodePort: int32(svcNodePort),
- }}
- svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{
- IP: svcLBIP,
- }}
- }),
- )
- epIP := "10.180.0.1"
- makeEndpointsMap(fp,
- makeTestEndpoints(svcPortName.Namespace, svcPortName.Name, func(ept *v1.Endpoints) {
- ept.Subsets = []v1.EndpointSubset{{
- Addresses: []v1.EndpointAddress{{
- IP: epIP,
- }},
- Ports: []v1.EndpointPort{{
- Name: svcPortName.Port,
- Port: int32(svcPort),
- }},
- }}
- }),
- )
- fp.syncProxyRules()
- proto := strings.ToLower(string(v1.ProtocolTCP))
- fwChain := string(serviceFirewallChainName(svcPortName.String(), proto))
- svcChain := string(servicePortChainName(svcPortName.String(), proto))
- kubeSvcRules := ipt.GetRules(string(kubeServicesChain))
- if !hasJump(kubeSvcRules, fwChain, svcLBIP, svcPort) {
- errorf(fmt.Sprintf("Failed to find jump to firewall chain %v", fwChain), kubeSvcRules, t)
- }
- fwRules := ipt.GetRules(fwChain)
- if !hasJump(fwRules, svcChain, "", 0) || !hasJump(fwRules, string(KubeMarkMasqChain), "", 0) {
- errorf(fmt.Sprintf("Failed to find jump from firewall chain %v to svc chain %v", fwChain, svcChain), fwRules, t)
- }
- }
- func TestNodePort(t *testing.T) {
- ipt := iptablestest.NewFake()
- fp := NewFakeProxier(ipt)
- svcIP := "10.20.30.41"
- svcPort := 80
- svcNodePort := 3001
- svcPortName := proxy.ServicePortName{
- NamespacedName: makeNSN("ns1", "svc1"),
- Port: "p80",
- }
- makeServiceMap(fp,
- makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
- svc.Spec.Type = "NodePort"
- svc.Spec.ClusterIP = svcIP
- svc.Spec.Ports = []v1.ServicePort{{
- Name: svcPortName.Port,
- Port: int32(svcPort),
- Protocol: v1.ProtocolTCP,
- NodePort: int32(svcNodePort),
- }}
- }),
- )
- epIP := "10.180.0.1"
- makeEndpointsMap(fp,
- makeTestEndpoints(svcPortName.Namespace, svcPortName.Name, func(ept *v1.Endpoints) {
- ept.Subsets = []v1.EndpointSubset{{
- Addresses: []v1.EndpointAddress{{
- IP: epIP,
- }},
- Ports: []v1.EndpointPort{{
- Name: svcPortName.Port,
- Port: int32(svcPort),
- }},
- }}
- }),
- )
- itf := net.Interface{Index: 0, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0}
- addrs := []net.Addr{utilproxytest.AddrStruct{Val: "127.0.0.1/16"}}
- itf1 := net.Interface{Index: 1, MTU: 0, Name: "eth1", HardwareAddr: nil, Flags: 0}
- addrs1 := []net.Addr{utilproxytest.AddrStruct{Val: "::1/128"}}
- fp.networkInterfacer.(*utilproxytest.FakeNetwork).AddInterfaceAddr(&itf, addrs)
- fp.networkInterfacer.(*utilproxytest.FakeNetwork).AddInterfaceAddr(&itf1, addrs1)
- fp.nodePortAddresses = []string{}
- fp.syncProxyRules()
- proto := strings.ToLower(string(v1.ProtocolTCP))
- svcChain := string(servicePortChainName(svcPortName.String(), proto))
- kubeNodePortRules := ipt.GetRules(string(kubeNodePortsChain))
- if !hasJump(kubeNodePortRules, svcChain, "", svcNodePort) {
- errorf(fmt.Sprintf("Failed to find jump to svc chain %v", svcChain), kubeNodePortRules, t)
- }
- }
- func TestExternalIPsReject(t *testing.T) {
- ipt := iptablestest.NewFake()
- fp := NewFakeProxier(ipt)
- svcIP := "10.20.30.41"
- svcPort := 80
- svcExternalIPs := "50.60.70.81"
- svcPortName := proxy.ServicePortName{
- NamespacedName: makeNSN("ns1", "svc1"),
- Port: "p80",
- }
- makeServiceMap(fp,
- makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
- svc.Spec.Type = "ClusterIP"
- svc.Spec.ClusterIP = svcIP
- svc.Spec.ExternalIPs = []string{svcExternalIPs}
- svc.Spec.Ports = []v1.ServicePort{{
- Name: svcPortName.Port,
- Port: int32(svcPort),
- Protocol: v1.ProtocolTCP,
- TargetPort: intstr.FromInt(svcPort),
- }}
- }),
- )
- makeEndpointsMap(fp)
- fp.syncProxyRules()
- kubeSvcRules := ipt.GetRules(string(kubeExternalServicesChain))
- if !hasJump(kubeSvcRules, iptablestest.Reject, svcExternalIPs, svcPort) {
- errorf(fmt.Sprintf("Failed to find a %v rule for externalIP %v with no endpoints", iptablestest.Reject, svcPortName), kubeSvcRules, t)
- }
- }
- func TestNodePortReject(t *testing.T) {
- ipt := iptablestest.NewFake()
- fp := NewFakeProxier(ipt)
- svcIP := "10.20.30.41"
- svcPort := 80
- svcNodePort := 3001
- svcPortName := proxy.ServicePortName{
- NamespacedName: makeNSN("ns1", "svc1"),
- Port: "p80",
- }
- makeServiceMap(fp,
- makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
- svc.Spec.Type = "NodePort"
- svc.Spec.ClusterIP = svcIP
- svc.Spec.Ports = []v1.ServicePort{{
- Name: svcPortName.Port,
- Port: int32(svcPort),
- Protocol: v1.ProtocolTCP,
- NodePort: int32(svcNodePort),
- }}
- }),
- )
- makeEndpointsMap(fp)
- fp.syncProxyRules()
- kubeSvcRules := ipt.GetRules(string(kubeExternalServicesChain))
- if !hasJump(kubeSvcRules, iptablestest.Reject, svcIP, svcNodePort) {
- errorf(fmt.Sprintf("Failed to find a %v rule for service %v with no endpoints", iptablestest.Reject, svcPortName), kubeSvcRules, t)
- }
- }
- func TestOnlyLocalLoadBalancing(t *testing.T) {
- ipt := iptablestest.NewFake()
- fp := NewFakeProxier(ipt)
- svcIP := "10.20.30.41"
- svcPort := 80
- svcNodePort := 3001
- svcLBIP := "1.2.3.4"
- svcPortName := proxy.ServicePortName{
- NamespacedName: makeNSN("ns1", "svc1"),
- Port: "p80",
- }
- svcSessionAffinityTimeout := int32(10800)
- makeServiceMap(fp,
- makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
- svc.Spec.Type = "LoadBalancer"
- svc.Spec.ClusterIP = svcIP
- svc.Spec.Ports = []v1.ServicePort{{
- Name: svcPortName.Port,
- Port: int32(svcPort),
- Protocol: v1.ProtocolTCP,
- NodePort: int32(svcNodePort),
- }}
- svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{
- IP: svcLBIP,
- }}
- svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyTypeLocal
- svc.Spec.SessionAffinity = v1.ServiceAffinityClientIP
- svc.Spec.SessionAffinityConfig = &v1.SessionAffinityConfig{
- ClientIP: &v1.ClientIPConfig{TimeoutSeconds: &svcSessionAffinityTimeout},
- }
- }),
- )
- epIP1 := "10.180.0.1"
- epIP2 := "10.180.2.1"
- epStrLocal := fmt.Sprintf("%s:%d", epIP1, svcPort)
- epStrNonLocal := fmt.Sprintf("%s:%d", epIP2, svcPort)
- makeEndpointsMap(fp,
- makeTestEndpoints(svcPortName.Namespace, svcPortName.Name, func(ept *v1.Endpoints) {
- ept.Subsets = []v1.EndpointSubset{{
- Addresses: []v1.EndpointAddress{{
- IP: epIP1,
- NodeName: nil,
- }, {
- IP: epIP2,
- NodeName: utilpointer.StringPtr(testHostname),
- }},
- Ports: []v1.EndpointPort{{
- Name: svcPortName.Port,
- Port: int32(svcPort),
- }},
- }}
- }),
- )
- fp.syncProxyRules()
- proto := strings.ToLower(string(v1.ProtocolTCP))
- fwChain := string(serviceFirewallChainName(svcPortName.String(), proto))
- lbChain := string(serviceLBChainName(svcPortName.String(), proto))
- nonLocalEpChain := string(servicePortEndpointChainName(svcPortName.String(), strings.ToLower(string(v1.ProtocolTCP)), epStrLocal))
- localEpChain := string(servicePortEndpointChainName(svcPortName.String(), strings.ToLower(string(v1.ProtocolTCP)), epStrNonLocal))
- kubeSvcRules := ipt.GetRules(string(kubeServicesChain))
- if !hasJump(kubeSvcRules, fwChain, svcLBIP, svcPort) {
- errorf(fmt.Sprintf("Failed to find jump to firewall chain %v", fwChain), kubeSvcRules, t)
- }
- fwRules := ipt.GetRules(fwChain)
- if !hasJump(fwRules, lbChain, "", 0) {
- errorf(fmt.Sprintf("Failed to find jump from firewall chain %v to svc chain %v", fwChain, lbChain), fwRules, t)
- }
- if hasJump(fwRules, string(KubeMarkMasqChain), "", 0) {
- errorf(fmt.Sprintf("Found jump from fw chain %v to MASQUERADE", fwChain), fwRules, t)
- }
- lbRules := ipt.GetRules(lbChain)
- if hasJump(lbRules, nonLocalEpChain, "", 0) {
- errorf(fmt.Sprintf("Found jump from lb chain %v to non-local ep %v", lbChain, epStrLocal), lbRules, t)
- }
- if !hasJump(lbRules, localEpChain, "", 0) {
- errorf(fmt.Sprintf("Didn't find jump from lb chain %v to local ep %v", lbChain, epStrNonLocal), lbRules, t)
- }
- if !hasSessionAffinityRule(lbRules) {
- errorf(fmt.Sprintf("Didn't find session affinity rule from lb chain %v", lbChain), lbRules, 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)
- }
- func TestOnlyLocalNodePorts(t *testing.T) {
- ipt := iptablestest.NewFake()
- fp := NewFakeProxier(ipt)
- onlyLocalNodePorts(t, fp, ipt)
- }
- func onlyLocalNodePorts(t *testing.T, fp *Proxier, ipt *iptablestest.FakeIPTables) {
- svcIP := "10.20.30.41"
- svcPort := 80
- svcNodePort := 3001
- svcPortName := proxy.ServicePortName{
- NamespacedName: makeNSN("ns1", "svc1"),
- Port: "p80",
- }
- makeServiceMap(fp,
- makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
- svc.Spec.Type = "NodePort"
- svc.Spec.ClusterIP = svcIP
- svc.Spec.Ports = []v1.ServicePort{{
- Name: svcPortName.Port,
- Port: int32(svcPort),
- Protocol: v1.ProtocolTCP,
- NodePort: int32(svcNodePort),
- }}
- svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyTypeLocal
- }),
- )
- epIP1 := "10.180.0.1"
- epIP2 := "10.180.2.1"
- epStrLocal := fmt.Sprintf("%s:%d", epIP1, svcPort)
- epStrNonLocal := fmt.Sprintf("%s:%d", epIP2, svcPort)
- makeEndpointsMap(fp,
- makeTestEndpoints(svcPortName.Namespace, svcPortName.Name, func(ept *v1.Endpoints) {
- ept.Subsets = []v1.EndpointSubset{{
- Addresses: []v1.EndpointAddress{{
- IP: epIP1,
- NodeName: nil,
- }, {
- IP: epIP2,
- NodeName: utilpointer.StringPtr(testHostname),
- }},
- Ports: []v1.EndpointPort{{
- Name: svcPortName.Port,
- Port: int32(svcPort),
- }},
- }}
- }),
- )
- itf := net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0}
- addrs := []net.Addr{utilproxytest.AddrStruct{Val: "10.20.30.51/24"}}
- fp.networkInterfacer.(*utilproxytest.FakeNetwork).AddInterfaceAddr(&itf, addrs)
- fp.nodePortAddresses = []string{"10.20.30.0/24"}
- fp.syncProxyRules()
- proto := strings.ToLower(string(v1.ProtocolTCP))
- lbChain := string(serviceLBChainName(svcPortName.String(), proto))
- nonLocalEpChain := string(servicePortEndpointChainName(svcPortName.String(), proto, epStrLocal))
- localEpChain := string(servicePortEndpointChainName(svcPortName.String(), proto, epStrNonLocal))
- kubeNodePortRules := ipt.GetRules(string(kubeNodePortsChain))
- if !hasJump(kubeNodePortRules, lbChain, "", svcNodePort) {
- errorf(fmt.Sprintf("Failed to find jump to lb chain %v", lbChain), kubeNodePortRules, t)
- }
- if !hasJump(kubeNodePortRules, string(KubeMarkMasqChain), "", svcNodePort) {
- errorf(fmt.Sprintf("Failed to find jump to %s chain for destination IP %d", KubeMarkMasqChain, svcNodePort), kubeNodePortRules, t)
- }
- kubeServiceRules := ipt.GetRules(string(kubeServicesChain))
- if !hasJump(kubeServiceRules, string(kubeNodePortsChain), "10.20.30.51", 0) {
- errorf(fmt.Sprintf("Failed to find jump to KUBE-NODEPORTS chain %v", string(kubeNodePortsChain)), kubeServiceRules, t)
- }
- svcChain := string(servicePortChainName(svcPortName.String(), proto))
- lbRules := ipt.GetRules(lbChain)
- if hasJump(lbRules, nonLocalEpChain, "", 0) {
- errorf(fmt.Sprintf("Found jump from lb chain %v to non-local ep %v", lbChain, epStrLocal), lbRules, t)
- }
- if !hasJump(lbRules, svcChain, "", 0) || !hasSrcType(lbRules, "LOCAL") {
- errorf(fmt.Sprintf("Did not find jump from lb chain %v to svc %v with src-type LOCAL", lbChain, svcChain), lbRules, t)
- }
- if !hasJump(lbRules, localEpChain, "", 0) {
- errorf(fmt.Sprintf("Didn't find jump from lb chain %v to local ep %v", lbChain, epStrLocal), lbRules, t)
- }
- }
- func makeTestService(namespace, name string, svcFunc func(*v1.Service)) *v1.Service {
- svc := &v1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: name,
- Namespace: namespace,
- Annotations: map[string]string{},
- },
- Spec: v1.ServiceSpec{},
- Status: v1.ServiceStatus{},
- }
- svcFunc(svc)
- return svc
- }
- func addTestPort(array []v1.ServicePort, name string, protocol v1.Protocol, port, nodeport int32, targetPort int) []v1.ServicePort {
- svcPort := v1.ServicePort{
- Name: name,
- Protocol: protocol,
- Port: port,
- NodePort: nodeport,
- TargetPort: intstr.FromInt(targetPort),
- }
- return append(array, svcPort)
- }
- func TestBuildServiceMapAddRemove(t *testing.T) {
- ipt := iptablestest.NewFake()
- fp := NewFakeProxier(ipt)
- 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, "sctpport", "SCTP", 1236, 6321, 0)
- }),
- 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, "muchmoreblah", "SCTP", 343, 676, 0)
- }),
- 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.Status.LoadBalancer = v1.LoadBalancerStatus{
- Ingress: []v1.LoadBalancerIngress{
- {IP: "10.1.2.4"},
- },
- }
- }),
- 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.Status.LoadBalancer = v1.LoadBalancerStatus{
- Ingress: []v1.LoadBalancerIngress{
- {IP: "10.1.2.3"},
- },
- }
- svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyTypeLocal
- svc.Spec.HealthCheckNodePort = 345
- }),
- }
- for i := range services {
- fp.OnServiceAdd(services[i])
- }
- result := proxy.UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
- if len(fp.serviceMap) != 10 {
- t.Errorf("expected service map length 10, got %v", fp.serviceMap)
- }
- // The only-local-loadbalancer ones get added
- if len(result.HCServiceNodePorts) != 1 {
- t.Errorf("expected 1 healthcheck port, got %v", result.HCServiceNodePorts)
- } else {
- nsn := makeNSN("somewhere", "only-local-load-balancer")
- if port, found := result.HCServiceNodePorts[nsn]; !found || port != 345 {
- t.Errorf("expected healthcheck port [%q]=345: got %v", nsn, result.HCServiceNodePorts)
- }
- }
- if len(result.UDPStaleClusterIP) != 0 {
- // Services only added, so nothing stale yet
- t.Errorf("expected stale UDP services length 0, got %d", len(result.UDPStaleClusterIP))
- }
- // Remove some stuff
- // oneService is a modification of services[0] with removed first port.
- oneService := makeTestService("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])
- result = proxy.UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
- if len(fp.serviceMap) != 1 {
- t.Errorf("expected service map length 1, got %v", fp.serviceMap)
- }
- if len(result.HCServiceNodePorts) != 0 {
- t.Errorf("expected 0 healthcheck ports, got %v", result.HCServiceNodePorts)
- }
- // All services but one were deleted. While you'd expect only the ClusterIPs
- // from the three deleted services here, we still have the ClusterIP for
- // the not-deleted service, because one of it's ServicePorts was deleted.
- expectedStaleUDPServices := []string{"172.16.55.10", "172.16.55.4", "172.16.55.11", "172.16.55.12"}
- if len(result.UDPStaleClusterIP) != len(expectedStaleUDPServices) {
- t.Errorf("expected stale UDP services length %d, got %v", len(expectedStaleUDPServices), result.UDPStaleClusterIP.UnsortedList())
- }
- for _, ip := range expectedStaleUDPServices {
- if !result.UDPStaleClusterIP.Has(ip) {
- t.Errorf("expected stale UDP service service %s", ip)
- }
- }
- }
- func TestBuildServiceMapServiceHeadless(t *testing.T) {
- ipt := iptablestest.NewFake()
- fp := NewFakeProxier(ipt)
- makeServiceMap(fp,
- 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)
- }),
- makeTestService("somewhere-else", "headless-without-port", func(svc *v1.Service) {
- svc.Spec.Type = v1.ServiceTypeClusterIP
- svc.Spec.ClusterIP = v1.ClusterIPNone
- }),
- )
- // Headless service should be ignored
- 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
- if len(result.HCServiceNodePorts) != 0 {
- t.Errorf("expected healthcheck ports length 0, got %d", len(result.HCServiceNodePorts))
- }
- if len(result.UDPStaleClusterIP) != 0 {
- t.Errorf("expected stale UDP services length 0, got %d", len(result.UDPStaleClusterIP))
- }
- }
- func TestBuildServiceMapServiceTypeExternalName(t *testing.T) {
- ipt := iptablestest.NewFake()
- fp := NewFakeProxier(ipt)
- makeServiceMap(fp,
- 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)
- }),
- )
- 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
- if len(result.HCServiceNodePorts) != 0 {
- t.Errorf("expected healthcheck ports length 0, got %v", result.HCServiceNodePorts)
- }
- if len(result.UDPStaleClusterIP) != 0 {
- t.Errorf("expected stale UDP services length 0, got %v", result.UDPStaleClusterIP)
- }
- }
- func TestBuildServiceMapServiceUpdate(t *testing.T) {
- ipt := iptablestest.NewFake()
- fp := NewFakeProxier(ipt)
- 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)
- })
- 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)
- svc.Status.LoadBalancer = v1.LoadBalancerStatus{
- Ingress: []v1.LoadBalancerIngress{
- {IP: "10.1.2.3"},
- },
- }
- svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyTypeLocal
- svc.Spec.HealthCheckNodePort = 345
- })
- fp.OnServiceAdd(servicev1)
- result := proxy.UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
- if len(fp.serviceMap) != 2 {
- t.Errorf("expected service map length 2, got %v", fp.serviceMap)
- }
- if len(result.HCServiceNodePorts) != 0 {
- t.Errorf("expected healthcheck ports length 0, got %v", result.HCServiceNodePorts)
- }
- if len(result.UDPStaleClusterIP) != 0 {
- // Services only added, so nothing stale yet
- t.Errorf("expected stale UDP services length 0, got %d", len(result.UDPStaleClusterIP))
- }
- // Change service to load-balancer
- fp.OnServiceUpdate(servicev1, servicev2)
- result = proxy.UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
- if len(fp.serviceMap) != 2 {
- t.Errorf("expected service map length 2, got %v", fp.serviceMap)
- }
- if len(result.HCServiceNodePorts) != 1 {
- t.Errorf("expected healthcheck ports length 1, got %v", result.HCServiceNodePorts)
- }
- if len(result.UDPStaleClusterIP) != 0 {
- t.Errorf("expected stale UDP services length 0, got %v", result.UDPStaleClusterIP.UnsortedList())
- }
- // No change; make sure the service map stays the same and there are
- // no health-check changes
- fp.OnServiceUpdate(servicev2, servicev2)
- result = proxy.UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
- if len(fp.serviceMap) != 2 {
- t.Errorf("expected service map length 2, got %v", fp.serviceMap)
- }
- if len(result.HCServiceNodePorts) != 1 {
- t.Errorf("expected healthcheck ports length 1, got %v", result.HCServiceNodePorts)
- }
- if len(result.UDPStaleClusterIP) != 0 {
- t.Errorf("expected stale UDP services length 0, got %v", result.UDPStaleClusterIP.UnsortedList())
- }
- // And back to ClusterIP
- fp.OnServiceUpdate(servicev2, servicev1)
- result = proxy.UpdateServiceMap(fp.serviceMap, fp.serviceChanges)
- if len(fp.serviceMap) != 2 {
- t.Errorf("expected service map length 2, got %v", fp.serviceMap)
- }
- if len(result.HCServiceNodePorts) != 0 {
- t.Errorf("expected healthcheck ports length 0, got %v", result.HCServiceNodePorts)
- }
- if len(result.UDPStaleClusterIP) != 0 {
- // Services only added, so nothing stale yet
- t.Errorf("expected stale UDP services length 0, got %d", len(result.UDPStaleClusterIP))
- }
- }
- 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
- }
- 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
- }
- func makeNSN(namespace, name string) types.NamespacedName {
- return types.NamespacedName{Namespace: namespace, Name: name}
- }
- func makeServicePortName(ns, name, port string) proxy.ServicePortName {
- return proxy.ServicePortName{
- NamespacedName: makeNSN(ns, name),
- Port: port,
- }
- }
- 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
- }
- func compareEndpointsMaps(t *testing.T, tci int, newMap proxy.EndpointsMap, expected map[proxy.ServicePortName][]*endpointsInfo) {
- 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]) {
- 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].(*endpointsInfo)
- if !ok {
- t.Errorf("Failed to cast endpointsInfo")
- continue
- }
- if newEp.Endpoint != expected[x][i].Endpoint ||
- newEp.IsLocal != expected[x][i].IsLocal ||
- newEp.protocol != expected[x][i].protocol ||
- newEp.chainName != expected[x][i].chainName {
- t.Errorf("[%d] expected new[%v][%d] to be %v, got %v", tci, x, i, expected[x][i], newEp)
- }
- }
- }
- }
- }
- func Test_updateEndpointsMap(t *testing.T) {
- var nodeName = testHostname
- emptyEndpoint := func(ept *v1.Endpoints) {
- ept.Subsets = []v1.EndpointSubset{}
- }
- unnamedPort := func(ept *v1.Endpoints) {
- ept.Subsets = []v1.EndpointSubset{{
- Addresses: []v1.EndpointAddress{{
- IP: "1.1.1.1",
- }},
- Ports: []v1.EndpointPort{{
- Port: 11,
- }},
- }}
- }
- unnamedPortLocal := func(ept *v1.Endpoints) {
- ept.Subsets = []v1.EndpointSubset{{
- Addresses: []v1.EndpointAddress{{
- IP: "1.1.1.1",
- NodeName: &nodeName,
- }},
- Ports: []v1.EndpointPort{{
- Port: 11,
- }},
- }}
- }
- namedPortLocal := func(ept *v1.Endpoints) {
- ept.Subsets = []v1.EndpointSubset{{
- Addresses: []v1.EndpointAddress{{
- IP: "1.1.1.1",
- NodeName: &nodeName,
- }},
- Ports: []v1.EndpointPort{{
- Name: "p11",
- Port: 11,
- }},
- }}
- }
- namedPort := func(ept *v1.Endpoints) {
- ept.Subsets = []v1.EndpointSubset{{
- Addresses: []v1.EndpointAddress{{
- IP: "1.1.1.1",
- }},
- Ports: []v1.EndpointPort{{
- Name: "p11",
- Port: 11,
- }},
- }}
- }
- namedPortRenamed := func(ept *v1.Endpoints) {
- ept.Subsets = []v1.EndpointSubset{{
- Addresses: []v1.EndpointAddress{{
- IP: "1.1.1.1",
- }},
- Ports: []v1.EndpointPort{{
- Name: "p11-2",
- Port: 11,
- }},
- }}
- }
- namedPortRenumbered := func(ept *v1.Endpoints) {
- ept.Subsets = []v1.EndpointSubset{{
- Addresses: []v1.EndpointAddress{{
- IP: "1.1.1.1",
- }},
- Ports: []v1.EndpointPort{{
- Name: "p11",
- Port: 22,
- }},
- }}
- }
- namedPortsLocalNoLocal := func(ept *v1.Endpoints) {
- ept.Subsets = []v1.EndpointSubset{{
- Addresses: []v1.EndpointAddress{{
- IP: "1.1.1.1",
- }, {
- IP: "1.1.1.2",
- NodeName: &nodeName,
- }},
- Ports: []v1.EndpointPort{{
- Name: "p11",
- Port: 11,
- }, {
- Name: "p12",
- Port: 12,
- }},
- }}
- }
- multipleSubsets := func(ept *v1.Endpoints) {
- ept.Subsets = []v1.EndpointSubset{{
- Addresses: []v1.EndpointAddress{{
- IP: "1.1.1.1",
- }},
- Ports: []v1.EndpointPort{{
- Name: "p11",
- Port: 11,
- }},
- }, {
- Addresses: []v1.EndpointAddress{{
- IP: "1.1.1.2",
- }},
- Ports: []v1.EndpointPort{{
- Name: "p12",
- Port: 12,
- }},
- }}
- }
- multipleSubsetsWithLocal := func(ept *v1.Endpoints) {
- ept.Subsets = []v1.EndpointSubset{{
- Addresses: []v1.EndpointAddress{{
- IP: "1.1.1.1",
- }},
- Ports: []v1.EndpointPort{{
- Name: "p11",
- Port: 11,
- }},
- }, {
- Addresses: []v1.EndpointAddress{{
- IP: "1.1.1.2",
- NodeName: &nodeName,
- }},
- Ports: []v1.EndpointPort{{
- Name: "p12",
- Port: 12,
- }},
- }}
- }
- multipleSubsetsMultiplePortsLocal := func(ept *v1.Endpoints) {
- ept.Subsets = []v1.EndpointSubset{{
- Addresses: []v1.EndpointAddress{{
- IP: "1.1.1.1",
- NodeName: &nodeName,
- }},
- Ports: []v1.EndpointPort{{
- Name: "p11",
- Port: 11,
- }, {
- Name: "p12",
- Port: 12,
- }},
- }, {
- Addresses: []v1.EndpointAddress{{
- IP: "1.1.1.3",
- }},
- Ports: []v1.EndpointPort{{
- Name: "p13",
- Port: 13,
- }},
- }}
- }
- multipleSubsetsIPsPorts1 := func(ept *v1.Endpoints) {
- ept.Subsets = []v1.EndpointSubset{{
- Addresses: []v1.EndpointAddress{{
- IP: "1.1.1.1",
- }, {
- IP: "1.1.1.2",
- NodeName: &nodeName,
- }},
- Ports: []v1.EndpointPort{{
- Name: "p11",
- Port: 11,
- }, {
- Name: "p12",
- Port: 12,
- }},
- }, {
- Addresses: []v1.EndpointAddress{{
- IP: "1.1.1.3",
- }, {
- IP: "1.1.1.4",
- NodeName: &nodeName,
- }},
- Ports: []v1.EndpointPort{{
- Name: "p13",
- Port: 13,
- }, {
- Name: "p14",
- Port: 14,
- }},
- }}
- }
- multipleSubsetsIPsPorts2 := func(ept *v1.Endpoints) {
- ept.Subsets = []v1.EndpointSubset{{
- Addresses: []v1.EndpointAddress{{
- IP: "2.2.2.1",
- }, {
- IP: "2.2.2.2",
- NodeName: &nodeName,
- }},
- Ports: []v1.EndpointPort{{
- Name: "p21",
- Port: 21,
- }, {
- Name: "p22",
- Port: 22,
- }},
- }}
- }
- complexBefore1 := func(ept *v1.Endpoints) {
- ept.Subsets = []v1.EndpointSubset{{
- Addresses: []v1.EndpointAddress{{
- IP: "1.1.1.1",
- }},
- Ports: []v1.EndpointPort{{
- Name: "p11",
- Port: 11,
- }},
- }}
- }
- 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,
- }},
- Ports: []v1.EndpointPort{{
- Name: "p22",
- Port: 22,
- }},
- }, {
- Addresses: []v1.EndpointAddress{{
- IP: "2.2.2.3",
- NodeName: &nodeName,
- }},
- Ports: []v1.EndpointPort{{
- Name: "p23",
- Port: 23,
- }},
- }}
- }
- 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,
- }},
- Ports: []v1.EndpointPort{{
- Name: "p44",
- Port: 44,
- }},
- }, {
- Addresses: []v1.EndpointAddress{{
- IP: "4.4.4.6",
- NodeName: &nodeName,
- }},
- Ports: []v1.EndpointPort{{
- Name: "p45",
- Port: 45,
- }},
- }}
- }
- complexAfter1 := func(ept *v1.Endpoints) {
- ept.Subsets = []v1.EndpointSubset{{
- Addresses: []v1.EndpointAddress{{
- IP: "1.1.1.1",
- }, {
- IP: "1.1.1.11",
- }},
- Ports: []v1.EndpointPort{{
- Name: "p11",
- Port: 11,
- }},
- }, {
- Addresses: []v1.EndpointAddress{{
- IP: "1.1.1.2",
- }},
- Ports: []v1.EndpointPort{{
- Name: "p12",
- Port: 12,
- }, {
- Name: "p122",
- Port: 122,
- }},
- }}
- }
- complexAfter3 := func(ept *v1.Endpoints) {
- ept.Subsets = []v1.EndpointSubset{{
- Addresses: []v1.EndpointAddress{{
- IP: "3.3.3.3",
- }},
- Ports: []v1.EndpointPort{{
- Name: "p33",
- Port: 33,
- }},
- }}
- }
- complexAfter4 := func(ept *v1.Endpoints) {
- ept.Subsets = []v1.EndpointSubset{{
- Addresses: []v1.EndpointAddress{{
- IP: "4.4.4.4",
- NodeName: &nodeName,
- }},
- 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.
- previousEndpoints []*v1.Endpoints
- currentEndpoints []*v1.Endpoints
- oldEndpoints map[proxy.ServicePortName][]*endpointsInfo
- expectedResult map[proxy.ServicePortName][]*endpointsInfo
- expectedStaleEndpoints []proxy.ServiceEndpoint
- expectedStaleServiceNames map[proxy.ServicePortName]bool
- expectedHealthchecks map[types.NamespacedName]int
- }{{
- // Case[0]: nothing
- oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{},
- expectedResult: map[proxy.ServicePortName][]*endpointsInfo{},
- expectedStaleEndpoints: []proxy.ServiceEndpoint{},
- expectedStaleServiceNames: map[proxy.ServicePortName]bool{},
- expectedHealthchecks: map[types.NamespacedName]int{},
- }, {
- // Case[1]: no change, unnamed port
- previousEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", unnamedPort),
- },
- currentEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", unnamedPort),
- },
- oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", ""): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}},
- },
- },
- expectedResult: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", ""): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}},
- },
- },
- expectedStaleEndpoints: []proxy.ServiceEndpoint{},
- expectedStaleServiceNames: map[proxy.ServicePortName]bool{},
- expectedHealthchecks: map[types.NamespacedName]int{},
- }, {
- // Case[2]: no change, named port, local
- previousEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", namedPortLocal),
- },
- currentEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", namedPortLocal),
- },
- oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", "p11"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true}},
- },
- },
- expectedResult: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", "p11"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true}},
- },
- },
- expectedStaleEndpoints: []proxy.ServiceEndpoint{},
- expectedStaleServiceNames: map[proxy.ServicePortName]bool{},
- expectedHealthchecks: map[types.NamespacedName]int{
- makeNSN("ns1", "ep1"): 1,
- },
- }, {
- // Case[3]: no change, multiple subsets
- previousEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", multipleSubsets),
- },
- currentEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", multipleSubsets),
- },
- oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", "p11"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}},
- },
- makeServicePortName("ns1", "ep1", "p12"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: false}},
- },
- },
- expectedResult: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", "p11"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}},
- },
- makeServicePortName("ns1", "ep1", "p12"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: false}},
- },
- },
- expectedStaleEndpoints: []proxy.ServiceEndpoint{},
- expectedStaleServiceNames: map[proxy.ServicePortName]bool{},
- expectedHealthchecks: map[types.NamespacedName]int{},
- }, {
- // Case[4]: no change, multiple subsets, multiple ports, local
- previousEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", multipleSubsetsMultiplePortsLocal),
- },
- currentEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", multipleSubsetsMultiplePortsLocal),
- },
- oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", "p11"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true}},
- },
- makeServicePortName("ns1", "ep1", "p12"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: true}},
- },
- makeServicePortName("ns1", "ep1", "p13"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.3:13", IsLocal: false}},
- },
- },
- expectedResult: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", "p11"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true}},
- },
- makeServicePortName("ns1", "ep1", "p12"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: true}},
- },
- makeServicePortName("ns1", "ep1", "p13"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.3:13", IsLocal: false}},
- },
- },
- expectedStaleEndpoints: []proxy.ServiceEndpoint{},
- expectedStaleServiceNames: map[proxy.ServicePortName]bool{},
- expectedHealthchecks: map[types.NamespacedName]int{
- makeNSN("ns1", "ep1"): 1,
- },
- }, {
- // Case[5]: no change, multiple endpoints, subsets, IPs, and ports
- previousEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", multipleSubsetsIPsPorts1),
- makeTestEndpoints("ns2", "ep2", multipleSubsetsIPsPorts2),
- },
- currentEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", multipleSubsetsIPsPorts1),
- makeTestEndpoints("ns2", "ep2", multipleSubsetsIPsPorts2),
- },
- oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", "p11"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}},
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:11", IsLocal: true}},
- },
- makeServicePortName("ns1", "ep1", "p12"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: false}},
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: true}},
- },
- makeServicePortName("ns1", "ep1", "p13"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.3:13", IsLocal: false}},
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.4:13", IsLocal: true}},
- },
- makeServicePortName("ns1", "ep1", "p14"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.3:14", IsLocal: false}},
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.4:14", IsLocal: true}},
- },
- makeServicePortName("ns2", "ep2", "p21"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.1:21", IsLocal: false}},
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.2:21", IsLocal: true}},
- },
- makeServicePortName("ns2", "ep2", "p22"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.1:22", IsLocal: false}},
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.2:22", IsLocal: true}},
- },
- },
- expectedResult: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", "p11"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}},
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:11", IsLocal: true}},
- },
- makeServicePortName("ns1", "ep1", "p12"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: false}},
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: true}},
- },
- makeServicePortName("ns1", "ep1", "p13"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.3:13", IsLocal: false}},
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.4:13", IsLocal: true}},
- },
- makeServicePortName("ns1", "ep1", "p14"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.3:14", IsLocal: false}},
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.4:14", IsLocal: true}},
- },
- makeServicePortName("ns2", "ep2", "p21"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.1:21", IsLocal: false}},
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.2:21", IsLocal: true}},
- },
- makeServicePortName("ns2", "ep2", "p22"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.1:22", IsLocal: false}},
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.2:22", IsLocal: true}},
- },
- },
- expectedStaleEndpoints: []proxy.ServiceEndpoint{},
- expectedStaleServiceNames: map[proxy.ServicePortName]bool{},
- expectedHealthchecks: map[types.NamespacedName]int{
- makeNSN("ns1", "ep1"): 2,
- makeNSN("ns2", "ep2"): 1,
- },
- }, {
- // Case[6]: add an Endpoints
- previousEndpoints: []*v1.Endpoints{
- nil,
- },
- currentEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", unnamedPortLocal),
- },
- oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{},
- expectedResult: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", ""): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true}},
- },
- },
- expectedStaleEndpoints: []proxy.ServiceEndpoint{},
- expectedStaleServiceNames: map[proxy.ServicePortName]bool{
- makeServicePortName("ns1", "ep1", ""): true,
- },
- expectedHealthchecks: map[types.NamespacedName]int{
- makeNSN("ns1", "ep1"): 1,
- },
- }, {
- // Case[7]: remove an Endpoints
- previousEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", unnamedPortLocal),
- },
- currentEndpoints: []*v1.Endpoints{
- nil,
- },
- oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", ""): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true}},
- },
- },
- expectedResult: map[proxy.ServicePortName][]*endpointsInfo{},
- expectedStaleEndpoints: []proxy.ServiceEndpoint{{
- Endpoint: "1.1.1.1:11",
- ServicePortName: makeServicePortName("ns1", "ep1", ""),
- }},
- expectedStaleServiceNames: map[proxy.ServicePortName]bool{},
- expectedHealthchecks: map[types.NamespacedName]int{},
- }, {
- // Case[8]: add an IP and port
- previousEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", namedPort),
- },
- currentEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", namedPortsLocalNoLocal),
- },
- oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", "p11"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}},
- },
- },
- expectedResult: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", "p11"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}},
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:11", IsLocal: true}},
- },
- makeServicePortName("ns1", "ep1", "p12"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: false}},
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: true}},
- },
- },
- expectedStaleEndpoints: []proxy.ServiceEndpoint{},
- 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
- previousEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", namedPortsLocalNoLocal),
- },
- currentEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", namedPort),
- },
- oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", "p11"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}},
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:11", IsLocal: true}},
- },
- makeServicePortName("ns1", "ep1", "p12"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: false}},
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: true}},
- },
- },
- expectedResult: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", "p11"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}},
- },
- },
- expectedStaleEndpoints: []proxy.ServiceEndpoint{{
- Endpoint: "1.1.1.2:11",
- ServicePortName: makeServicePortName("ns1", "ep1", "p11"),
- }, {
- Endpoint: "1.1.1.1:12",
- ServicePortName: makeServicePortName("ns1", "ep1", "p12"),
- }, {
- Endpoint: "1.1.1.2:12",
- ServicePortName: makeServicePortName("ns1", "ep1", "p12"),
- }},
- expectedStaleServiceNames: map[proxy.ServicePortName]bool{},
- expectedHealthchecks: map[types.NamespacedName]int{},
- }, {
- // Case[10]: add a subset
- previousEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", namedPort),
- },
- currentEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", multipleSubsetsWithLocal),
- },
- oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", "p11"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}},
- },
- },
- expectedResult: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", "p11"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}},
- },
- makeServicePortName("ns1", "ep1", "p12"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: true}},
- },
- },
- expectedStaleEndpoints: []proxy.ServiceEndpoint{},
- expectedStaleServiceNames: map[proxy.ServicePortName]bool{
- makeServicePortName("ns1", "ep1", "p12"): true,
- },
- expectedHealthchecks: map[types.NamespacedName]int{
- makeNSN("ns1", "ep1"): 1,
- },
- }, {
- // Case[11]: remove a subset
- previousEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", multipleSubsets),
- },
- currentEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", namedPort),
- },
- oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", "p11"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}},
- },
- makeServicePortName("ns1", "ep1", "p12"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: false}},
- },
- },
- expectedResult: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", "p11"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}},
- },
- },
- expectedStaleEndpoints: []proxy.ServiceEndpoint{{
- Endpoint: "1.1.1.2:12",
- ServicePortName: makeServicePortName("ns1", "ep1", "p12"),
- }},
- expectedStaleServiceNames: map[proxy.ServicePortName]bool{},
- expectedHealthchecks: map[types.NamespacedName]int{},
- }, {
- // Case[12]: rename a port
- previousEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", namedPort),
- },
- currentEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", namedPortRenamed),
- },
- oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", "p11"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}},
- },
- },
- expectedResult: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", "p11-2"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}},
- },
- },
- expectedStaleEndpoints: []proxy.ServiceEndpoint{{
- Endpoint: "1.1.1.1:11",
- ServicePortName: makeServicePortName("ns1", "ep1", "p11"),
- }},
- expectedStaleServiceNames: map[proxy.ServicePortName]bool{
- makeServicePortName("ns1", "ep1", "p11-2"): true,
- },
- expectedHealthchecks: map[types.NamespacedName]int{},
- }, {
- // Case[13]: renumber a port
- previousEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", namedPort),
- },
- currentEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", namedPortRenumbered),
- },
- oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", "p11"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}},
- },
- },
- expectedResult: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", "p11"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:22", IsLocal: false}},
- },
- },
- expectedStaleEndpoints: []proxy.ServiceEndpoint{{
- Endpoint: "1.1.1.1:11",
- ServicePortName: makeServicePortName("ns1", "ep1", "p11"),
- }},
- expectedStaleServiceNames: map[proxy.ServicePortName]bool{},
- expectedHealthchecks: map[types.NamespacedName]int{},
- }, {
- // Case[14]: complex add and remove
- previousEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", complexBefore1),
- makeTestEndpoints("ns2", "ep2", complexBefore2),
- nil,
- makeTestEndpoints("ns4", "ep4", complexBefore4),
- },
- currentEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", complexAfter1),
- nil,
- makeTestEndpoints("ns3", "ep3", complexAfter3),
- makeTestEndpoints("ns4", "ep4", complexAfter4),
- },
- oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", "p11"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}},
- },
- makeServicePortName("ns2", "ep2", "p22"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.2:22", IsLocal: true}},
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.22:22", IsLocal: true}},
- },
- makeServicePortName("ns2", "ep2", "p23"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.3:23", IsLocal: true}},
- },
- makeServicePortName("ns4", "ep4", "p44"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "4.4.4.4:44", IsLocal: true}},
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "4.4.4.5:44", IsLocal: true}},
- },
- makeServicePortName("ns4", "ep4", "p45"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "4.4.4.6:45", IsLocal: true}},
- },
- },
- expectedResult: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", "p11"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}},
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.11:11", IsLocal: false}},
- },
- makeServicePortName("ns1", "ep1", "p12"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: false}},
- },
- makeServicePortName("ns1", "ep1", "p122"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:122", IsLocal: false}},
- },
- makeServicePortName("ns3", "ep3", "p33"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "3.3.3.3:33", IsLocal: false}},
- },
- makeServicePortName("ns4", "ep4", "p44"): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "4.4.4.4:44", IsLocal: true}},
- },
- },
- expectedStaleEndpoints: []proxy.ServiceEndpoint{{
- Endpoint: "2.2.2.2:22",
- ServicePortName: makeServicePortName("ns2", "ep2", "p22"),
- }, {
- Endpoint: "2.2.2.22:22",
- ServicePortName: makeServicePortName("ns2", "ep2", "p22"),
- }, {
- Endpoint: "2.2.2.3:23",
- ServicePortName: makeServicePortName("ns2", "ep2", "p23"),
- }, {
- Endpoint: "4.4.4.5:44",
- ServicePortName: makeServicePortName("ns4", "ep4", "p44"),
- }, {
- Endpoint: "4.4.4.6:45",
- ServicePortName: makeServicePortName("ns4", "ep4", "p45"),
- }},
- 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,
- },
- }, {
- // Case[15]: change from 0 endpoint address to 1 unnamed port
- previousEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", emptyEndpoint),
- },
- currentEndpoints: []*v1.Endpoints{
- makeTestEndpoints("ns1", "ep1", unnamedPort),
- },
- oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{},
- expectedResult: map[proxy.ServicePortName][]*endpointsInfo{
- makeServicePortName("ns1", "ep1", ""): {
- {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}},
- },
- },
- expectedStaleEndpoints: []proxy.ServiceEndpoint{},
- expectedStaleServiceNames: map[proxy.ServicePortName]bool{
- makeServicePortName("ns1", "ep1", ""): true,
- },
- expectedHealthchecks: map[types.NamespacedName]int{},
- },
- }
- for tci, tc := range testCases {
- ipt := iptablestest.NewFake()
- fp := NewFakeProxier(ipt)
- fp.hostname = nodeName
- // 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])
- }
- }
- fp.endpointsMap.Update(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) {
- 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)
- }
- }
- result := fp.endpointsMap.Update(fp.endpointsChanges)
- newMap := fp.endpointsMap
- compareEndpointsMaps(t, tci, newMap, tc.expectedResult)
- 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)
- }
- for _, x := range tc.expectedStaleEndpoints {
- 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)
- }
- }
- 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)
- }
- for svcName := range tc.expectedStaleServiceNames {
- found := false
- for _, stale := range result.StaleServiceNames {
- if stale == svcName {
- found = true
- }
- }
- if !found {
- t.Errorf("[%d] expected staleServiceNames[%v], but didn't find it: %v", tci, svcName, result.StaleServiceNames)
- }
- }
- if !reflect.DeepEqual(result.HCEndpointsLocalIPSize, tc.expectedHealthchecks) {
- t.Errorf("[%d] expected healthchecks %v, got %v", tci, tc.expectedHealthchecks, result.HCEndpointsLocalIPSize)
- }
- }
- }
- // TODO(thockin): add *more* tests for syncProxyRules() or break it down further and test the pieces.
|