github.com/cilium/cilium@v1.16.2/test/controlplane/services/nodeport/nodeport.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package nodeport 5 6 import ( 7 "fmt" 8 "net" 9 "os" 10 "path" 11 "testing" 12 13 datapathTables "github.com/cilium/cilium/pkg/datapath/tables" 14 lb "github.com/cilium/cilium/pkg/loadbalancer" 15 agentOption "github.com/cilium/cilium/pkg/option" 16 "github.com/cilium/cilium/test/controlplane" 17 "github.com/cilium/cilium/test/controlplane/services/helpers" 18 "github.com/cilium/cilium/test/controlplane/suite" 19 ) 20 21 func init() { 22 suite.AddTestCase("Services/NodePort", func(t *testing.T) { 23 cwd, err := os.Getwd() 24 if err != nil { 25 t.Fatal(err) 26 } 27 28 modConfig := func(cfg *agentOption.DaemonConfig) { 29 cfg.EnableNodePort = true 30 } 31 32 for _, version := range controlplane.K8sVersions() { 33 abs := func(f string) string { return path.Join(cwd, "services", "nodeport", "v"+version, f) } 34 35 // Run the test from each nodes perspective. 36 for _, nodeName := range []string{"nodeport-control-plane", "nodeport-worker", "nodeport-worker2"} { 37 t.Run("v"+version+"/"+nodeName, func(t *testing.T) { 38 test := suite.NewControlPlaneTest(t, nodeName, version) 39 40 // Feed in initial state and start the agent. 41 test. 42 UpdateObjectsFromFile(abs("init.yaml")). 43 SetupEnvironment(). 44 StartAgent(modConfig). 45 EnsureWatchers("endpointslices", "pods", "services"). 46 UpdateObjectsFromFile(abs("state1.yaml")). 47 Eventually(func() error { return validate(test, abs("lbmap1_"+nodeName+".golden")) }). 48 StopAgent(). 49 ClearEnvironment() 50 }) 51 } 52 } 53 }) 54 } 55 56 func validate(test *suite.ControlPlaneTest, goldenFile string) error { 57 if err := helpers.ValidateLBMapGoldenFile(goldenFile, test.Datapath); err != nil { 58 return err 59 } 60 if err := validateExternalTrafficPolicyLocal(test); err != nil { 61 return err 62 } 63 return nil 64 } 65 66 func validateExternalTrafficPolicyLocal(test *suite.ControlPlaneTest) error { 67 dp := test.Datapath 68 lbmap := dp.LBMockMap() 69 lbmap.Lock() 70 defer lbmap.Unlock() 71 72 // Collect all echo-local services with internal ("local") scope. 73 localServices := []*lb.SVC{} 74 for _, svc := range dp.LBMockMap().ServiceByID { 75 if svc.Name.Name == "echo-local" && svc.Frontend.Scope == lb.ScopeInternal { 76 localServices = append(localServices, svc) 77 } 78 } 79 80 expectedFrontendIPs := map[string]bool{} 81 82 db, nodeAddrs := test.AgentDB() 83 iter := nodeAddrs.List(db.ReadTxn(), datapathTables.NodeAddressNodePortIndex.Query(true)) 84 for addr, _, ok := iter.Next(); ok; addr, _, ok = iter.Next() { 85 if addr.NodePort && addr.Addr.Is4() { 86 expectedFrontendIPs[addr.Addr.String()] = true 87 } 88 } 89 expectedFrontendIPs[net.IPv4zero.String()] = true 90 91 // Check that all expected service entries exist with the expected frontends. 92 for _, svc := range localServices { 93 ip := svc.Frontend.AddrCluster.String() 94 if _, ok := expectedFrontendIPs[ip]; !ok { 95 return fmt.Errorf("unexpected frontend IP %q for service %s, expected one of %v", ip, svc.Name, expectedFrontendIPs) 96 } 97 delete(expectedFrontendIPs, ip) 98 if len(svc.Backends) != 1 { 99 return fmt.Errorf("missing backend for %s, expected 1, got %d", svc.Name, len(svc.Backends)) 100 } 101 } 102 if len(expectedFrontendIPs) > 0 { 103 return fmt.Errorf("missing services for frontends: %v", expectedFrontendIPs) 104 } 105 106 return nil 107 }