123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- /*
- 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 route
- import (
- "net"
- "testing"
- "time"
- "k8s.io/kubernetes/pkg/api"
- "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
- "k8s.io/kubernetes/pkg/client/testing/core"
- "k8s.io/kubernetes/pkg/cloudprovider"
- fakecloud "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"
- node1 := api.Node{ObjectMeta: api.ObjectMeta{Name: "node-1", UID: "01"}, Spec: api.NodeSpec{PodCIDR: "10.120.0.0/24"}}
- node2 := api.Node{ObjectMeta: api.ObjectMeta{Name: "node-2", UID: "02"}, Spec: api.NodeSpec{PodCIDR: "10.120.1.0/24"}}
- nodeNoCidr := api.Node{ObjectMeta: api.ObjectMeta{Name: "node-2", UID: "02"}, Spec: api.NodeSpec{PodCIDR: ""}}
- testCases := []struct {
- nodes []api.Node
- initialRoutes []*cloudprovider.Route
- expectedRoutes []*cloudprovider.Route
- expectedNetworkUnavailable []bool
- clientset *fake.Clientset
- }{
- // 2 nodes, routes already there
- {
- nodes: []api.Node{
- node1,
- node2,
- },
- 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"},
- },
- expectedNetworkUnavailable: []bool{true, true},
- clientset: fake.NewSimpleClientset(&api.NodeList{Items: []api.Node{node1, node2}}),
- },
- // 2 nodes, one route already there
- {
- nodes: []api.Node{
- node1,
- node2,
- },
- 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"},
- },
- expectedNetworkUnavailable: []bool{true, true},
- clientset: fake.NewSimpleClientset(&api.NodeList{Items: []api.Node{node1, node2}}),
- },
- // 2 nodes, no routes yet
- {
- nodes: []api.Node{
- node1,
- node2,
- },
- initialRoutes: []*cloudprovider.Route{},
- expectedRoutes: []*cloudprovider.Route{
- {cluster + "-01", "node-1", "10.120.0.0/24"},
- {cluster + "-02", "node-2", "10.120.1.0/24"},
- },
- expectedNetworkUnavailable: []bool{true, true},
- clientset: fake.NewSimpleClientset(&api.NodeList{Items: []api.Node{node1, node2}}),
- },
- // 2 nodes, a few too many routes
- {
- nodes: []api.Node{
- node1,
- node2,
- },
- 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"},
- },
- expectedNetworkUnavailable: []bool{true, true},
- clientset: fake.NewSimpleClientset(&api.NodeList{Items: []api.Node{node1, node2}}),
- },
- // 2 nodes, 2 routes, but only 1 is right
- {
- nodes: []api.Node{
- node1,
- node2,
- },
- 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"},
- },
- expectedNetworkUnavailable: []bool{true, true},
- clientset: fake.NewSimpleClientset(&api.NodeList{Items: []api.Node{node1, node2}}),
- },
- // 2 nodes, one node without CIDR assigned.
- {
- nodes: []api.Node{
- node1,
- nodeNoCidr,
- },
- initialRoutes: []*cloudprovider.Route{},
- expectedRoutes: []*cloudprovider.Route{
- {cluster + "-01", "node-1", "10.120.0.0/24"},
- },
- expectedNetworkUnavailable: []bool{true, false},
- clientset: fake.NewSimpleClientset(&api.NodeList{Items: []api.Node{node1, nodeNoCidr}}),
- },
- }
- for i, testCase := range testCases {
- cloud := &fakecloud.FakeCloud{RouteMap: make(map[string]*fakecloud.FakeRoute)}
- for _, route := range testCase.initialRoutes {
- fakeRoute := &fakecloud.FakeRoute{}
- fakeRoute.ClusterName = cluster
- fakeRoute.Route = *route
- cloud.RouteMap[route.Name] = fakeRoute
- }
- routes, ok := cloud.Routes()
- if !ok {
- t.Error("Error in test: fakecloud doesn't support Routes()")
- }
- _, cidr, _ := net.ParseCIDR("10.120.0.0/16")
- rc := New(routes, testCase.clientset, cluster, cidr)
- if err := rc.reconcile(testCase.nodes, testCase.initialRoutes); err != nil {
- t.Errorf("%d. Error from rc.reconcile(): %v", i, err)
- }
- for _, action := range testCase.clientset.Actions() {
- if action.GetVerb() == "update" && action.GetResource().Resource == "nodes" {
- node := action.(core.UpdateAction).GetObject().(*api.Node)
- _, condition := api.GetNodeCondition(&node.Status, api.NodeNetworkUnavailable)
- if condition == nil {
- t.Errorf("%d. Missing NodeNetworkUnavailable condition for Node %v", i, node.Name)
- } else {
- check := func(index int) bool {
- return (condition.Status == api.ConditionFalse) == testCase.expectedNetworkUnavailable[index]
- }
- index := -1
- for j := range testCase.nodes {
- if testCase.nodes[j].Name == node.Name {
- index = j
- }
- }
- if index == -1 {
- // Something's wrong
- continue
- }
- if !check(index) {
- t.Errorf("%d. Invalid NodeNetworkUnavailable condition for Node %v, expected %v, got %v",
- i, node.Name, testCase.expectedNetworkUnavailable[index], (condition.Status == api.ConditionFalse))
- }
- }
- }
- }
- 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
- }
|