mirror of
https://github.com/cloudnativelabs/kube-router.git
synced 2025-10-04 14:31:03 +02:00
* Makefile: Add lint using golangci-lint * build/travis-test.sh: Run lint step * metrics_controller: Lint pkg/metrics/metrics_controller.go:150:2: `mu` is unused (structcheck) mu sync.Mutex ^ pkg/metrics/metrics_controller.go:151:2: `nodeIP` is unused (structcheck) nodeIP net.IP ^ * network_service_graceful: Lint pkg/controllers/proxy/network_service_graceful.go:21:6: `gracefulQueueItem` is unused (deadcode) type gracefulQueueItem struct { ^ pkg/controllers/proxy/network_service_graceful.go:22:2: `added` is unused (structcheck) added time.Time ^ pkg/controllers/proxy/network_service_graceful.go:23:2: `service` is unused (structcheck) service *ipvs.Service ^ * network_services_controller_test: Lint pkg/controllers/proxy/network_services_controller_test.go:80:6: func `logf` is unused (unused) * ecmp_vip: Lint pkg/controllers/routing/ecmp_vip.go:208:4: S1023: redundant `return` statement (gosimple) return ^ * bgp_peers: Lint pkg/controllers/routing/bgp_peers.go:331:4: S1023: redundant `return` statement (gosimple) return ^ * bgp_policies: Lint pkg/controllers/routing/bgp_policies.go:80:3: S1011: should replace loop with `externalBgpPeers = append(externalBgpPeers, nrc.nodePeerRouters...)` (gosimple) for _, peer := range nrc.nodePeerRouters { ^ pkg/controllers/routing/bgp_policies.go:23:20: ineffectual assignment to `err` (ineffassign) podCidrPrefixSet, err := table.NewPrefixSet(config.PrefixSet{ ^ pkg/controllers/routing/bgp_policies.go:42:22: ineffectual assignment to `err` (ineffassign) clusterIPPrefixSet, err := table.NewPrefixSet(config.PrefixSet{ ^ pkg/controllers/routing/bgp_policies.go:33:30: Error return value of `nrc.bgpServer.AddDefinedSet` is not checked (errcheck) nrc.bgpServer.AddDefinedSet(podCidrPrefixSet) ^ pkg/controllers/routing/bgp_policies.go:48:30: Error return value of `nrc.bgpServer.AddDefinedSet` is not checked (errcheck) nrc.bgpServer.AddDefinedSet(clusterIPPrefixSet) ^ pkg/controllers/routing/bgp_policies.go:69:31: Error return value of `nrc.bgpServer.AddDefinedSet` is not checked (errcheck) nrc.bgpServer.AddDefinedSet(iBGPPeerNS) ^ pkg/controllers/routing/bgp_policies.go:108:31: Error return value of `nrc.bgpServer.AddDefinedSet` is not checked (errcheck) nrc.bgpServer.AddDefinedSet(ns) ^ pkg/controllers/routing/bgp_policies.go:120:30: Error return value of `nrc.bgpServer.AddDefinedSet` is not checked (errcheck) nrc.bgpServer.AddDefinedSet(ns) ^ ^ * network_policy_controller: Lint pkg/controllers/netpol/network_policy_controller.go:35:2: `networkPolicyAnnotation` is unused (deadcode) networkPolicyAnnotation = "net.beta.kubernetes.io/network-policy" ^ pkg/controllers/netpol/network_policy_controller.go:1047:4: SA9003: empty branch (staticcheck) if err != nil { ^ pkg/controllers/netpol/network_policy_controller.go:969:10: SA4006: this value of `err` is never used (staticcheck) chains, err := iptablesCmdHandler.ListChains("filter") ^ pkg/controllers/netpol/network_policy_controller.go:1568:4: SA4006: this value of `err` is never used (staticcheck) err = iptablesCmdHandler.Delete("filter", "FORWARD", strconv.Itoa(i-realRuleNo)) ^ pkg/controllers/netpol/network_policy_controller.go:1584:4: SA4006: this value of `err` is never used (staticcheck) err = iptablesCmdHandler.Delete("filter", "OUTPUT", strconv.Itoa(i-realRuleNo)) ^ * network_services_controller: Lint pkg/controllers/proxy/network_services_controller.go:66:2: `h` is unused (deadcode) h *ipvs.Handle ^ pkg/controllers/proxy/network_services_controller.go:879:23: SA1019: client.NewEnvClient is deprecated: use NewClientWithOpts(FromEnv) (staticcheck) dockerClient, err := client.NewEnvClient() ^ pkg/controllers/proxy/network_services_controller.go:944:5: unreachable: unreachable code (govet) glog.V(3).Infof("Waiting for tunnel interface %s to come up in the pod, retrying", KUBE_TUNNEL_IF) ^ pkg/controllers/proxy/network_services_controller.go:1289:5: S1002: should omit comparison to bool constant, can be simplified to `!hasHairpinChain` (gosimple) if hasHairpinChain != true { ^ pkg/controllers/proxy/network_services_controller.go:1237:43: S1019: should use make(map[string][]string) instead (gosimple) rulesNeeded := make(map[string][]string, 0) ^ pkg/controllers/proxy/network_services_controller.go:1111:4: S1023: redundant break statement (gosimple) break ^ pkg/controllers/proxy/network_services_controller.go:1114:4: S1023: redundant break statement (gosimple) break ^ pkg/controllers/proxy/network_services_controller.go:1117:4: S1023: redundant break statement (gosimple) break ^ pkg/controllers/proxy/network_services_controller.go:445:21: Error return value of `nsc.publishMetrics` is not checked (errcheck) nsc.publishMetrics(nsc.serviceMap) ^ pkg/controllers/proxy/network_services_controller.go:1609:9: Error return value of `h.Write` is not checked (errcheck) h.Write([]byte(ip + "-" + protocol + "-" + port)) ^ pkg/controllers/proxy/network_services_controller.go:912:13: Error return value of `netns.Set` is not checked (errcheck) netns.Set(hostNetworkNamespaceHandle) ^ pkg/controllers/proxy/network_services_controller.go:926:13: Error return value of `netns.Set` is not checked (errcheck) netns.Set(hostNetworkNamespaceHandle) ^ pkg/controllers/proxy/network_services_controller.go:950:13: Error return value of `netns.Set` is not checked (errcheck) netns.Set(hostNetworkNamespaceHandle) ^ pkg/controllers/proxy/network_services_controller.go:641:9: SA4006: this value of `err` is never used (staticcheck) addrs, err := getAllLocalIPs() ^ * network_routes_controller: Lint pkg/controllers/routing/network_routes_controller.go:340:2: S1000: should use for range instead of for { select {} } (gosimple) for { ^ pkg/controllers/routing/network_routes_controller.go:757:22: Error return value of `nrc.bgpServer.Stop` is not checked (errcheck) nrc.bgpServer.Stop() ^ pkg/controllers/routing/network_routes_controller.go:770:22: Error return value of `nrc.bgpServer.Stop` is not checked (errcheck) nrc.bgpServer.Stop() ^ pkg/controllers/routing/network_routes_controller.go:782:23: Error return value of `nrc.bgpServer.Stop` is not checked (errcheck) nrc.bgpServer.Stop() ^ pkg/controllers/routing/network_routes_controller.go:717:12: Error return value of `g.Serve` is not checked (errcheck) go g.Serve() * ipset: Lint pkg/utils/ipset.go:243:23: Error return value of `entry.Set.Parent.Save` is not checked (errcheck) entry.Set.Parent.Save() ^ * pkg/cmd/kube-router: Lint pkg/cmd/kube-router.go:214:26: SA1006: printf-style function with dynamic format string and no further arguments should use print-style function instead (staticcheck) fmt.Fprintf(os.Stderr, output) ^ pkg/cmd/kube-router.go:184:15: SA1017: the channel used with signal.Notify should be buffered (staticcheck) signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM) ^ pkg/cmd/kube-router.go:94:17: Error return value of `hc.RunServer` is not checked (errcheck) go hc.RunServer(stopCh, &wg) ^ pkg/cmd/kube-router.go:112:16: Error return value of `hc.RunCheck` is not checked (errcheck) go hc.RunCheck(healthChan, stopCh, &wg) ^ pkg/cmd/kube-router.go:121:12: Error return value of `mc.Run` is not checked (errcheck) go mc.Run(healthChan, stopCh, &wg) ^ * cmd/kube-router/kube-router: Lint cmd/kube-router/kube-router.go:31:24: Error return value of `flag.CommandLine.Parse` is not checked (errcheck) flag.CommandLine.Parse([]string{}) ^ cmd/kube-router/kube-router.go:33:10: Error return value of `flag.Set` is not checked (errcheck) flag.Set("logtostderr", "true") ^ cmd/kube-router/kube-router.go:34:10: Error return value of `flag.Set` is not checked (errcheck) flag.Set("v", config.VLevel) ^ cmd/kube-router/kube-router.go:62:27: SA1006: printf-style function with dynamic format string and no further arguments should use print-style function instead (staticcheck) fmt.Fprintf(os.Stdout, http.ListenAndServe("0.0.0.0:6060", nil).Error()) ^ * kube-router_test: Lint cmd/kube-router/kube-router_test.go:21:10: Error return value of `io.Copy` is not checked (errcheck) io.Copy(stderrBuf, stderrR) ^ cmd/kube-router/kube-router_test.go:40:17: Error return value of `docBuf.ReadFrom` is not checked (errcheck) docBuf.ReadFrom(docF) ^ * service_endpoints_sync: Lint pkg/controllers/proxy/service_endpoints_sync.go:460:2: ineffectual assignment to `ipvsSvcs` (ineffassign) ipvsSvcs, err := nsc.ln.ipvsGetServices() ^ pkg/controllers/proxy/service_endpoints_sync.go:311:5: SA4006: this value of `err` is never used (staticcheck) err = nsc.ln.ipAddrDel(dummyVipInterface, externalIP) ^ * node: Lint pkg/utils/node.go:19:16: SA1019: clientset.Core is deprecated: please explicitly pick a version if possible. (staticcheck) node, err := clientset.Core().Nodes().Get(nodeName, metav1.GetOptions{}) ^ pkg/utils/node.go:27:15: SA1019: clientset.Core is deprecated: please explicitly pick a version if possible. (staticcheck) node, err := clientset.Core().Nodes().Get(hostName, metav1.GetOptions{}) ^ pkg/utils/node.go:34:15: SA1019: clientset.Core is deprecated: please explicitly pick a version if possible. (staticcheck) node, err = clientset.Core().Nodes().Get(hostnameOverride, metav1.GetOptions{}) ^ * aws: Lint pkg/controllers/routing/aws.go:31:8: SA4006: this value of `err` is never used (staticcheck) URL, err := url.Parse(providerID) ^ * health_controller: Lint pkg/healthcheck/health_controller.go:54:10: Error return value of `w.Write` is not checked (errcheck) w.Write([]byte("OK\n")) ^ pkg/healthcheck/health_controller.go:68:10: Error return value of `w.Write` is not checked (errcheck) w.Write([]byte("Unhealthy")) ^ pkg/healthcheck/health_controller.go:159:2: S1000: should use a simple channel send/receive instead of `select` with a single case (gosimple) select { ^ * network_routes_controller_test: Lint pkg/controllers/routing/network_routes_controller_test.go:1113:37: Error return value of `testcase.nrc.bgpServer.Stop` is not checked (errcheck) defer testcase.nrc.bgpServer.Stop() ^ pkg/controllers/routing/network_routes_controller_test.go:1314:37: Error return value of `testcase.nrc.bgpServer.Stop` is not checked (errcheck) defer testcase.nrc.bgpServer.Stop() ^ pkg/controllers/routing/network_routes_controller_test.go:2327:37: Error return value of `testcase.nrc.bgpServer.Stop` is not checked (errcheck) defer testcase.nrc.bgpServer.Stop() ^ * .golangci.yml: Increase timeout Default is 1m, increase to 5m otherwise travis might fail * Makefile: Update golangci-lint to 1.27.0 * kube-router_test.go: defer waitgroup Co-authored-by: Aaron U'Ren <aauren@users.noreply.github.com> * network_routes_controller: Incorporate review * bgp_policies: Incorporate review * network_routes_controller: Incorporate review * bgp_policies: Log error instead * network_services_controller: Incorporate review Co-authored-by: Aaron U'Ren <aauren@users.noreply.github.com>
2568 lines
64 KiB
Go
2568 lines
64 KiB
Go
package routing
|
|
|
|
import (
|
|
"net"
|
|
"os"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/osrg/gobgp/config"
|
|
gobgp "github.com/osrg/gobgp/server"
|
|
"github.com/osrg/gobgp/table"
|
|
|
|
v1core "k8s.io/api/core/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/client-go/informers"
|
|
"k8s.io/client-go/kubernetes"
|
|
"k8s.io/client-go/kubernetes/fake"
|
|
"k8s.io/client-go/tools/cache"
|
|
)
|
|
|
|
func Test_advertiseClusterIPs(t *testing.T) {
|
|
testcases := []struct {
|
|
name string
|
|
nrc *NetworkRoutingController
|
|
existingServices []*v1core.Service
|
|
// the key is the subnet from the watch event
|
|
watchEvents map[string]bool
|
|
}{
|
|
{
|
|
"add bgp path for service with ClusterIP",
|
|
&NetworkRoutingController{
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
},
|
|
[]*v1core.Service{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "ClusterIP",
|
|
ClusterIP: "10.0.0.1",
|
|
},
|
|
},
|
|
},
|
|
map[string]bool{
|
|
"10.0.0.1/32": true,
|
|
},
|
|
},
|
|
{
|
|
"add bgp path for service with ClusterIP/NodePort/LoadBalancer",
|
|
&NetworkRoutingController{
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
},
|
|
[]*v1core.Service{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "ClusterIP",
|
|
ClusterIP: "10.0.0.1",
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-2",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "LoadBalancer",
|
|
ClusterIP: "10.0.0.2",
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-3",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "NodePort",
|
|
ClusterIP: "10.0.0.3",
|
|
},
|
|
},
|
|
},
|
|
map[string]bool{
|
|
"10.0.0.1/32": true,
|
|
"10.0.0.2/32": true,
|
|
"10.0.0.3/32": true,
|
|
},
|
|
},
|
|
{
|
|
"add bgp path for invalid service type",
|
|
&NetworkRoutingController{
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
},
|
|
[]*v1core.Service{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "ClusterIP",
|
|
ClusterIP: "10.0.0.1",
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-2",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "AnotherType",
|
|
ClusterIP: "10.0.0.2",
|
|
},
|
|
},
|
|
},
|
|
map[string]bool{
|
|
"10.0.0.1/32": true,
|
|
},
|
|
},
|
|
{
|
|
"add bgp path for headless service",
|
|
&NetworkRoutingController{
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
},
|
|
[]*v1core.Service{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "ClusterIP",
|
|
ClusterIP: "10.0.0.1",
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-2",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "ClusterIP",
|
|
ClusterIP: "None",
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-3",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "ClusterIP",
|
|
ClusterIP: "",
|
|
},
|
|
},
|
|
},
|
|
map[string]bool{
|
|
"10.0.0.1/32": true,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, testcase := range testcases {
|
|
t.Run(testcase.name, func(t *testing.T) {
|
|
go testcase.nrc.bgpServer.Serve()
|
|
err := testcase.nrc.bgpServer.Start(&config.Global{
|
|
Config: config.GlobalConfig{
|
|
As: 1,
|
|
RouterId: "10.0.0.0",
|
|
Port: 10000,
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("failed to start BGP server: %v", err)
|
|
}
|
|
defer func() {
|
|
if err := testcase.nrc.bgpServer.Stop(); err != nil {
|
|
t.Fatalf("failed to stop BGP server : %s", err)
|
|
}
|
|
}()
|
|
w := testcase.nrc.bgpServer.Watch(gobgp.WatchBestPath(false))
|
|
|
|
clientset := fake.NewSimpleClientset()
|
|
startInformersForRoutes(testcase.nrc, clientset)
|
|
|
|
err = createServices(clientset, testcase.existingServices)
|
|
if err != nil {
|
|
t.Fatalf("failed to create existing services: %v", err)
|
|
}
|
|
|
|
waitForListerWithTimeout(testcase.nrc.svcLister, time.Second*10, t)
|
|
|
|
// ClusterIPs
|
|
testcase.nrc.advertiseClusterIP = true
|
|
testcase.nrc.advertiseExternalIP = false
|
|
testcase.nrc.advertiseLoadBalancerIP = false
|
|
|
|
toAdvertise, toWithdraw, _ := testcase.nrc.getActiveVIPs()
|
|
testcase.nrc.advertiseVIPs(toAdvertise)
|
|
testcase.nrc.withdrawVIPs(toWithdraw)
|
|
|
|
watchEvents := waitForBGPWatchEventWithTimeout(time.Second*10, len(testcase.watchEvents), w, t)
|
|
for _, watchEvent := range watchEvents {
|
|
for _, path := range watchEvent.PathList {
|
|
if _, ok := testcase.watchEvents[path.GetNlri().String()]; ok {
|
|
continue
|
|
} else {
|
|
t.Errorf("got unexpected path: %v", path.GetNlri().String())
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_advertiseExternalIPs(t *testing.T) {
|
|
testcases := []struct {
|
|
name string
|
|
nrc *NetworkRoutingController
|
|
existingServices []*v1core.Service
|
|
// the key is the subnet from the watch event
|
|
watchEvents map[string]bool
|
|
}{
|
|
{
|
|
"add bgp path for service with external IPs",
|
|
&NetworkRoutingController{
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
},
|
|
[]*v1core.Service{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "ClusterIP",
|
|
ClusterIP: "10.0.0.1",
|
|
ExternalIPs: []string{"1.1.1.1", "2.2.2.2"},
|
|
},
|
|
},
|
|
},
|
|
map[string]bool{
|
|
"1.1.1.1/32": true,
|
|
"2.2.2.2/32": true,
|
|
},
|
|
},
|
|
{
|
|
"add bgp path for services with external IPs of type ClusterIP/NodePort/LoadBalancer",
|
|
&NetworkRoutingController{
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
},
|
|
[]*v1core.Service{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "ClusterIP",
|
|
ClusterIP: "10.0.0.1",
|
|
ExternalIPs: []string{"1.1.1.1"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-2",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "LoadBalancer",
|
|
ClusterIP: "10.0.0.2",
|
|
// ignored since LoadBalancer services don't
|
|
// advertise external IPs.
|
|
ExternalIPs: []string{"2.2.2.2"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-3",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "NodePort",
|
|
ClusterIP: "10.0.0.3",
|
|
ExternalIPs: []string{"3.3.3.3", "4.4.4.4"},
|
|
},
|
|
},
|
|
},
|
|
map[string]bool{
|
|
"1.1.1.1/32": true,
|
|
"3.3.3.3/32": true,
|
|
"4.4.4.4/32": true,
|
|
},
|
|
},
|
|
{
|
|
"add bgp path for invalid service type",
|
|
&NetworkRoutingController{
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
},
|
|
[]*v1core.Service{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "ClusterIP",
|
|
ClusterIP: "10.0.0.1",
|
|
ExternalIPs: []string{"1.1.1.1"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-2",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "AnotherType",
|
|
ClusterIP: "10.0.0.2",
|
|
ExternalIPs: []string{"2.2.2.2"},
|
|
},
|
|
},
|
|
},
|
|
map[string]bool{
|
|
"1.1.1.1/32": true,
|
|
},
|
|
},
|
|
{
|
|
"add bgp path for headless service",
|
|
&NetworkRoutingController{
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
},
|
|
[]*v1core.Service{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "ClusterIP",
|
|
ClusterIP: "10.0.0.1",
|
|
ExternalIPs: []string{"1.1.1.1"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-2",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "ClusterIP",
|
|
ClusterIP: "None",
|
|
ExternalIPs: []string{"2.2.2.2"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-3",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "ClusterIP",
|
|
ClusterIP: "",
|
|
ExternalIPs: []string{"3.3.3.3"},
|
|
},
|
|
},
|
|
},
|
|
map[string]bool{
|
|
"1.1.1.1/32": true,
|
|
},
|
|
},
|
|
{
|
|
"skip bgp path to loadbalancerIP for service without LoadBalancer IP",
|
|
&NetworkRoutingController{
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
},
|
|
[]*v1core.Service{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "LoadBalancer",
|
|
ClusterIP: "10.0.0.1",
|
|
},
|
|
Status: v1core.ServiceStatus{
|
|
LoadBalancer: v1core.LoadBalancerStatus{
|
|
Ingress: []v1core.LoadBalancerIngress{
|
|
{
|
|
Hostname: "foo-bar.zone.elb.example.com",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
map[string]bool{},
|
|
},
|
|
{
|
|
"add bgp path to loadbalancerIP for service with LoadBalancer IP",
|
|
&NetworkRoutingController{
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
},
|
|
[]*v1core.Service{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "LoadBalancer",
|
|
ClusterIP: "10.0.0.1",
|
|
},
|
|
Status: v1core.ServiceStatus{
|
|
LoadBalancer: v1core.LoadBalancerStatus{
|
|
Ingress: []v1core.LoadBalancerIngress{
|
|
{
|
|
IP: "10.0.255.1",
|
|
},
|
|
{
|
|
IP: "10.0.255.2",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
map[string]bool{
|
|
"10.0.255.1/32": true,
|
|
"10.0.255.2/32": true,
|
|
},
|
|
},
|
|
{
|
|
"no bgp path to nil loadbalancerIPs for service with LoadBalancer",
|
|
&NetworkRoutingController{
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
},
|
|
[]*v1core.Service{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "LoadBalancer",
|
|
ClusterIP: "10.0.0.1",
|
|
},
|
|
Status: v1core.ServiceStatus{
|
|
LoadBalancer: v1core.LoadBalancerStatus{
|
|
Ingress: []v1core.LoadBalancerIngress{},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
map[string]bool{},
|
|
},
|
|
{
|
|
"no bgp path to loadbalancerIPs for service with LoadBalancer and skiplbips annotation",
|
|
&NetworkRoutingController{
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
},
|
|
[]*v1core.Service{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
Annotations: map[string]string{
|
|
svcSkipLbIpsAnnotation: "true",
|
|
},
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "LoadBalancer",
|
|
ClusterIP: "10.0.0.1",
|
|
},
|
|
Status: v1core.ServiceStatus{
|
|
LoadBalancer: v1core.LoadBalancerStatus{
|
|
Ingress: []v1core.LoadBalancerIngress{
|
|
{
|
|
IP: "10.0.255.1",
|
|
},
|
|
{
|
|
IP: "10.0.255.2",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
map[string]bool{},
|
|
},
|
|
}
|
|
|
|
for _, testcase := range testcases {
|
|
t.Run(testcase.name, func(t *testing.T) {
|
|
go testcase.nrc.bgpServer.Serve()
|
|
err := testcase.nrc.bgpServer.Start(&config.Global{
|
|
Config: config.GlobalConfig{
|
|
As: 1,
|
|
RouterId: "10.0.0.0",
|
|
Port: 10000,
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("failed to start BGP server: %v", err)
|
|
}
|
|
defer func() {
|
|
if err := testcase.nrc.bgpServer.Stop(); err != nil {
|
|
t.Fatalf("failed to stop BGP server : %s", err)
|
|
}
|
|
}()
|
|
|
|
w := testcase.nrc.bgpServer.Watch(gobgp.WatchBestPath(false))
|
|
|
|
clientset := fake.NewSimpleClientset()
|
|
startInformersForRoutes(testcase.nrc, clientset)
|
|
|
|
err = createServices(clientset, testcase.existingServices)
|
|
if err != nil {
|
|
t.Fatalf("failed to create existing services: %v", err)
|
|
}
|
|
|
|
waitForListerWithTimeout(testcase.nrc.svcLister, time.Second*10, t)
|
|
|
|
// ExternalIPs
|
|
testcase.nrc.advertiseClusterIP = false
|
|
testcase.nrc.advertiseExternalIP = true
|
|
testcase.nrc.advertiseLoadBalancerIP = true
|
|
|
|
toAdvertise, toWithdraw, _ := testcase.nrc.getActiveVIPs()
|
|
testcase.nrc.advertiseVIPs(toAdvertise)
|
|
testcase.nrc.withdrawVIPs(toWithdraw)
|
|
|
|
watchEvents := waitForBGPWatchEventWithTimeout(time.Second*10, len(testcase.watchEvents), w, t)
|
|
for _, watchEvent := range watchEvents {
|
|
for _, path := range watchEvent.PathList {
|
|
if _, ok := testcase.watchEvents[path.GetNlri().String()]; ok {
|
|
continue
|
|
} else {
|
|
t.Errorf("got unexpected path: %v", path.GetNlri().String())
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_advertiseAnnotationOptOut(t *testing.T) {
|
|
testcases := []struct {
|
|
name string
|
|
nrc *NetworkRoutingController
|
|
existingServices []*v1core.Service
|
|
// the key is the subnet from the watch event
|
|
watchEvents map[string]bool
|
|
}{
|
|
{
|
|
"add bgp paths for all service IPs",
|
|
&NetworkRoutingController{
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
},
|
|
[]*v1core.Service{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "ClusterIP",
|
|
ClusterIP: "10.0.0.1",
|
|
ExternalIPs: []string{"1.1.1.1"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-2",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "NodePort",
|
|
ClusterIP: "10.0.0.2",
|
|
ExternalIPs: []string{"2.2.2.2", "3.3.3.3"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-3",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "LoadBalancer",
|
|
ClusterIP: "10.0.0.3",
|
|
// ignored since LoadBalancer services don't
|
|
// advertise external IPs.
|
|
ExternalIPs: []string{"4.4.4.4"},
|
|
},
|
|
Status: v1core.ServiceStatus{
|
|
LoadBalancer: v1core.LoadBalancerStatus{
|
|
Ingress: []v1core.LoadBalancerIngress{
|
|
{
|
|
IP: "10.0.255.1",
|
|
},
|
|
{
|
|
IP: "10.0.255.2",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
map[string]bool{
|
|
"10.0.0.1/32": true,
|
|
"10.0.0.2/32": true,
|
|
"10.0.0.3/32": true,
|
|
"1.1.1.1/32": true,
|
|
"2.2.2.2/32": true,
|
|
"3.3.3.3/32": true,
|
|
"10.0.255.1/32": true,
|
|
"10.0.255.2/32": true,
|
|
},
|
|
},
|
|
{
|
|
"opt out to advertise any IPs via annotations",
|
|
&NetworkRoutingController{
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
},
|
|
[]*v1core.Service{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
Annotations: map[string]string{
|
|
svcAdvertiseClusterAnnotation: "false",
|
|
svcAdvertiseExternalAnnotation: "false",
|
|
svcAdvertiseLoadBalancerAnnotation: "false",
|
|
},
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "LoadBalancer",
|
|
ClusterIP: "10.0.0.1",
|
|
ExternalIPs: []string{"1.1.1.1", "2.2.2.2"},
|
|
},
|
|
Status: v1core.ServiceStatus{
|
|
LoadBalancer: v1core.LoadBalancerStatus{
|
|
Ingress: []v1core.LoadBalancerIngress{
|
|
{
|
|
IP: "10.0.255.1",
|
|
},
|
|
{
|
|
IP: "10.0.255.2",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
map[string]bool{},
|
|
},
|
|
}
|
|
|
|
for _, testcase := range testcases {
|
|
t.Run(testcase.name, func(t *testing.T) {
|
|
go testcase.nrc.bgpServer.Serve()
|
|
err := testcase.nrc.bgpServer.Start(&config.Global{
|
|
Config: config.GlobalConfig{
|
|
As: 1,
|
|
RouterId: "10.0.0.0",
|
|
Port: 10000,
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("failed to start BGP server: %v", err)
|
|
}
|
|
defer func() {
|
|
if err := testcase.nrc.bgpServer.Stop(); err != nil {
|
|
t.Fatalf("failed to stop BGP server : %s", err)
|
|
}
|
|
}()
|
|
|
|
w := testcase.nrc.bgpServer.Watch(gobgp.WatchBestPath(false))
|
|
|
|
clientset := fake.NewSimpleClientset()
|
|
startInformersForRoutes(testcase.nrc, clientset)
|
|
|
|
err = createServices(clientset, testcase.existingServices)
|
|
if err != nil {
|
|
t.Fatalf("failed to create existing services: %v", err)
|
|
}
|
|
|
|
waitForListerWithTimeout(testcase.nrc.svcLister, time.Second*10, t)
|
|
|
|
// By default advertise all IPs
|
|
testcase.nrc.advertiseClusterIP = true
|
|
testcase.nrc.advertiseExternalIP = true
|
|
testcase.nrc.advertiseLoadBalancerIP = true
|
|
|
|
toAdvertise, toWithdraw, _ := testcase.nrc.getActiveVIPs()
|
|
testcase.nrc.advertiseVIPs(toAdvertise)
|
|
testcase.nrc.withdrawVIPs(toWithdraw)
|
|
|
|
watchEvents := waitForBGPWatchEventWithTimeout(time.Second*10, len(testcase.watchEvents), w, t)
|
|
for _, watchEvent := range watchEvents {
|
|
for _, path := range watchEvent.PathList {
|
|
if _, ok := testcase.watchEvents[path.GetNlri().String()]; ok {
|
|
continue
|
|
} else {
|
|
t.Errorf("got unexpected path: %v", path.GetNlri().String())
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_advertiseAnnotationOptIn(t *testing.T) {
|
|
testcases := []struct {
|
|
name string
|
|
nrc *NetworkRoutingController
|
|
existingServices []*v1core.Service
|
|
// the key is the subnet from the watch event
|
|
watchEvents map[string]bool
|
|
}{
|
|
{
|
|
"no bgp paths for any service IPs",
|
|
&NetworkRoutingController{
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
},
|
|
[]*v1core.Service{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "ClusterIP",
|
|
ClusterIP: "10.0.0.1",
|
|
ExternalIPs: []string{"1.1.1.1"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-2",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "NodePort",
|
|
ClusterIP: "10.0.0.2",
|
|
ExternalIPs: []string{"2.2.2.2", "3.3.3.3"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-3",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "LoadBalancer",
|
|
ClusterIP: "10.0.0.3",
|
|
// ignored since LoadBalancer services don't
|
|
// advertise external IPs.
|
|
ExternalIPs: []string{"4.4.4.4"},
|
|
},
|
|
Status: v1core.ServiceStatus{
|
|
LoadBalancer: v1core.LoadBalancerStatus{
|
|
Ingress: []v1core.LoadBalancerIngress{
|
|
{
|
|
IP: "10.0.255.1",
|
|
},
|
|
{
|
|
IP: "10.0.255.2",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
map[string]bool{},
|
|
},
|
|
{
|
|
"opt in to advertise all IPs via annotations",
|
|
&NetworkRoutingController{
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
},
|
|
[]*v1core.Service{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
Annotations: map[string]string{
|
|
svcAdvertiseClusterAnnotation: "true",
|
|
svcAdvertiseExternalAnnotation: "true",
|
|
svcAdvertiseLoadBalancerAnnotation: "true",
|
|
},
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "ClusterIP",
|
|
ClusterIP: "10.0.0.1",
|
|
ExternalIPs: []string{"1.1.1.1"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-2",
|
|
Annotations: map[string]string{
|
|
svcAdvertiseClusterAnnotation: "true",
|
|
svcAdvertiseExternalAnnotation: "true",
|
|
svcAdvertiseLoadBalancerAnnotation: "true",
|
|
},
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "NodePort",
|
|
ClusterIP: "10.0.0.2",
|
|
ExternalIPs: []string{"2.2.2.2", "3.3.3.3"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-3",
|
|
Annotations: map[string]string{
|
|
svcAdvertiseClusterAnnotation: "true",
|
|
svcAdvertiseExternalAnnotation: "true",
|
|
svcAdvertiseLoadBalancerAnnotation: "true",
|
|
},
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "LoadBalancer",
|
|
ClusterIP: "10.0.0.3",
|
|
// ignored since LoadBalancer services don't
|
|
// advertise external IPs.
|
|
ExternalIPs: []string{"4.4.4.4"},
|
|
},
|
|
Status: v1core.ServiceStatus{
|
|
LoadBalancer: v1core.LoadBalancerStatus{
|
|
Ingress: []v1core.LoadBalancerIngress{
|
|
{
|
|
IP: "10.0.255.1",
|
|
},
|
|
{
|
|
IP: "10.0.255.2",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
map[string]bool{
|
|
"10.0.0.1/32": true,
|
|
"10.0.0.2/32": true,
|
|
"10.0.0.3/32": true,
|
|
"1.1.1.1/32": true,
|
|
"2.2.2.2/32": true,
|
|
"3.3.3.3/32": true,
|
|
"10.0.255.1/32": true,
|
|
"10.0.255.2/32": true,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, testcase := range testcases {
|
|
t.Run(testcase.name, func(t *testing.T) {
|
|
go testcase.nrc.bgpServer.Serve()
|
|
err := testcase.nrc.bgpServer.Start(&config.Global{
|
|
Config: config.GlobalConfig{
|
|
As: 1,
|
|
RouterId: "10.0.0.0",
|
|
Port: 10000,
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("failed to start BGP server: %v", err)
|
|
}
|
|
defer func() {
|
|
if err := testcase.nrc.bgpServer.Stop(); err != nil {
|
|
t.Fatalf("failed to stop BGP server : %s", err)
|
|
}
|
|
}()
|
|
|
|
w := testcase.nrc.bgpServer.Watch(gobgp.WatchBestPath(false))
|
|
|
|
clientset := fake.NewSimpleClientset()
|
|
startInformersForRoutes(testcase.nrc, clientset)
|
|
|
|
err = createServices(clientset, testcase.existingServices)
|
|
if err != nil {
|
|
t.Fatalf("failed to create existing services: %v", err)
|
|
}
|
|
|
|
waitForListerWithTimeout(testcase.nrc.svcLister, time.Second*10, t)
|
|
|
|
// By default do not advertise any IPs
|
|
testcase.nrc.advertiseClusterIP = false
|
|
testcase.nrc.advertiseExternalIP = false
|
|
testcase.nrc.advertiseLoadBalancerIP = false
|
|
|
|
toAdvertise, toWithdraw, _ := testcase.nrc.getActiveVIPs()
|
|
testcase.nrc.advertiseVIPs(toAdvertise)
|
|
testcase.nrc.withdrawVIPs(toWithdraw)
|
|
|
|
watchEvents := waitForBGPWatchEventWithTimeout(time.Second*10, len(testcase.watchEvents), w, t)
|
|
for _, watchEvent := range watchEvents {
|
|
for _, path := range watchEvent.PathList {
|
|
if _, ok := testcase.watchEvents[path.GetNlri().String()]; ok {
|
|
continue
|
|
} else {
|
|
t.Errorf("got unexpected path: %v", path.GetNlri().String())
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_nodeHasEndpointsForService(t *testing.T) {
|
|
testcases := []struct {
|
|
name string
|
|
nrc *NetworkRoutingController
|
|
existingService *v1core.Service
|
|
existingEndpoint *v1core.Endpoints
|
|
nodeHasEndpoints bool
|
|
err error
|
|
}{
|
|
{
|
|
"node has endpoints for service",
|
|
&NetworkRoutingController{
|
|
nodeName: "node-1",
|
|
},
|
|
&v1core.Service{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
Namespace: "default",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "ClusterIP",
|
|
ClusterIP: "10.0.0.1",
|
|
ExternalIPs: []string{"1.1.1.1", "2.2.2.2"},
|
|
},
|
|
},
|
|
&v1core.Endpoints{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
Namespace: "default",
|
|
},
|
|
Subsets: []v1core.EndpointSubset{
|
|
{
|
|
Addresses: []v1core.EndpointAddress{
|
|
{
|
|
IP: "172.20.1.1",
|
|
NodeName: ptrToString("node-1"),
|
|
},
|
|
{
|
|
IP: "172.20.1.2",
|
|
NodeName: ptrToString("node-2"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
true,
|
|
nil,
|
|
},
|
|
{
|
|
"node has no endpoints for service",
|
|
&NetworkRoutingController{
|
|
nodeName: "node-1",
|
|
},
|
|
&v1core.Service{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
Namespace: "default",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "ClusterIP",
|
|
ClusterIP: "10.0.0.1",
|
|
ExternalIPs: []string{"1.1.1.1", "2.2.2.2"},
|
|
},
|
|
},
|
|
&v1core.Endpoints{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
Namespace: "default",
|
|
},
|
|
Subsets: []v1core.EndpointSubset{
|
|
{
|
|
Addresses: []v1core.EndpointAddress{
|
|
{
|
|
IP: "172.20.1.1",
|
|
NodeName: ptrToString("node-2"),
|
|
},
|
|
{
|
|
IP: "172.20.1.2",
|
|
NodeName: ptrToString("node-3"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
false,
|
|
nil,
|
|
},
|
|
}
|
|
|
|
for _, testcase := range testcases {
|
|
t.Run(testcase.name, func(t *testing.T) {
|
|
clientset := fake.NewSimpleClientset()
|
|
startInformersForRoutes(testcase.nrc, clientset)
|
|
|
|
_, err := clientset.CoreV1().Endpoints("default").Create(testcase.existingEndpoint)
|
|
if err != nil {
|
|
t.Fatalf("failed to create existing endpoints: %v", err)
|
|
}
|
|
|
|
_, err = clientset.CoreV1().Services("default").Create(testcase.existingService)
|
|
if err != nil {
|
|
t.Fatalf("failed to create existing services: %v", err)
|
|
}
|
|
|
|
waitForListerWithTimeout(testcase.nrc.svcLister, time.Second*10, t)
|
|
waitForListerWithTimeout(testcase.nrc.epLister, time.Second*10, t)
|
|
|
|
nodeHasEndpoints, err := testcase.nrc.nodeHasEndpointsForService(testcase.existingService)
|
|
if !reflect.DeepEqual(err, testcase.err) {
|
|
t.Logf("actual err: %v", err)
|
|
t.Logf("expected err: %v", testcase.err)
|
|
t.Error("unexpected error")
|
|
}
|
|
if nodeHasEndpoints != testcase.nodeHasEndpoints {
|
|
t.Logf("expected nodeHasEndpoints: %v", testcase.nodeHasEndpoints)
|
|
t.Logf("actual nodeHasEndpoints: %v", nodeHasEndpoints)
|
|
t.Error("unexpected nodeHasEndpoints")
|
|
}
|
|
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_advertisePodRoute(t *testing.T) {
|
|
testcases := []struct {
|
|
name string
|
|
nrc *NetworkRoutingController
|
|
envNodeName string
|
|
node *v1core.Node
|
|
// the key is the subnet from the watch event
|
|
watchEvents map[string]bool
|
|
err error
|
|
}{
|
|
{
|
|
"add bgp path for pod cidr using NODE_NAME",
|
|
&NetworkRoutingController{
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
podCidr: "172.20.0.0/24",
|
|
},
|
|
"node-1",
|
|
&v1core.Node{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-1",
|
|
},
|
|
Spec: v1core.NodeSpec{
|
|
PodCIDR: "172.20.0.0/24",
|
|
},
|
|
},
|
|
map[string]bool{
|
|
"172.20.0.0/24": true,
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"add bgp path for pod cidr using hostname override",
|
|
&NetworkRoutingController{
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
hostnameOverride: "node-1",
|
|
podCidr: "172.20.0.0/24",
|
|
},
|
|
"",
|
|
&v1core.Node{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-1",
|
|
},
|
|
Spec: v1core.NodeSpec{
|
|
PodCIDR: "172.20.0.0/24",
|
|
},
|
|
},
|
|
map[string]bool{
|
|
"172.20.0.0/24": true,
|
|
},
|
|
nil,
|
|
},
|
|
/* disabling tests for now, as node POD cidr is read just once at the starting of the program
|
|
Tests needs to be adopted to catch the errors when NetworkRoutingController starts
|
|
{
|
|
"add bgp path for pod cidr without NODE_NAME or hostname override",
|
|
&NetworkRoutingController{
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
},
|
|
"",
|
|
&v1core.Node{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-1",
|
|
},
|
|
Spec: v1core.NodeSpec{
|
|
PodCIDR: "172.20.0.0/24",
|
|
},
|
|
},
|
|
map[string]bool{},
|
|
errors.New("Failed to get pod CIDR allocated for the node due to: Failed to identify the node by NODE_NAME, hostname or --hostname-override"),
|
|
},
|
|
{
|
|
"node does not have pod cidr set",
|
|
&NetworkRoutingController{
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
},
|
|
"node-1",
|
|
&v1core.Node{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-1",
|
|
},
|
|
Spec: v1core.NodeSpec{
|
|
PodCIDR: "",
|
|
},
|
|
},
|
|
map[string]bool{},
|
|
errors.New("node.Spec.PodCIDR not set for node: node-1"),
|
|
},
|
|
*/
|
|
}
|
|
|
|
for _, testcase := range testcases {
|
|
t.Run(testcase.name, func(t *testing.T) {
|
|
go testcase.nrc.bgpServer.Serve()
|
|
err := testcase.nrc.bgpServer.Start(&config.Global{
|
|
Config: config.GlobalConfig{
|
|
As: 1,
|
|
RouterId: "10.0.0.0",
|
|
Port: 10000,
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("failed to start BGP server: %v", err)
|
|
}
|
|
defer func() {
|
|
if err := testcase.nrc.bgpServer.Stop(); err != nil {
|
|
t.Fatalf("failed to stop BGP server : %s", err)
|
|
}
|
|
}()
|
|
|
|
w := testcase.nrc.bgpServer.Watch(gobgp.WatchBestPath(false))
|
|
|
|
clientset := fake.NewSimpleClientset()
|
|
_, err = clientset.CoreV1().Nodes().Create(testcase.node)
|
|
if err != nil {
|
|
t.Fatalf("failed to create node: %v", err)
|
|
}
|
|
testcase.nrc.clientset = clientset
|
|
|
|
os.Setenv("NODE_NAME", testcase.envNodeName)
|
|
defer os.Unsetenv("NODE_NAME")
|
|
|
|
err = testcase.nrc.advertisePodRoute()
|
|
if !reflect.DeepEqual(err, testcase.err) {
|
|
t.Logf("actual error: %v", err)
|
|
t.Logf("expected error: %v", testcase.err)
|
|
t.Error("did not get expected error")
|
|
}
|
|
|
|
watchEvents := waitForBGPWatchEventWithTimeout(time.Second*10, len(testcase.watchEvents), w, t)
|
|
for _, watchEvent := range watchEvents {
|
|
for _, path := range watchEvent.PathList {
|
|
if _, ok := testcase.watchEvents[path.GetNlri().String()]; ok {
|
|
continue
|
|
} else {
|
|
t.Errorf("got unexpected path: %v", path.GetNlri().String())
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_syncInternalPeers(t *testing.T) {
|
|
testcases := []struct {
|
|
name string
|
|
nrc *NetworkRoutingController
|
|
existingNodes []*v1core.Node
|
|
neighbors map[string]bool
|
|
}{
|
|
{
|
|
"sync 1 peer",
|
|
&NetworkRoutingController{
|
|
bgpFullMeshMode: true,
|
|
clientset: fake.NewSimpleClientset(),
|
|
nodeIP: net.ParseIP("10.0.0.0"),
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
activeNodes: make(map[string]bool),
|
|
},
|
|
[]*v1core.Node{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-1",
|
|
},
|
|
Status: v1core.NodeStatus{
|
|
Addresses: []v1core.NodeAddress{
|
|
{
|
|
Type: v1core.NodeInternalIP,
|
|
Address: "10.0.0.1",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
map[string]bool{
|
|
"10.0.0.1": true,
|
|
},
|
|
},
|
|
{
|
|
"sync multiple peers",
|
|
&NetworkRoutingController{
|
|
bgpFullMeshMode: true,
|
|
clientset: fake.NewSimpleClientset(),
|
|
nodeIP: net.ParseIP("10.0.0.0"),
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
activeNodes: make(map[string]bool),
|
|
},
|
|
[]*v1core.Node{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-1",
|
|
},
|
|
Status: v1core.NodeStatus{
|
|
Addresses: []v1core.NodeAddress{
|
|
{
|
|
Type: v1core.NodeInternalIP,
|
|
Address: "10.0.0.1",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-2",
|
|
},
|
|
Status: v1core.NodeStatus{
|
|
Addresses: []v1core.NodeAddress{
|
|
{
|
|
Type: v1core.NodeInternalIP,
|
|
Address: "10.0.0.2",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
map[string]bool{
|
|
"10.0.0.1": true,
|
|
"10.0.0.2": true,
|
|
},
|
|
},
|
|
{
|
|
"sync peer with removed nodes",
|
|
&NetworkRoutingController{
|
|
bgpFullMeshMode: true,
|
|
clientset: fake.NewSimpleClientset(),
|
|
nodeIP: net.ParseIP("10.0.0.0"),
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
activeNodes: map[string]bool{
|
|
"10.0.0.2": true,
|
|
},
|
|
},
|
|
[]*v1core.Node{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-1",
|
|
},
|
|
Status: v1core.NodeStatus{
|
|
Addresses: []v1core.NodeAddress{
|
|
{
|
|
Type: v1core.NodeInternalIP,
|
|
Address: "10.0.0.1",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
map[string]bool{
|
|
"10.0.0.1": true,
|
|
},
|
|
},
|
|
{
|
|
"sync multiple peers with full mesh disabled",
|
|
&NetworkRoutingController{
|
|
bgpFullMeshMode: false,
|
|
clientset: fake.NewSimpleClientset(),
|
|
nodeIP: net.ParseIP("10.0.0.0"),
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
activeNodes: make(map[string]bool),
|
|
nodeAsnNumber: 100,
|
|
},
|
|
[]*v1core.Node{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-1",
|
|
Annotations: map[string]string{
|
|
"kube-router.io/node.asn": "100",
|
|
},
|
|
},
|
|
Status: v1core.NodeStatus{
|
|
Addresses: []v1core.NodeAddress{
|
|
{
|
|
Type: v1core.NodeInternalIP,
|
|
Address: "10.0.0.1",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-2",
|
|
},
|
|
Status: v1core.NodeStatus{
|
|
Addresses: []v1core.NodeAddress{
|
|
{
|
|
Type: v1core.NodeInternalIP,
|
|
Address: "10.0.0.2",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
map[string]bool{
|
|
"10.0.0.1": true,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, testcase := range testcases {
|
|
t.Run(testcase.name, func(t *testing.T) {
|
|
go testcase.nrc.bgpServer.Serve()
|
|
err := testcase.nrc.bgpServer.Start(&config.Global{
|
|
Config: config.GlobalConfig{
|
|
As: 1,
|
|
RouterId: "10.0.0.0",
|
|
Port: 10000,
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("failed to start BGP server: %v", err)
|
|
}
|
|
defer func() {
|
|
if err := testcase.nrc.bgpServer.Stop(); err != nil {
|
|
t.Fatalf("failed to stop BGP server : %s", err)
|
|
}
|
|
}()
|
|
|
|
startInformersForRoutes(testcase.nrc, testcase.nrc.clientset)
|
|
if err = createNodes(testcase.nrc.clientset, testcase.existingNodes); err != nil {
|
|
t.Errorf("failed to create existing nodes: %v", err)
|
|
}
|
|
waitForListerWithTimeout(testcase.nrc.nodeLister, time.Second*10, t)
|
|
|
|
testcase.nrc.syncInternalPeers()
|
|
|
|
neighbors := testcase.nrc.bgpServer.GetNeighbor("", false)
|
|
for _, neighbor := range neighbors {
|
|
_, exists := testcase.neighbors[neighbor.Config.NeighborAddress]
|
|
if !exists {
|
|
t.Errorf("expected neighbor: %v doesn't exist", neighbor.Config.NeighborAddress)
|
|
}
|
|
}
|
|
|
|
if !reflect.DeepEqual(testcase.nrc.activeNodes, testcase.neighbors) {
|
|
t.Logf("actual active nodes: %v", testcase.nrc.activeNodes)
|
|
t.Logf("expected active nodes: %v", testcase.neighbors)
|
|
t.Errorf("did not get expected activeNodes")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
/* Disabling test for now. OnNodeUpdate() behaviour is changed. test needs to be adopted.
|
|
func Test_OnNodeUpdate(t *testing.T) {
|
|
testcases := []struct {
|
|
name string
|
|
nrc *NetworkRoutingController
|
|
nodeEvents []*watchers.NodeUpdate
|
|
activeNodes map[string]bool
|
|
}{
|
|
{
|
|
"node add event",
|
|
&NetworkRoutingController{
|
|
activeNodes: make(map[string]bool),
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
defaultNodeAsnNumber: 1,
|
|
clientset: fake.NewSimpleClientset(),
|
|
},
|
|
[]*watchers.NodeUpdate{
|
|
{
|
|
Node: &v1core.Node{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-1",
|
|
},
|
|
Status: v1core.NodeStatus{
|
|
Addresses: []v1core.NodeAddress{
|
|
{
|
|
Type: v1core.NodeInternalIP,
|
|
Address: "10.0.0.1",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Op: watchers.ADD,
|
|
},
|
|
},
|
|
map[string]bool{
|
|
"10.0.0.1": true,
|
|
},
|
|
},
|
|
{
|
|
"add multiple nodes",
|
|
&NetworkRoutingController{
|
|
activeNodes: make(map[string]bool),
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
defaultNodeAsnNumber: 1,
|
|
clientset: fake.NewSimpleClientset(),
|
|
},
|
|
[]*watchers.NodeUpdate{
|
|
{
|
|
Node: &v1core.Node{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-1",
|
|
},
|
|
Status: v1core.NodeStatus{
|
|
Addresses: []v1core.NodeAddress{
|
|
{
|
|
Type: v1core.NodeInternalIP,
|
|
Address: "10.0.0.1",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Op: watchers.ADD,
|
|
},
|
|
{
|
|
Node: &v1core.Node{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-2",
|
|
},
|
|
Status: v1core.NodeStatus{
|
|
Addresses: []v1core.NodeAddress{
|
|
{
|
|
Type: v1core.NodeExternalIP,
|
|
Address: "1.1.1.1",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Op: watchers.ADD,
|
|
},
|
|
},
|
|
map[string]bool{
|
|
"10.0.0.1": true,
|
|
"1.1.1.1": true,
|
|
},
|
|
},
|
|
{
|
|
"add and then delete nodes",
|
|
&NetworkRoutingController{
|
|
activeNodes: make(map[string]bool),
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
defaultNodeAsnNumber: 1,
|
|
clientset: fake.NewSimpleClientset(),
|
|
},
|
|
[]*watchers.NodeUpdate{
|
|
{
|
|
Node: &v1core.Node{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-1",
|
|
},
|
|
Status: v1core.NodeStatus{
|
|
Addresses: []v1core.NodeAddress{
|
|
{
|
|
Type: v1core.NodeInternalIP,
|
|
Address: "10.0.0.1",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Op: watchers.ADD,
|
|
},
|
|
{
|
|
Node: &v1core.Node{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-1",
|
|
},
|
|
Status: v1core.NodeStatus{
|
|
Addresses: []v1core.NodeAddress{
|
|
{
|
|
Type: v1core.NodeInternalIP,
|
|
Address: "10.0.0.1",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Op: watchers.REMOVE,
|
|
},
|
|
},
|
|
map[string]bool{},
|
|
},
|
|
}
|
|
|
|
for _, testcase := range testcases {
|
|
t.Run(testcase.name, func(t *testing.T) {
|
|
go testcase.nrc.bgpServer.Serve()
|
|
err := testcase.nrc.bgpServer.Start(&config.Global{
|
|
Config: config.GlobalConfig{
|
|
As: 1,
|
|
RouterId: "10.0.0.0",
|
|
Port: 10000,
|
|
},
|
|
})
|
|
testcase.nrc.bgpServerStarted = true
|
|
if err != nil {
|
|
t.Fatalf("failed to start BGP server: %v", err)
|
|
}
|
|
defer testcase.nrc.bgpServer.Stop()
|
|
|
|
for _, nodeEvent := range testcase.nodeEvents {
|
|
testcase.nrc.OnNodeUpdate(nodeEvent)
|
|
}
|
|
|
|
neighbors := testcase.nrc.bgpServer.GetNeighbor("", false)
|
|
for _, neighbor := range neighbors {
|
|
_, exists := testcase.activeNodes[neighbor.Config.NeighborAddress]
|
|
if !exists {
|
|
t.Errorf("expected neighbor: %v doesn't exist", neighbor.Config.NeighborAddress)
|
|
}
|
|
}
|
|
|
|
if !reflect.DeepEqual(testcase.nrc.activeNodes, testcase.activeNodes) {
|
|
t.Logf("actual active nodes: %v", testcase.nrc.activeNodes)
|
|
t.Logf("expected active nodes: %v", testcase.activeNodes)
|
|
t.Errorf("did not get expected activeNodes")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
*/
|
|
|
|
type PolicyTestCase struct {
|
|
name string
|
|
nrc *NetworkRoutingController
|
|
existingNodes []*v1core.Node
|
|
existingServices []*v1core.Service
|
|
podDefinedSet *config.DefinedSets
|
|
clusterIPDefinedSet *config.DefinedSets
|
|
externalPeerDefinedSet *config.DefinedSets
|
|
allPeerDefinedSet *config.DefinedSets
|
|
exportPolicyStatements []*config.Statement
|
|
importPolicyStatements []*config.Statement
|
|
err error
|
|
}
|
|
|
|
func Test_AddPolicies(t *testing.T) {
|
|
testcases := []PolicyTestCase{
|
|
{
|
|
"has nodes and services",
|
|
&NetworkRoutingController{
|
|
clientset: fake.NewSimpleClientset(),
|
|
hostnameOverride: "node-1",
|
|
bgpFullMeshMode: false,
|
|
bgpEnableInternal: true,
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
activeNodes: make(map[string]bool),
|
|
nodeAsnNumber: 100,
|
|
podCidr: "172.20.0.0/24",
|
|
},
|
|
[]*v1core.Node{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-1",
|
|
Annotations: map[string]string{
|
|
"kube-router.io/node.asn": "100",
|
|
},
|
|
},
|
|
Status: v1core.NodeStatus{
|
|
Addresses: []v1core.NodeAddress{
|
|
{
|
|
Type: v1core.NodeInternalIP,
|
|
Address: "10.0.0.1",
|
|
},
|
|
},
|
|
},
|
|
Spec: v1core.NodeSpec{
|
|
PodCIDR: "172.20.0.0/24",
|
|
},
|
|
},
|
|
},
|
|
[]*v1core.Service{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "ClusterIP",
|
|
ClusterIP: "10.0.0.1",
|
|
ExternalIPs: []string{"1.1.1.1"},
|
|
},
|
|
},
|
|
},
|
|
&config.DefinedSets{
|
|
PrefixSets: []config.PrefixSet{
|
|
{
|
|
PrefixSetName: "podcidrprefixset",
|
|
PrefixList: []config.Prefix{
|
|
{
|
|
IpPrefix: "172.20.0.0/24",
|
|
MasklengthRange: "24..24",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
NeighborSets: []config.NeighborSet{},
|
|
TagSets: []config.TagSet{},
|
|
BgpDefinedSets: config.BgpDefinedSets{},
|
|
},
|
|
&config.DefinedSets{
|
|
PrefixSets: []config.PrefixSet{
|
|
{
|
|
PrefixSetName: "clusteripprefixset",
|
|
PrefixList: []config.Prefix{
|
|
{
|
|
IpPrefix: "1.1.1.1/32",
|
|
MasklengthRange: "32..32",
|
|
},
|
|
{
|
|
IpPrefix: "10.0.0.1/32",
|
|
MasklengthRange: "32..32",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
NeighborSets: []config.NeighborSet{},
|
|
TagSets: []config.TagSet{},
|
|
BgpDefinedSets: config.BgpDefinedSets{},
|
|
},
|
|
&config.DefinedSets{},
|
|
&config.DefinedSets{
|
|
PrefixSets: []config.PrefixSet{},
|
|
NeighborSets: []config.NeighborSet{
|
|
{
|
|
NeighborSetName: "allpeerset",
|
|
NeighborInfoList: []string{},
|
|
},
|
|
},
|
|
TagSets: []config.TagSet{},
|
|
BgpDefinedSets: config.BgpDefinedSets{},
|
|
},
|
|
[]*config.Statement{
|
|
{
|
|
Name: "kube_router_export_stmt0",
|
|
Conditions: config.Conditions{
|
|
MatchPrefixSet: config.MatchPrefixSet{
|
|
PrefixSet: "podcidrprefixset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
MatchNeighborSet: config.MatchNeighborSet{
|
|
NeighborSet: "iBGPpeerset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
},
|
|
Actions: config.Actions{
|
|
RouteDisposition: config.ROUTE_DISPOSITION_ACCEPT_ROUTE,
|
|
},
|
|
},
|
|
},
|
|
[]*config.Statement{
|
|
{
|
|
Name: "kube_router_import_stmt0",
|
|
Conditions: config.Conditions{
|
|
MatchPrefixSet: config.MatchPrefixSet{
|
|
PrefixSet: "clusteripprefixset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
MatchNeighborSet: config.MatchNeighborSet{
|
|
NeighborSet: "allpeerset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
},
|
|
Actions: config.Actions{
|
|
RouteDisposition: config.ROUTE_DISPOSITION_REJECT_ROUTE,
|
|
},
|
|
},
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"has nodes, services with external peers",
|
|
&NetworkRoutingController{
|
|
clientset: fake.NewSimpleClientset(),
|
|
hostnameOverride: "node-1",
|
|
bgpFullMeshMode: false,
|
|
bgpEnableInternal: true,
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
activeNodes: make(map[string]bool),
|
|
podCidr: "172.20.0.0/24",
|
|
globalPeerRouters: []*config.Neighbor{
|
|
{
|
|
Config: config.NeighborConfig{NeighborAddress: "10.10.0.1"},
|
|
},
|
|
{
|
|
Config: config.NeighborConfig{NeighborAddress: "10.10.0.2"},
|
|
},
|
|
},
|
|
nodeAsnNumber: 100,
|
|
},
|
|
[]*v1core.Node{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-1",
|
|
Annotations: map[string]string{
|
|
"kube-router.io/node.asn": "100",
|
|
},
|
|
},
|
|
Status: v1core.NodeStatus{
|
|
Addresses: []v1core.NodeAddress{
|
|
{
|
|
Type: v1core.NodeInternalIP,
|
|
Address: "10.0.0.1",
|
|
},
|
|
},
|
|
},
|
|
Spec: v1core.NodeSpec{
|
|
PodCIDR: "172.20.0.0/24",
|
|
},
|
|
},
|
|
},
|
|
[]*v1core.Service{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "ClusterIP",
|
|
ClusterIP: "10.0.0.1",
|
|
ExternalIPs: []string{"1.1.1.1"},
|
|
},
|
|
},
|
|
},
|
|
&config.DefinedSets{
|
|
PrefixSets: []config.PrefixSet{
|
|
{
|
|
PrefixSetName: "podcidrprefixset",
|
|
PrefixList: []config.Prefix{
|
|
{
|
|
IpPrefix: "172.20.0.0/24",
|
|
MasklengthRange: "24..24",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
NeighborSets: []config.NeighborSet{},
|
|
TagSets: []config.TagSet{},
|
|
BgpDefinedSets: config.BgpDefinedSets{},
|
|
},
|
|
&config.DefinedSets{
|
|
PrefixSets: []config.PrefixSet{
|
|
{
|
|
PrefixSetName: "clusteripprefixset",
|
|
PrefixList: []config.Prefix{
|
|
{
|
|
IpPrefix: "1.1.1.1/32",
|
|
MasklengthRange: "32..32",
|
|
},
|
|
{
|
|
IpPrefix: "10.0.0.1/32",
|
|
MasklengthRange: "32..32",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
NeighborSets: []config.NeighborSet{},
|
|
TagSets: []config.TagSet{},
|
|
BgpDefinedSets: config.BgpDefinedSets{},
|
|
},
|
|
&config.DefinedSets{
|
|
PrefixSets: []config.PrefixSet{},
|
|
NeighborSets: []config.NeighborSet{
|
|
{
|
|
NeighborSetName: "externalpeerset",
|
|
NeighborInfoList: []string{"10.10.0.1/32", "10.10.0.2/32"},
|
|
},
|
|
},
|
|
TagSets: []config.TagSet{},
|
|
BgpDefinedSets: config.BgpDefinedSets{},
|
|
},
|
|
&config.DefinedSets{
|
|
PrefixSets: []config.PrefixSet{},
|
|
NeighborSets: []config.NeighborSet{
|
|
{
|
|
NeighborSetName: "allpeerset",
|
|
NeighborInfoList: []string{"10.10.0.1/32", "10.10.0.2/32"},
|
|
},
|
|
},
|
|
TagSets: []config.TagSet{},
|
|
BgpDefinedSets: config.BgpDefinedSets{},
|
|
},
|
|
[]*config.Statement{
|
|
{
|
|
Name: "kube_router_export_stmt0",
|
|
Conditions: config.Conditions{
|
|
MatchPrefixSet: config.MatchPrefixSet{
|
|
PrefixSet: "podcidrprefixset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
MatchNeighborSet: config.MatchNeighborSet{
|
|
NeighborSet: "iBGPpeerset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
},
|
|
Actions: config.Actions{
|
|
RouteDisposition: config.ROUTE_DISPOSITION_ACCEPT_ROUTE,
|
|
},
|
|
},
|
|
{
|
|
Name: "kube_router_export_stmt1",
|
|
Conditions: config.Conditions{
|
|
MatchPrefixSet: config.MatchPrefixSet{
|
|
PrefixSet: "clusteripprefixset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
MatchNeighborSet: config.MatchNeighborSet{
|
|
NeighborSet: "externalpeerset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
},
|
|
Actions: config.Actions{
|
|
RouteDisposition: config.ROUTE_DISPOSITION_ACCEPT_ROUTE,
|
|
},
|
|
},
|
|
},
|
|
[]*config.Statement{
|
|
{
|
|
Name: "kube_router_import_stmt0",
|
|
Conditions: config.Conditions{
|
|
MatchPrefixSet: config.MatchPrefixSet{
|
|
PrefixSet: "clusteripprefixset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
MatchNeighborSet: config.MatchNeighborSet{
|
|
NeighborSet: "allpeerset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
},
|
|
Actions: config.Actions{
|
|
RouteDisposition: config.ROUTE_DISPOSITION_REJECT_ROUTE,
|
|
},
|
|
},
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"has nodes, services with external peers and iBGP disabled",
|
|
&NetworkRoutingController{
|
|
clientset: fake.NewSimpleClientset(),
|
|
hostnameOverride: "node-1",
|
|
bgpFullMeshMode: false,
|
|
bgpEnableInternal: false,
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
activeNodes: make(map[string]bool),
|
|
podCidr: "172.20.0.0/24",
|
|
globalPeerRouters: []*config.Neighbor{
|
|
{
|
|
Config: config.NeighborConfig{NeighborAddress: "10.10.0.1"},
|
|
},
|
|
{
|
|
Config: config.NeighborConfig{NeighborAddress: "10.10.0.2"},
|
|
},
|
|
},
|
|
nodeAsnNumber: 100,
|
|
},
|
|
[]*v1core.Node{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-1",
|
|
Annotations: map[string]string{
|
|
"kube-router.io/node.asn": "100",
|
|
},
|
|
},
|
|
Status: v1core.NodeStatus{
|
|
Addresses: []v1core.NodeAddress{
|
|
{
|
|
Type: v1core.NodeInternalIP,
|
|
Address: "10.0.0.1",
|
|
},
|
|
},
|
|
},
|
|
Spec: v1core.NodeSpec{
|
|
PodCIDR: "172.20.0.0/24",
|
|
},
|
|
},
|
|
},
|
|
[]*v1core.Service{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "ClusterIP",
|
|
ClusterIP: "10.0.0.1",
|
|
ExternalIPs: []string{"1.1.1.1"},
|
|
},
|
|
},
|
|
},
|
|
&config.DefinedSets{
|
|
PrefixSets: []config.PrefixSet{
|
|
{
|
|
PrefixSetName: "podcidrprefixset",
|
|
PrefixList: []config.Prefix{
|
|
{
|
|
IpPrefix: "172.20.0.0/24",
|
|
MasklengthRange: "24..24",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
NeighborSets: []config.NeighborSet{},
|
|
TagSets: []config.TagSet{},
|
|
BgpDefinedSets: config.BgpDefinedSets{},
|
|
},
|
|
&config.DefinedSets{
|
|
PrefixSets: []config.PrefixSet{
|
|
{
|
|
PrefixSetName: "clusteripprefixset",
|
|
PrefixList: []config.Prefix{
|
|
{
|
|
IpPrefix: "1.1.1.1/32",
|
|
MasklengthRange: "32..32",
|
|
},
|
|
{
|
|
IpPrefix: "10.0.0.1/32",
|
|
MasklengthRange: "32..32",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
NeighborSets: []config.NeighborSet{},
|
|
TagSets: []config.TagSet{},
|
|
BgpDefinedSets: config.BgpDefinedSets{},
|
|
},
|
|
&config.DefinedSets{
|
|
PrefixSets: []config.PrefixSet{},
|
|
NeighborSets: []config.NeighborSet{
|
|
{
|
|
NeighborSetName: "externalpeerset",
|
|
NeighborInfoList: []string{"10.10.0.1/32", "10.10.0.2/32"},
|
|
},
|
|
},
|
|
TagSets: []config.TagSet{},
|
|
BgpDefinedSets: config.BgpDefinedSets{},
|
|
},
|
|
&config.DefinedSets{
|
|
PrefixSets: []config.PrefixSet{},
|
|
NeighborSets: []config.NeighborSet{
|
|
{
|
|
NeighborSetName: "allpeerset",
|
|
NeighborInfoList: []string{"10.10.0.1/32", "10.10.0.2/32"},
|
|
},
|
|
},
|
|
TagSets: []config.TagSet{},
|
|
BgpDefinedSets: config.BgpDefinedSets{},
|
|
},
|
|
[]*config.Statement{
|
|
{
|
|
Name: "kube_router_export_stmt0",
|
|
Conditions: config.Conditions{
|
|
MatchPrefixSet: config.MatchPrefixSet{
|
|
PrefixSet: "clusteripprefixset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
MatchNeighborSet: config.MatchNeighborSet{
|
|
NeighborSet: "externalpeerset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
},
|
|
Actions: config.Actions{
|
|
RouteDisposition: config.ROUTE_DISPOSITION_ACCEPT_ROUTE,
|
|
},
|
|
},
|
|
},
|
|
[]*config.Statement{
|
|
{
|
|
Name: "kube_router_import_stmt0",
|
|
Conditions: config.Conditions{
|
|
MatchPrefixSet: config.MatchPrefixSet{
|
|
PrefixSet: "clusteripprefixset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
MatchNeighborSet: config.MatchNeighborSet{
|
|
NeighborSet: "allpeerset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
},
|
|
Actions: config.Actions{
|
|
RouteDisposition: config.ROUTE_DISPOSITION_REJECT_ROUTE,
|
|
},
|
|
},
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"prepends AS with external peers",
|
|
&NetworkRoutingController{
|
|
clientset: fake.NewSimpleClientset(),
|
|
hostnameOverride: "node-1",
|
|
bgpEnableInternal: true,
|
|
bgpFullMeshMode: false,
|
|
pathPrepend: true,
|
|
pathPrependCount: 5,
|
|
pathPrependAS: "65100",
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
activeNodes: make(map[string]bool),
|
|
podCidr: "172.20.0.0/24",
|
|
globalPeerRouters: []*config.Neighbor{
|
|
{
|
|
Config: config.NeighborConfig{NeighborAddress: "10.10.0.1"},
|
|
},
|
|
{
|
|
Config: config.NeighborConfig{NeighborAddress: "10.10.0.2"},
|
|
},
|
|
},
|
|
nodeAsnNumber: 100,
|
|
},
|
|
[]*v1core.Node{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-1",
|
|
Annotations: map[string]string{
|
|
"kube-router.io/node.asn": "100",
|
|
},
|
|
},
|
|
Status: v1core.NodeStatus{
|
|
Addresses: []v1core.NodeAddress{
|
|
{
|
|
Type: v1core.NodeInternalIP,
|
|
Address: "10.0.0.1",
|
|
},
|
|
},
|
|
},
|
|
Spec: v1core.NodeSpec{
|
|
PodCIDR: "172.20.0.0/24",
|
|
},
|
|
},
|
|
},
|
|
[]*v1core.Service{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "ClusterIP",
|
|
ClusterIP: "10.0.0.1",
|
|
ExternalIPs: []string{"1.1.1.1"},
|
|
},
|
|
},
|
|
},
|
|
&config.DefinedSets{
|
|
PrefixSets: []config.PrefixSet{
|
|
{
|
|
PrefixSetName: "podcidrprefixset",
|
|
PrefixList: []config.Prefix{
|
|
{
|
|
IpPrefix: "172.20.0.0/24",
|
|
MasklengthRange: "24..24",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
NeighborSets: []config.NeighborSet{},
|
|
TagSets: []config.TagSet{},
|
|
BgpDefinedSets: config.BgpDefinedSets{},
|
|
},
|
|
&config.DefinedSets{
|
|
PrefixSets: []config.PrefixSet{
|
|
{
|
|
PrefixSetName: "clusteripprefixset",
|
|
PrefixList: []config.Prefix{
|
|
{
|
|
IpPrefix: "1.1.1.1/32",
|
|
MasklengthRange: "32..32",
|
|
},
|
|
{
|
|
IpPrefix: "10.0.0.1/32",
|
|
MasklengthRange: "32..32",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
NeighborSets: []config.NeighborSet{},
|
|
TagSets: []config.TagSet{},
|
|
BgpDefinedSets: config.BgpDefinedSets{},
|
|
},
|
|
&config.DefinedSets{
|
|
PrefixSets: []config.PrefixSet{},
|
|
NeighborSets: []config.NeighborSet{
|
|
{
|
|
NeighborSetName: "externalpeerset",
|
|
NeighborInfoList: []string{"10.10.0.1/32", "10.10.0.2/32"},
|
|
},
|
|
},
|
|
TagSets: []config.TagSet{},
|
|
BgpDefinedSets: config.BgpDefinedSets{},
|
|
},
|
|
&config.DefinedSets{
|
|
PrefixSets: []config.PrefixSet{},
|
|
NeighborSets: []config.NeighborSet{
|
|
{
|
|
NeighborSetName: "allpeerset",
|
|
NeighborInfoList: []string{"10.10.0.1/32", "10.10.0.2/32"},
|
|
},
|
|
},
|
|
TagSets: []config.TagSet{},
|
|
BgpDefinedSets: config.BgpDefinedSets{},
|
|
},
|
|
[]*config.Statement{
|
|
{
|
|
Name: "kube_router_export_stmt0",
|
|
Conditions: config.Conditions{
|
|
MatchPrefixSet: config.MatchPrefixSet{
|
|
PrefixSet: "podcidrprefixset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
MatchNeighborSet: config.MatchNeighborSet{
|
|
NeighborSet: "iBGPpeerset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
},
|
|
Actions: config.Actions{
|
|
RouteDisposition: config.ROUTE_DISPOSITION_ACCEPT_ROUTE,
|
|
},
|
|
},
|
|
{
|
|
Name: "kube_router_export_stmt1",
|
|
Conditions: config.Conditions{
|
|
MatchPrefixSet: config.MatchPrefixSet{
|
|
PrefixSet: "clusteripprefixset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
MatchNeighborSet: config.MatchNeighborSet{
|
|
NeighborSet: "externalpeerset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
},
|
|
Actions: config.Actions{
|
|
RouteDisposition: config.ROUTE_DISPOSITION_ACCEPT_ROUTE,
|
|
BgpActions: config.BgpActions{
|
|
SetAsPathPrepend: config.SetAsPathPrepend{
|
|
As: "65100",
|
|
RepeatN: 5,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
[]*config.Statement{
|
|
{
|
|
Name: "kube_router_import_stmt0",
|
|
Conditions: config.Conditions{
|
|
MatchPrefixSet: config.MatchPrefixSet{
|
|
PrefixSet: "clusteripprefixset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
MatchNeighborSet: config.MatchNeighborSet{
|
|
NeighborSet: "allpeerset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
},
|
|
Actions: config.Actions{
|
|
RouteDisposition: config.ROUTE_DISPOSITION_REJECT_ROUTE,
|
|
},
|
|
},
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"only prepends AS when both node annotations are present",
|
|
&NetworkRoutingController{
|
|
clientset: fake.NewSimpleClientset(),
|
|
hostnameOverride: "node-1",
|
|
bgpEnableInternal: true,
|
|
bgpFullMeshMode: false,
|
|
pathPrepend: false,
|
|
pathPrependAS: "65100",
|
|
bgpServer: gobgp.NewBgpServer(),
|
|
activeNodes: make(map[string]bool),
|
|
podCidr: "172.20.0.0/24",
|
|
globalPeerRouters: []*config.Neighbor{
|
|
{
|
|
Config: config.NeighborConfig{NeighborAddress: "10.10.0.1"},
|
|
},
|
|
{
|
|
Config: config.NeighborConfig{NeighborAddress: "10.10.0.2"},
|
|
},
|
|
},
|
|
nodeAsnNumber: 100,
|
|
},
|
|
[]*v1core.Node{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-1",
|
|
Annotations: map[string]string{
|
|
"kube-router.io/node.asn": "100",
|
|
},
|
|
},
|
|
Status: v1core.NodeStatus{
|
|
Addresses: []v1core.NodeAddress{
|
|
{
|
|
Type: v1core.NodeInternalIP,
|
|
Address: "10.0.0.1",
|
|
},
|
|
},
|
|
},
|
|
Spec: v1core.NodeSpec{
|
|
PodCIDR: "172.20.0.0/24",
|
|
},
|
|
},
|
|
},
|
|
[]*v1core.Service{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "svc-1",
|
|
},
|
|
Spec: v1core.ServiceSpec{
|
|
Type: "ClusterIP",
|
|
ClusterIP: "10.0.0.1",
|
|
ExternalIPs: []string{"1.1.1.1"},
|
|
},
|
|
},
|
|
},
|
|
&config.DefinedSets{
|
|
PrefixSets: []config.PrefixSet{
|
|
{
|
|
PrefixSetName: "podcidrprefixset",
|
|
PrefixList: []config.Prefix{
|
|
{
|
|
IpPrefix: "172.20.0.0/24",
|
|
MasklengthRange: "24..24",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
NeighborSets: []config.NeighborSet{},
|
|
TagSets: []config.TagSet{},
|
|
BgpDefinedSets: config.BgpDefinedSets{},
|
|
},
|
|
&config.DefinedSets{
|
|
PrefixSets: []config.PrefixSet{
|
|
{
|
|
PrefixSetName: "clusteripprefixset",
|
|
PrefixList: []config.Prefix{
|
|
{
|
|
IpPrefix: "1.1.1.1/32",
|
|
MasklengthRange: "32..32",
|
|
},
|
|
{
|
|
IpPrefix: "10.0.0.1/32",
|
|
MasklengthRange: "32..32",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
NeighborSets: []config.NeighborSet{},
|
|
TagSets: []config.TagSet{},
|
|
BgpDefinedSets: config.BgpDefinedSets{},
|
|
},
|
|
&config.DefinedSets{
|
|
PrefixSets: []config.PrefixSet{},
|
|
NeighborSets: []config.NeighborSet{
|
|
{
|
|
NeighborSetName: "externalpeerset",
|
|
NeighborInfoList: []string{"10.10.0.1/32", "10.10.0.2/32"},
|
|
},
|
|
},
|
|
TagSets: []config.TagSet{},
|
|
BgpDefinedSets: config.BgpDefinedSets{},
|
|
},
|
|
&config.DefinedSets{
|
|
PrefixSets: []config.PrefixSet{},
|
|
NeighborSets: []config.NeighborSet{
|
|
{
|
|
NeighborSetName: "allpeerset",
|
|
NeighborInfoList: []string{"10.10.0.1/32", "10.10.0.2/32"},
|
|
},
|
|
},
|
|
TagSets: []config.TagSet{},
|
|
BgpDefinedSets: config.BgpDefinedSets{},
|
|
},
|
|
[]*config.Statement{
|
|
{
|
|
Name: "kube_router_export_stmt0",
|
|
Conditions: config.Conditions{
|
|
MatchPrefixSet: config.MatchPrefixSet{
|
|
PrefixSet: "podcidrprefixset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
MatchNeighborSet: config.MatchNeighborSet{
|
|
NeighborSet: "iBGPpeerset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
},
|
|
Actions: config.Actions{
|
|
RouteDisposition: config.ROUTE_DISPOSITION_ACCEPT_ROUTE,
|
|
},
|
|
},
|
|
{
|
|
Name: "kube_router_export_stmt1",
|
|
Conditions: config.Conditions{
|
|
MatchPrefixSet: config.MatchPrefixSet{
|
|
PrefixSet: "clusteripprefixset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
MatchNeighborSet: config.MatchNeighborSet{
|
|
NeighborSet: "externalpeerset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
},
|
|
Actions: config.Actions{
|
|
RouteDisposition: config.ROUTE_DISPOSITION_ACCEPT_ROUTE,
|
|
},
|
|
},
|
|
},
|
|
[]*config.Statement{
|
|
{
|
|
Name: "kube_router_import_stmt0",
|
|
Conditions: config.Conditions{
|
|
MatchPrefixSet: config.MatchPrefixSet{
|
|
PrefixSet: "clusteripprefixset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
MatchNeighborSet: config.MatchNeighborSet{
|
|
NeighborSet: "allpeerset",
|
|
MatchSetOptions: config.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY,
|
|
},
|
|
},
|
|
Actions: config.Actions{
|
|
RouteDisposition: config.ROUTE_DISPOSITION_REJECT_ROUTE,
|
|
},
|
|
},
|
|
},
|
|
nil,
|
|
},
|
|
}
|
|
|
|
for _, testcase := range testcases {
|
|
t.Run(testcase.name, func(t *testing.T) {
|
|
go testcase.nrc.bgpServer.Serve()
|
|
err := testcase.nrc.bgpServer.Start(&config.Global{
|
|
Config: config.GlobalConfig{
|
|
As: 1,
|
|
RouterId: "10.0.0.0",
|
|
Port: 10000,
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("failed to start BGP server: %v", err)
|
|
}
|
|
defer func() {
|
|
if err := testcase.nrc.bgpServer.Stop(); err != nil {
|
|
t.Fatalf("failed to stop BGP server : %s", err)
|
|
}
|
|
}()
|
|
|
|
startInformersForRoutes(testcase.nrc, testcase.nrc.clientset)
|
|
|
|
if err = createNodes(testcase.nrc.clientset, testcase.existingNodes); err != nil {
|
|
t.Errorf("failed to create existing nodes: %v", err)
|
|
}
|
|
|
|
if err = createServices(testcase.nrc.clientset, testcase.existingServices); err != nil {
|
|
t.Errorf("failed to create existing nodes: %v", err)
|
|
}
|
|
|
|
// ClusterIPs and ExternalIPs
|
|
waitForListerWithTimeout(testcase.nrc.svcLister, time.Second*10, t)
|
|
|
|
testcase.nrc.advertiseClusterIP = true
|
|
testcase.nrc.advertiseExternalIP = true
|
|
testcase.nrc.advertiseLoadBalancerIP = false
|
|
|
|
informerFactory := informers.NewSharedInformerFactory(testcase.nrc.clientset, 0)
|
|
nodeInformer := informerFactory.Core().V1().Nodes().Informer()
|
|
testcase.nrc.nodeLister = nodeInformer.GetIndexer()
|
|
err = testcase.nrc.AddPolicies()
|
|
if !reflect.DeepEqual(err, testcase.err) {
|
|
t.Logf("expected err %v", testcase.err)
|
|
t.Logf("actual err %v", err)
|
|
t.Error("unexpected error")
|
|
}
|
|
|
|
podDefinedSet, err := testcase.nrc.bgpServer.GetDefinedSet(table.DEFINED_TYPE_PREFIX, "podcidrprefixset")
|
|
if err != nil {
|
|
t.Fatalf("error validating defined sets: %v", err)
|
|
}
|
|
|
|
if !podDefinedSet.Equal(testcase.podDefinedSet) {
|
|
t.Logf("expected pod defined set: %+v", testcase.podDefinedSet.PrefixSets)
|
|
t.Logf("actual pod defined set: %+v", podDefinedSet.PrefixSets)
|
|
t.Error("unexpected pod defined set")
|
|
}
|
|
|
|
clusterIPDefinedSet, err := testcase.nrc.bgpServer.GetDefinedSet(table.DEFINED_TYPE_PREFIX, "clusteripprefixset")
|
|
if err != nil {
|
|
t.Fatalf("error validating defined sets: %v", err)
|
|
}
|
|
|
|
if !clusterIPDefinedSet.Equal(testcase.clusterIPDefinedSet) {
|
|
t.Logf("expected cluster ip defined set: %+v", testcase.clusterIPDefinedSet.PrefixSets)
|
|
t.Logf("actual cluster ip defined set: %+v", clusterIPDefinedSet.PrefixSets)
|
|
t.Error("unexpected cluster ip defined set")
|
|
}
|
|
|
|
externalPeerDefinedSet, err := testcase.nrc.bgpServer.GetDefinedSet(table.DEFINED_TYPE_NEIGHBOR, "externalpeerset")
|
|
if err != nil {
|
|
t.Fatalf("error validating defined sets: %v", err)
|
|
}
|
|
|
|
if !externalPeerDefinedSet.Equal(testcase.externalPeerDefinedSet) {
|
|
t.Logf("expected external peer defined set: %+v", testcase.externalPeerDefinedSet.NeighborSets)
|
|
t.Logf("actual external peer defined set: %+v", externalPeerDefinedSet.NeighborSets)
|
|
t.Error("unexpected external peer defined set")
|
|
}
|
|
|
|
allPeerDefinedSet, err := testcase.nrc.bgpServer.GetDefinedSet(table.DEFINED_TYPE_NEIGHBOR, "allpeerset")
|
|
if err != nil {
|
|
t.Fatalf("error validating defined sets: %v", err)
|
|
}
|
|
|
|
if !allPeerDefinedSet.Equal(testcase.allPeerDefinedSet) {
|
|
t.Logf("expected all peer defined set: %+v", testcase.allPeerDefinedSet.NeighborSets)
|
|
t.Logf("actual all peer defined set: %+v", allPeerDefinedSet.NeighborSets)
|
|
t.Error("unexpected all peer defined set")
|
|
}
|
|
|
|
checkPolicies(t, testcase, table.POLICY_DIRECTION_EXPORT, table.ROUTE_TYPE_REJECT, testcase.exportPolicyStatements)
|
|
checkPolicies(t, testcase, table.POLICY_DIRECTION_IMPORT, table.ROUTE_TYPE_ACCEPT, testcase.importPolicyStatements)
|
|
})
|
|
}
|
|
}
|
|
|
|
func checkPolicies(t *testing.T, testcase PolicyTestCase, direction table.PolicyDirection, defaultPolicy table.RouteType,
|
|
policyStatements []*config.Statement) {
|
|
policies := testcase.nrc.bgpServer.GetPolicy()
|
|
policyExists := false
|
|
for _, policy := range policies {
|
|
if policy.Name == "kube_router_"+direction.String() {
|
|
policyExists = true
|
|
break
|
|
}
|
|
}
|
|
if !policyExists {
|
|
t.Errorf("policy 'kube_router_%v' was not added", direction)
|
|
}
|
|
|
|
routeType, policyAssignments, err := testcase.nrc.bgpServer.GetPolicyAssignment("", direction)
|
|
if routeType != defaultPolicy {
|
|
t.Errorf("expected route type '%v' for %v policy assignment, but got %v", defaultPolicy, direction, routeType)
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("failed to get policy assignments: %v", err)
|
|
}
|
|
|
|
policyAssignmentExists := false
|
|
for _, policyAssignment := range policyAssignments {
|
|
if policyAssignment.Name == "kube_router_"+direction.String() {
|
|
policyAssignmentExists = true
|
|
}
|
|
}
|
|
|
|
if !policyAssignmentExists {
|
|
t.Errorf("export policy assignment 'kube_router_%v' was not added", direction)
|
|
}
|
|
|
|
statements := testcase.nrc.bgpServer.GetStatement()
|
|
for _, expectedStatement := range policyStatements {
|
|
found := false
|
|
for _, statement := range statements {
|
|
if reflect.DeepEqual(statement, expectedStatement) {
|
|
found = true
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
t.Errorf("statement %v not found", expectedStatement)
|
|
}
|
|
}
|
|
}
|
|
|
|
func Test_generateTunnelName(t *testing.T) {
|
|
testcases := []struct {
|
|
name string
|
|
nodeIP string
|
|
tunnelName string
|
|
}{
|
|
{
|
|
"IP less than 12 characters after removing '.'",
|
|
"10.0.0.1",
|
|
"tun-10001",
|
|
},
|
|
{
|
|
"IP has 12 characters after removing '.'",
|
|
"100.200.300.400",
|
|
"tun100200300400",
|
|
},
|
|
}
|
|
|
|
for _, testcase := range testcases {
|
|
t.Run(testcase.name, func(t *testing.T) {
|
|
tunnelName := generateTunnelName(testcase.nodeIP)
|
|
if tunnelName != testcase.tunnelName {
|
|
t.Logf("actual tunnel interface name: %s", tunnelName)
|
|
t.Logf("expected tunnel interface name: %s", testcase.tunnelName)
|
|
t.Error("did not get expected tunnel interface name")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func createServices(clientset kubernetes.Interface, svcs []*v1core.Service) error {
|
|
for _, svc := range svcs {
|
|
_, err := clientset.CoreV1().Services("default").Create(svc)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func createNodes(clientset kubernetes.Interface, nodes []*v1core.Node) error {
|
|
for _, node := range nodes {
|
|
_, err := clientset.CoreV1().Nodes().Create(node)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func startInformersForRoutes(nrc *NetworkRoutingController, clientset kubernetes.Interface) {
|
|
informerFactory := informers.NewSharedInformerFactory(clientset, 0)
|
|
svcInformer := informerFactory.Core().V1().Services().Informer()
|
|
epInformer := informerFactory.Core().V1().Endpoints().Informer()
|
|
nodeInformer := informerFactory.Core().V1().Nodes().Informer()
|
|
|
|
go informerFactory.Start(nil)
|
|
informerFactory.WaitForCacheSync(nil)
|
|
|
|
nrc.svcLister = svcInformer.GetIndexer()
|
|
nrc.epLister = epInformer.GetIndexer()
|
|
nrc.nodeLister = nodeInformer.GetIndexer()
|
|
}
|
|
|
|
func waitForListerWithTimeout(lister cache.Indexer, timeout time.Duration, t *testing.T) {
|
|
tick := time.Tick(100 * time.Millisecond)
|
|
timeoutCh := time.After(timeout)
|
|
for {
|
|
select {
|
|
case <-timeoutCh:
|
|
t.Fatal("timeout exceeded waiting for service lister to fill cache")
|
|
case <-tick:
|
|
if len(lister.List()) != 0 {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func waitForBGPWatchEventWithTimeout(timeout time.Duration, expectedNumEvents int, w *gobgp.Watcher, t *testing.T) []*gobgp.WatchEventBestPath {
|
|
timeoutCh := time.After(timeout)
|
|
var events []*gobgp.WatchEventBestPath
|
|
for {
|
|
select {
|
|
case <-timeoutCh:
|
|
t.Fatalf("timeout exceeded waiting for %d watch events, got %d", expectedNumEvents, len(events))
|
|
case event := <-w.Event():
|
|
events = append(events, event.(*gobgp.WatchEventBestPath))
|
|
default:
|
|
if len(events) == expectedNumEvents {
|
|
return events
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func ptrToString(str string) *string {
|
|
return &str
|
|
}
|