mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			209 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			209 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
Copyright 2015 The Kubernetes Authors All rights reserved.
 | 
						|
 | 
						|
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 route
 | 
						|
 | 
						|
import (
 | 
						|
	"net"
 | 
						|
	"testing"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"k8s.io/kubernetes/pkg/api"
 | 
						|
	"k8s.io/kubernetes/pkg/cloudprovider"
 | 
						|
	fake_cloud "k8s.io/kubernetes/pkg/cloudprovider/providers/fake"
 | 
						|
)
 | 
						|
 | 
						|
func TestIsResponsibleForRoute(t *testing.T) {
 | 
						|
	myClusterName := "my-awesome-cluster"
 | 
						|
	myClusterRoute := "my-awesome-cluster-12345678-90ab-cdef-1234-567890abcdef"
 | 
						|
	testCases := []struct {
 | 
						|
		clusterCIDR         string
 | 
						|
		routeName           string
 | 
						|
		routeCIDR           string
 | 
						|
		expectedResponsible bool
 | 
						|
	}{
 | 
						|
		// Routes that belong to this cluster
 | 
						|
		{"10.244.0.0/16", myClusterRoute, "10.244.0.0/24", true},
 | 
						|
		{"10.244.0.0/16", myClusterRoute, "10.244.10.0/24", true},
 | 
						|
		{"10.244.0.0/16", myClusterRoute, "10.244.255.0/24", true},
 | 
						|
		{"10.244.0.0/14", myClusterRoute, "10.244.0.0/24", true},
 | 
						|
		{"10.244.0.0/14", myClusterRoute, "10.247.255.0/24", true},
 | 
						|
		// Routes that match our naming/tagging scheme, but are outside our cidr
 | 
						|
		{"10.244.0.0/16", myClusterRoute, "10.224.0.0/24", false},
 | 
						|
		{"10.244.0.0/16", myClusterRoute, "10.0.10.0/24", false},
 | 
						|
		{"10.244.0.0/16", myClusterRoute, "10.255.255.0/24", false},
 | 
						|
		{"10.244.0.0/14", myClusterRoute, "10.248.0.0/24", false},
 | 
						|
		{"10.244.0.0/14", myClusterRoute, "10.243.255.0/24", false},
 | 
						|
	}
 | 
						|
	for i, testCase := range testCases {
 | 
						|
		_, cidr, err := net.ParseCIDR(testCase.clusterCIDR)
 | 
						|
		if err != nil {
 | 
						|
			t.Errorf("%d. Error in test case: unparsable cidr %q", i, testCase.clusterCIDR)
 | 
						|
		}
 | 
						|
		rc := New(nil, nil, myClusterName, cidr)
 | 
						|
		route := &cloudprovider.Route{
 | 
						|
			Name:            testCase.routeName,
 | 
						|
			TargetInstance:  "doesnt-matter-for-this-test",
 | 
						|
			DestinationCIDR: testCase.routeCIDR,
 | 
						|
		}
 | 
						|
		if resp := rc.isResponsibleForRoute(route); resp != testCase.expectedResponsible {
 | 
						|
			t.Errorf("%d. isResponsibleForRoute() = %t; want %t", i, resp, testCase.expectedResponsible)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestReconcile(t *testing.T) {
 | 
						|
	cluster := "my-k8s"
 | 
						|
	testCases := []struct {
 | 
						|
		nodes          []api.Node
 | 
						|
		initialRoutes  []*cloudprovider.Route
 | 
						|
		expectedRoutes []*cloudprovider.Route
 | 
						|
	}{
 | 
						|
		// 2 nodes, routes already there
 | 
						|
		{
 | 
						|
			nodes: []api.Node{
 | 
						|
				{ObjectMeta: api.ObjectMeta{Name: "node-1", UID: "01"}, Spec: api.NodeSpec{PodCIDR: "10.120.0.0/24"}},
 | 
						|
				{ObjectMeta: api.ObjectMeta{Name: "node-2", UID: "02"}, Spec: api.NodeSpec{PodCIDR: "10.120.1.0/24"}},
 | 
						|
			},
 | 
						|
			initialRoutes: []*cloudprovider.Route{
 | 
						|
				{cluster + "-01", "node-1", "10.120.0.0/24"},
 | 
						|
				{cluster + "-02", "node-2", "10.120.1.0/24"},
 | 
						|
			},
 | 
						|
			expectedRoutes: []*cloudprovider.Route{
 | 
						|
				{cluster + "-01", "node-1", "10.120.0.0/24"},
 | 
						|
				{cluster + "-02", "node-2", "10.120.1.0/24"},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		// 2 nodes, one route already there
 | 
						|
		{
 | 
						|
			nodes: []api.Node{
 | 
						|
				{ObjectMeta: api.ObjectMeta{Name: "node-1", UID: "01"}, Spec: api.NodeSpec{PodCIDR: "10.120.0.0/24"}},
 | 
						|
				{ObjectMeta: api.ObjectMeta{Name: "node-2", UID: "02"}, Spec: api.NodeSpec{PodCIDR: "10.120.1.0/24"}},
 | 
						|
			},
 | 
						|
			initialRoutes: []*cloudprovider.Route{
 | 
						|
				{cluster + "-01", "node-1", "10.120.0.0/24"},
 | 
						|
			},
 | 
						|
			expectedRoutes: []*cloudprovider.Route{
 | 
						|
				{cluster + "-01", "node-1", "10.120.0.0/24"},
 | 
						|
				{cluster + "-02", "node-2", "10.120.1.0/24"},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		// 2 nodes, no routes yet
 | 
						|
		{
 | 
						|
			nodes: []api.Node{
 | 
						|
				{ObjectMeta: api.ObjectMeta{Name: "node-1", UID: "01"}, Spec: api.NodeSpec{PodCIDR: "10.120.0.0/24"}},
 | 
						|
				{ObjectMeta: api.ObjectMeta{Name: "node-2", UID: "02"}, Spec: api.NodeSpec{PodCIDR: "10.120.1.0/24"}},
 | 
						|
			},
 | 
						|
			initialRoutes: []*cloudprovider.Route{},
 | 
						|
			expectedRoutes: []*cloudprovider.Route{
 | 
						|
				{cluster + "-01", "node-1", "10.120.0.0/24"},
 | 
						|
				{cluster + "-02", "node-2", "10.120.1.0/24"},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		// 2 nodes, a few too many routes
 | 
						|
		{
 | 
						|
			nodes: []api.Node{
 | 
						|
				{ObjectMeta: api.ObjectMeta{Name: "node-1", UID: "01"}, Spec: api.NodeSpec{PodCIDR: "10.120.0.0/24"}},
 | 
						|
				{ObjectMeta: api.ObjectMeta{Name: "node-2", UID: "02"}, Spec: api.NodeSpec{PodCIDR: "10.120.1.0/24"}},
 | 
						|
			},
 | 
						|
			initialRoutes: []*cloudprovider.Route{
 | 
						|
				{cluster + "-01", "node-1", "10.120.0.0/24"},
 | 
						|
				{cluster + "-02", "node-2", "10.120.1.0/24"},
 | 
						|
				{cluster + "-03", "node-3", "10.120.2.0/24"},
 | 
						|
				{cluster + "-04", "node-4", "10.120.3.0/24"},
 | 
						|
			},
 | 
						|
			expectedRoutes: []*cloudprovider.Route{
 | 
						|
				{cluster + "-01", "node-1", "10.120.0.0/24"},
 | 
						|
				{cluster + "-02", "node-2", "10.120.1.0/24"},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		// 2 nodes, 2 routes, but only 1 is right
 | 
						|
		{
 | 
						|
			nodes: []api.Node{
 | 
						|
				{ObjectMeta: api.ObjectMeta{Name: "node-1", UID: "01"}, Spec: api.NodeSpec{PodCIDR: "10.120.0.0/24"}},
 | 
						|
				{ObjectMeta: api.ObjectMeta{Name: "node-2", UID: "02"}, Spec: api.NodeSpec{PodCIDR: "10.120.1.0/24"}},
 | 
						|
			},
 | 
						|
			initialRoutes: []*cloudprovider.Route{
 | 
						|
				{cluster + "-01", "node-1", "10.120.0.0/24"},
 | 
						|
				{cluster + "-03", "node-3", "10.120.2.0/24"},
 | 
						|
			},
 | 
						|
			expectedRoutes: []*cloudprovider.Route{
 | 
						|
				{cluster + "-01", "node-1", "10.120.0.0/24"},
 | 
						|
				{cluster + "-02", "node-2", "10.120.1.0/24"},
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
	for i, testCase := range testCases {
 | 
						|
		cloud := &fake_cloud.FakeCloud{RouteMap: make(map[string]*fake_cloud.FakeRoute)}
 | 
						|
		for _, route := range testCase.initialRoutes {
 | 
						|
			fakeRoute := &fake_cloud.FakeRoute{}
 | 
						|
			fakeRoute.ClusterName = cluster
 | 
						|
			fakeRoute.Route = *route
 | 
						|
			cloud.RouteMap[route.Name] = fakeRoute
 | 
						|
		}
 | 
						|
		routes, ok := cloud.Routes()
 | 
						|
		if !ok {
 | 
						|
			t.Error("Error in test: fake_cloud doesn't support Routes()")
 | 
						|
		}
 | 
						|
		_, cidr, _ := net.ParseCIDR("10.120.0.0/16")
 | 
						|
		rc := New(routes, nil, cluster, cidr)
 | 
						|
		if err := rc.reconcile(testCase.nodes, testCase.initialRoutes); err != nil {
 | 
						|
			t.Errorf("%d. Error from rc.reconcile(): %v", i, err)
 | 
						|
		}
 | 
						|
		var finalRoutes []*cloudprovider.Route
 | 
						|
		var err error
 | 
						|
		timeoutChan := time.After(200 * time.Millisecond)
 | 
						|
		tick := time.NewTicker(10 * time.Millisecond)
 | 
						|
		defer tick.Stop()
 | 
						|
	poll:
 | 
						|
		for {
 | 
						|
			select {
 | 
						|
			case <-tick.C:
 | 
						|
				if finalRoutes, err = routes.ListRoutes(cluster); err == nil && routeListEqual(finalRoutes, testCase.expectedRoutes) {
 | 
						|
					break poll
 | 
						|
				}
 | 
						|
			case <-timeoutChan:
 | 
						|
				t.Errorf("%d. rc.reconcile() = %v, routes:\n%v\nexpected: nil, routes:\n%v\n", i, err, flatten(finalRoutes), flatten(testCase.expectedRoutes))
 | 
						|
				break poll
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func routeListEqual(list1, list2 []*cloudprovider.Route) bool {
 | 
						|
	if len(list1) != len(list2) {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
	routeMap1 := make(map[string]*cloudprovider.Route)
 | 
						|
	for _, route1 := range list1 {
 | 
						|
		routeMap1[route1.Name] = route1
 | 
						|
	}
 | 
						|
	for _, route2 := range list2 {
 | 
						|
		if route1, exists := routeMap1[route2.Name]; !exists || *route1 != *route2 {
 | 
						|
			return false
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return true
 | 
						|
}
 | 
						|
 | 
						|
func flatten(list []*cloudprovider.Route) []cloudprovider.Route {
 | 
						|
	var structList []cloudprovider.Route
 | 
						|
	for _, route := range list {
 | 
						|
		structList = append(structList, *route)
 | 
						|
	}
 | 
						|
	return structList
 | 
						|
}
 |