func TestConsistencyStaleInterface(t *testing.T) { client := createTestClient() podStore := new(mocks.Store) serviceStore := new(mocks.Store) checker := NewConsistencyChecker(client, NewConfig(), podStore, serviceStore, nil) kube := mocks.NewKubeClient() controller := NewTestController(kube, client, nil, nil) netnsProject := new(types.Project) netnsProject.SetFQName("domain", []string{"default-domain", "testns"}) client.Create(netnsProject) installPods(controller, &kube.PodInterface.Mock, &podStore.Mock, "testns", 3) shutdown := make(chan struct{}) go controller.Run(shutdown) time.Sleep(100 * time.Millisecond) type shutdownMsg struct { } shutdown <- shutdownMsg{} time.Sleep(100 * time.Millisecond) serviceStore.On("List").Return([]interface{}{}) assert.True(t, checker.Check()) vmi := new(types.VirtualMachineInterface) vmi.SetFQName("project", []string{"default-domain", "testns", "pod03"}) assert.NoError(t, client.Create(vmi)) assert.False(t, checker.Check()) }
func TestPodUsesNonExistingService(t *testing.T) { kube := mocks.NewKubeClient() client := new(contrail_mocks.ApiClient) client.Init() client.AddInterceptor("virtual-machine-interface", &VmiInterceptor{}) client.AddInterceptor("virtual-network", &NetworkInterceptor{}) allocator := new(mocks.AddressAllocator) controller := NewTestController(kube, client, allocator, nil) pod1 := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "test-xz1", Namespace: "testns", UID: kubetypes.UID(uuid.New()), Labels: map[string]string{ "name": "testpod", "uses": "nonexisting", }, }, } netnsProject := new(types.Project) netnsProject.SetFQName("", []string{"default-domain", "testns"}) client.Create(netnsProject) allocator.On("LocateIpAddress", string(pod1.ObjectMeta.UID)).Return("10.0.0.1", nil) allocator.On("ReleaseIpAddress", string(pod1.ObjectMeta.UID)).Return() kube.PodInterface.On("Update", pod1).Return(pod1, nil) shutdown := make(chan struct{}) go controller.Run(shutdown) controller.AddPod(pod1) time.Sleep(100 * time.Millisecond) _, err := types.NetworkPolicyByName(client, "default-domain:testns:nonexisting") assert.NoError(t, err) _, err = types.VirtualNetworkByName(client, "default-domain:testns:testpod") assert.NoError(t, err) controller.DeletePod(pod1) time.Sleep(100 * time.Millisecond) type shutdownMsg struct { } shutdown <- shutdownMsg{} _, err = types.VirtualNetworkByName(client, "default-domain:testns:testpod") assert.Error(t, err) _, err = types.NetworkPolicyByName(client, "default-domain:testns:nonexisting") assert.Error(t, err) allocator.AssertExpectations(t) }
func (t *TestFramework) SetUp(publicSubnet string) { t.client = new(contrail_mocks.ApiClient) t.client.Init() t.client.AddInterceptor("virtual-machine-interface", &VmiInterceptor{}) t.client.AddInterceptor("virtual-network", &NetworkInterceptor{}) t.client.AddInterceptor("instance-ip", &IpInterceptor{}) t.client.AddInterceptor("floating-ip", &FloatingIpInterceptor{}) t.podStore = new(mocks.Store) t.serviceStore = new(mocks.Store) t.kubeMock = mocks.NewKubeClient() t.config = NewConfig() t.config.PublicSubnet = publicSubnet t.controller = makeSyncController(t.kubeMock, t.config) t.controller.SetPodStore(t.podStore) t.controller.SetServiceStore(t.serviceStore) t.controller.initComponents(t.client) t.checker = t.controller.newConsistencyChecker() for _, projectName := range testProjects { project := new(types.Project) project.SetFQName("domain", []string{t.config.DefaultDomain, projectName}) t.client.Create(project) } t.state = make(map[string]*TestGroupState, 0) t.clusterIPs = make(map[int]string, 0) t.keyList = make([]string, 0) t.shutdown = make(chan struct{}) keysCall := t.podStore.On("ListKeys").Return() keysCall.Run(func(arg mock.Arguments) { keysCall.Return(t.keyList) }) listCall := t.serviceStore.On("List").Return() listCall.Run(func(arg mock.Arguments) { serviceList := make([]interface{}, 0) for _, v := range t.state { for _, svc := range v.Services { serviceList = append(serviceList, svc) } } listCall.Return(serviceList) }) }
func TestPodCreate(t *testing.T) { kube := mocks.NewKubeClient() client := new(contrail_mocks.ApiClient) client.Init() client.AddInterceptor("virtual-machine-interface", &VmiInterceptor{}) allocator := new(mocks.AddressAllocator) networkMgr := new(mocks.NetworkManager) controller := NewTestController(kube, client, allocator, networkMgr) pod := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "test", Namespace: "testns", UID: kubetypes.UID(uuid.New()), Labels: map[string]string{ "name": "testnet", }, }, } netnsProject := new(types.Project) netnsProject.SetUuid(uuid.New()) netnsProject.SetFQName("", []string{"default-domain", "testns"}) client.Create(netnsProject) testnet := new(types.VirtualNetwork) testnet.SetFQName("project", []string{"default-domain", "testns", "testnet"}) client.Create(testnet) allocator.On("LocateIpAddress", string(pod.ObjectMeta.UID)).Return("10.0.0.42", nil) networkMgr.On("LocateNetwork", "testns", "testnet", controller.config.PrivateSubnet).Return(testnet, nil) networkMgr.On("GetGatewayAddress", testnet).Return("10.0.255.254", nil) kube.PodInterface.On("Update", pod).Return(pod, nil) shutdown := make(chan struct{}) go controller.Run(shutdown) controller.AddPod(pod) time.Sleep(100 * time.Millisecond) type shutdownMsg struct { } shutdown <- shutdownMsg{} kube.PodInterface.AssertExpectations(t) }
func TestConsistencyMissingInterface(t *testing.T) { client := createTestClient() podStore := new(mocks.Store) serviceStore := new(mocks.Store) checker := NewConsistencyChecker(client, NewConfig(), podStore, serviceStore, nil) kube := mocks.NewKubeClient() controller := NewTestController(kube, client, nil, nil) netnsProject := new(types.Project) netnsProject.SetFQName("domain", []string{"default-domain", "testns"}) client.Create(netnsProject) installPods(controller, &kube.PodInterface.Mock, &podStore.Mock, "testns", 3) shutdown := make(chan struct{}) go controller.Run(shutdown) time.Sleep(100 * time.Millisecond) type shutdownMsg struct { } shutdown <- shutdownMsg{} time.Sleep(100 * time.Millisecond) serviceStore.On("List").Return([]interface{}{}) assert.True(t, checker.Check()) vmi, err := types.VirtualMachineInterfaceByName(client, "default-domain:testns:pod01") assert.NoError(t, err) refs, err := vmi.GetInstanceIpBackRefs() for _, ref := range refs { ip, err := types.InstanceIpByUuid(client, ref.Uuid) assert.NoError(t, err) ip.ClearVirtualMachineInterface() assert.NoError(t, client.Update(ip)) } assert.NoError(t, client.Delete(vmi)) assert.False(t, checker.Check()) }
func TestConsistencyMissingVM(t *testing.T) { client := createTestClient() podStore := new(mocks.Store) serviceStore := new(mocks.Store) checker := NewConsistencyChecker(client, NewConfig(), podStore, serviceStore, nil, nil) pod1 := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "test-sv1", Namespace: "testns", UID: kubetypes.UID(uuid.New()), }, } pod2 := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "test-sv2", Namespace: "testns", UID: kubetypes.UID(uuid.New()), }, } kube := mocks.NewKubeClient() controller := NewTestController(kube, client, nil, nil) netnsProject := new(types.Project) netnsProject.SetFQName("domain", []string{"default-domain", "testns"}) client.Create(netnsProject) kube.Pods("testns").(*mocks.KubePodInterface).On("Update", pod1).Return(pod1, nil) kube.Pods("testns").(*mocks.KubePodInterface).On("Update", pod2).Return(pod2, nil) podStore.On("ListKeys").Return([]string{"testns/test-sv1", "testns/test-sv2"}) podStore.On("GetByKey", "testns/test-sv1").Return(pod1, true, nil) podStore.On("GetByKey", "testns/test-sv2").Return(pod2, true, nil) serviceStore.On("List").Return([]interface{}{}) shutdown := make(chan struct{}) go controller.Run(shutdown) controller.AddPod(pod1) controller.AddPod(pod2) time.Sleep(100 * time.Millisecond) type shutdownMsg struct { } shutdown <- shutdownMsg{} assert.True(t, checker.Check()) vmi, err := types.VirtualMachineInterfaceByName(client, "default-domain:testns:test-sv1") assert.NoError(t, err) if err == nil { vmi.ClearVirtualMachine() err = client.Update(vmi) assert.NoError(t, err) } vm, err := types.VirtualMachineByName(client, "default-domain:testns:test-sv1") assert.NoError(t, err) if err == nil { err = client.Delete(vm) assert.NoError(t, err) } assert.False(t, checker.Check()) }
func TestConsistencyConnectionsDelete(t *testing.T) { podStore := new(mocks.Store) serviceStore := new(mocks.Store) kube := mocks.NewKubeClient() client := createTestClient() controller := NewTestController(kube, client, nil, nil) config := controller.config controller.SetPodStore(podStore) controller.SetServiceStore(serviceStore) checker := NewConsistencyChecker(client, controller.config, podStore, serviceStore, controller.serviceMgr) controller.config.ClusterServices = []string{"kube-system/dns", "kube-system/monitoring"} // 2 client pods in network "private" pod1 := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "pod01", Namespace: "testns", UID: kubetypes.UID(uuid.New()), Labels: map[string]string{ config.NetworkTag: "private", config.NetworkAccessTag: "tagA", }, }, } pod2 := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "pod02", Namespace: "testns", UID: kubetypes.UID(uuid.New()), Labels: map[string]string{ config.NetworkTag: "private", config.NetworkAccessTag: "tagB", }, }, } // The service pods for service tagA and tagB respectivly. pod3 := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "pod03", Namespace: "testns", UID: kubetypes.UID(uuid.New()), Labels: map[string]string{ config.NetworkTag: "svc-backend", "app": "provider01", }, }, } pod4 := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "pod04", Namespace: "testns", UID: kubetypes.UID(uuid.New()), Labels: map[string]string{ config.NetworkTag: "svc-backend", "app": "provider02", }, }, } // And the services service1 := &api.Service{ ObjectMeta: api.ObjectMeta{ Name: "service1", Namespace: "testns", Labels: map[string]string{ config.NetworkTag: "tagA", }, }, Spec: api.ServiceSpec{ Selector: map[string]string{ "app": "provider01", }, ClusterIP: "10.254.42.42", Type: api.ServiceTypeClusterIP, }, } service2 := &api.Service{ ObjectMeta: api.ObjectMeta{ Name: "service1", Namespace: "testns", Labels: map[string]string{ config.NetworkTag: "tagB", }, }, Spec: api.ServiceSpec{ Selector: map[string]string{ "app": "provider02", }, ClusterIP: "10.254.42.43", Type: api.ServiceTypeClusterIP, }, } netnsProject := new(types.Project) netnsProject.SetFQName("domain", []string{"default-domain", "testns"}) client.Create(netnsProject) sysProject := new(types.Project) sysProject.SetFQName("domain", []string{"default-domain", "kube-system"}) client.Create(sysProject) keys := make([]string, 0) addPod(pod1, kube.PodInterface, podStore, &keys) addPod(pod2, kube.PodInterface, podStore, &keys) addPod(pod3, kube.PodInterface, podStore, &keys) addPod(pod4, kube.PodInterface, podStore, &keys) podStore.On("ListKeys").Return(keys).Once() serviceStore.On("List").Return([]interface{}{service1, service2}) s1Pods := makeListOptSelector(map[string]string{"app": "provider01"}) kube.PodInterface.On("List", s1Pods).Return(&api.PodList{Items: []api.Pod{*pod3}}, nil) s2Pods := makeListOptSelector(map[string]string{"app": "provider02"}) kube.PodInterface.On("List", s2Pods).Return(&api.PodList{Items: []api.Pod{*pod4}}, nil) kube.ServiceInterface.On("Update", service1).Return(service1, nil) kube.ServiceInterface.On("Update", service2).Return(service2, nil) shutdown := make(chan struct{}) go controller.Run(shutdown) controller.AddPod(pod1) controller.AddPod(pod2) controller.AddPod(pod3) controller.AddPod(pod4) controller.AddService(service1) controller.AddService(service2) time.Sleep(100 * time.Millisecond) assert.True(t, checker.Check()) controller.DeletePod(pod2) time.Sleep(100 * time.Millisecond) keys = append(keys[0:1], keys[2:]...) podStore.On("ListKeys").Return(keys) assert.False(t, checker.Check()) assert.False(t, checker.Check()) assert.True(t, checker.Check()) config.ClusterServices = []string{"kube-system/dns"} assert.False(t, checker.Check()) assert.False(t, checker.Check()) assert.True(t, checker.Check()) type shutdownMsg struct { } shutdown <- shutdownMsg{} }
func TestConsistencyServiceIp(t *testing.T) { client := createTestClient() podStore := new(mocks.Store) serviceStore := new(mocks.Store) checker := NewConsistencyChecker(client, NewConfig(), podStore, serviceStore, nil) kube := mocks.NewKubeClient() controller := NewTestController(kube, client, nil, nil) config := controller.config netnsProject := new(types.Project) netnsProject.SetFQName("domain", []string{"default-domain", "testns"}) client.Create(netnsProject) installPods(controller, &kube.PodInterface.Mock, &podStore.Mock, "testns", 3) service1 := &api.Service{ ObjectMeta: api.ObjectMeta{ Name: "s1", Namespace: "testns", Labels: map[string]string{ config.NetworkTag: "services", }, }, Spec: api.ServiceSpec{ Selector: map[string]string{ "app": "pod01", }, ClusterIP: "10.254.42.42", Type: api.ServiceTypeLoadBalancer, }, } service2 := &api.Service{ ObjectMeta: api.ObjectMeta{ Name: "s2", Namespace: "testns", Labels: map[string]string{ config.NetworkTag: "services", }, }, Spec: api.ServiceSpec{ Selector: map[string]string{ "app": "pod02", }, ClusterIP: "10.254.42.43", ExternalIPs: []string{"10.1.4.89"}, }, } service3 := &api.Service{ ObjectMeta: api.ObjectMeta{ Name: "s3", Namespace: "testns", Labels: map[string]string{ config.NetworkTag: "services", }, }, Spec: api.ServiceSpec{ Selector: map[string]string{ "app": "pod01", }, ClusterIP: "10.254.42.44", }, } kube.ServiceInterface.On("Update", service1).Return(service1, nil) shutdown := make(chan struct{}) go controller.Run(shutdown) controller.AddService(service1) controller.AddService(service2) controller.AddService(service3) serviceStore.On("List").Return([]interface{}{service1, service2, service3}) time.Sleep(100 * time.Millisecond) type shutdownMsg struct { } shutdown <- shutdownMsg{} time.Sleep(100 * time.Millisecond) assert.True(t, checker.Check()) pool, err := types.FloatingIpPoolByName(client, "default-domain:testns:service-services:service-services") assert.NoError(t, err) vmi, err := types.VirtualMachineInterfaceByName(client, "default-domain:testns:pod01") assert.NoError(t, err) vip := new(types.FloatingIp) fqn := make([]string, len(pool.GetFQName())+1) copy(fqn, pool.GetFQName()) fqn[len(pool.GetFQName())] = "s4" vip.SetFQName(vip.GetDefaultParentType(), fqn) vip.AddVirtualMachineInterface(vmi) assert.NoError(t, client.Create(vip)) assert.False(t, checker.Check()) assert.NoError(t, client.Delete(vip)) assert.True(t, checker.Check()) vip, err = types.FloatingIpByName(client, "default-domain:testns:service-services:service-services:s3") assert.NoError(t, err) assert.NoError(t, client.Delete(vip)) assert.False(t, checker.Check()) }
func TestServiceWithMultipleUsers(t *testing.T) { kube := mocks.NewKubeClient() client := new(contrail_mocks.ApiClient) client.Init() client.AddInterceptor("virtual-machine-interface", &VmiInterceptor{}) client.AddInterceptor("virtual-network", &NetworkInterceptor{}) allocator := new(mocks.AddressAllocator) controller := NewTestController(kube, client, allocator, nil) pod1 := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "test-server", Namespace: "testns", UID: kubetypes.UID(uuid.New()), Labels: map[string]string{ "name": "server", }, }, } pod2 := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "test-xz1", Namespace: "testns", UID: kubetypes.UID(uuid.New()), Labels: map[string]string{ "name": "client1", "uses": "x1", }, }, } pod3 := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "test-xz2", Namespace: "testns", UID: kubetypes.UID(uuid.New()), Labels: map[string]string{ "name": "client1", "uses": "x1", }, }, } pod4 := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "test-xz3", Namespace: "testns", UID: kubetypes.UID(uuid.New()), Labels: map[string]string{ "name": "client2", "uses": "x1", }, }, } service := &api.Service{ ObjectMeta: api.ObjectMeta{ Name: "s1", Namespace: "testns", Labels: map[string]string{ "name": "x1", }, }, Spec: api.ServiceSpec{ Selector: map[string]string{ "name": "server", }, ClusterIP: "10.254.42.42", }, } netnsProject := new(types.Project) netnsProject.SetFQName("", []string{"default-domain", "testns"}) client.Create(netnsProject) allocator.On("LocateIpAddress", string(pod1.ObjectMeta.UID)).Return("10.0.0.1", nil) allocator.On("LocateIpAddress", string(pod2.ObjectMeta.UID)).Return("10.0.0.2", nil) allocator.On("LocateIpAddress", string(pod3.ObjectMeta.UID)).Return("10.0.0.3", nil) allocator.On("LocateIpAddress", string(pod4.ObjectMeta.UID)).Return("10.0.0.4", nil) allocator.On("ReleaseIpAddress", string(pod1.ObjectMeta.UID)).Return() allocator.On("ReleaseIpAddress", string(pod2.ObjectMeta.UID)).Return() allocator.On("ReleaseIpAddress", string(pod3.ObjectMeta.UID)).Return() allocator.On("ReleaseIpAddress", string(pod4.ObjectMeta.UID)).Return() kube.PodInterface.On("Update", pod1).Return(pod1, nil) kube.PodInterface.On("Update", pod2).Return(pod2, nil) kube.PodInterface.On("Update", pod3).Return(pod3, nil) kube.PodInterface.On("Update", pod4).Return(pod4, nil) kube.PodInterface.On("List", mock.Anything, mock.Anything).Return(&api.PodList{Items: []api.Pod{*pod1}}, nil) shutdown := make(chan struct{}) go controller.Run(shutdown) controller.AddPod(pod1) controller.AddService(service) controller.AddPod(pod2) controller.AddPod(pod3) controller.AddPod(pod4) time.Sleep(100 * time.Millisecond) policy, err := types.NetworkPolicyByName(client, "default-domain:testns:x1") assert.NoError(t, err) if err == nil { assert.Len(t, policy.GetNetworkPolicyEntries().PolicyRule, 2) assert.True(t, policyHasRule(policy, "default-domain:testns:client1", "default-domain:testns:service-x1")) assert.True(t, policyHasRule(policy, "default-domain:testns:client2", "default-domain:testns:service-x1")) } _, err = types.VirtualNetworkByName(client, "default-domain:testns:client2") assert.NoError(t, err) controller.DeletePod(pod3) time.Sleep(100 * time.Millisecond) policy, err = types.NetworkPolicyByName(client, "default-domain:testns:x1") assert.NoError(t, err) if err == nil { assert.Len(t, policy.GetNetworkPolicyEntries().PolicyRule, 2) } controller.DeletePod(pod4) time.Sleep(100 * time.Millisecond) _, err = types.VirtualNetworkByName(client, "default-domain:testns:client2") assert.Error(t, err) policy, err = types.NetworkPolicyByName(client, "default-domain:testns:x1") assert.NoError(t, err) if err == nil { assert.Len(t, policy.GetNetworkPolicyEntries().PolicyRule, 1) assert.True(t, policyHasRule(policy, "default-domain:testns:client1", "default-domain:testns:service-x1")) } controller.DeletePod(pod2) time.Sleep(100 * time.Millisecond) policy, err = types.NetworkPolicyByName(client, "default-domain:testns:x1") assert.NoError(t, err) if err == nil { assert.Len(t, policy.GetNetworkPolicyEntries().PolicyRule, 0) } controller.DeletePod(pod1) controller.DeleteService(service) time.Sleep(100 * time.Millisecond) type shutdownMsg struct { } shutdown <- shutdownMsg{} policy, err = types.NetworkPolicyByName(client, "default-domain:testns:x1") assert.Error(t, err) }
func TestServiceDeleteWithPod(t *testing.T) { kube := mocks.NewKubeClient() client := new(contrail_mocks.ApiClient) client.Init() client.AddInterceptor("virtual-machine-interface", &VmiInterceptor{}) client.AddInterceptor("virtual-network", &NetworkInterceptor{}) allocator := new(mocks.AddressAllocator) controller := NewTestController(kube, client, allocator, nil) pod1 := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "test-xz1", Namespace: "testns", UID: kubetypes.UID(uuid.New()), Labels: map[string]string{ "name": "testpod", }, }, } pod2 := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "test-xz2", Namespace: "testns", UID: kubetypes.UID(uuid.New()), Labels: map[string]string{ "name": "testpod", }, }, } service := &api.Service{ ObjectMeta: api.ObjectMeta{ Name: "s1", Namespace: "testns", Labels: map[string]string{ "name": "x1", }, }, Spec: api.ServiceSpec{ Selector: map[string]string{ "name": "testpod", }, ClusterIP: "10.254.42.42", }, } netnsProject := new(types.Project) netnsProject.SetFQName("", []string{"default-domain", "testns"}) client.Create(netnsProject) allocator.On("LocateIpAddress", string(pod1.ObjectMeta.UID)).Return("10.0.0.1", nil) allocator.On("LocateIpAddress", string(pod2.ObjectMeta.UID)).Return("10.0.0.2", nil) kube.PodInterface.On("Update", pod1).Return(pod1, nil) kube.PodInterface.On("Update", pod2).Return(pod2, nil) kube.PodInterface.On("List", mock.Anything, mock.Anything).Return(&api.PodList{Items: []api.Pod{*pod1, *pod2}}, nil) shutdown := make(chan struct{}) go controller.Run(shutdown) controller.AddPod(pod1) controller.AddPod(pod2) controller.AddService(service) time.Sleep(100 * time.Millisecond) obj, err := client.FindByName("virtual-network", "default-domain:testns:service-x1") assert.NoError(t, err) serviceNet := obj.(*types.VirtualNetwork) sip, err := controller.networkMgr.LocateFloatingIp(serviceNet, service.Name, service.Spec.ClusterIP) sipName := sip.GetFQName() assert.NoError(t, err) refList, err := sip.GetVirtualMachineInterfaceRefs() assert.Nil(t, err) assert.NotEmpty(t, refList) obj, err = client.FindByName("network-policy", "default-domain:testns:x1") assert.NoError(t, err) controller.DeleteService(service) time.Sleep(100 * time.Millisecond) type shutdownMsg struct { } shutdown <- shutdownMsg{} obj, err = client.FindByName("virtual-network", "default-domain:testns:service-x1") assert.Error(t, err) obj, err = client.FindByName("floating-ip", strings.Join(sipName, ":")) assert.Error(t, err) obj, err = client.FindByName("network-policy", "default-domain:testns:x1") assert.Error(t, err) }
func TestPodAddWithService(t *testing.T) { kube := mocks.NewKubeClient() client := new(contrail_mocks.ApiClient) client.Init() client.AddInterceptor("virtual-machine-interface", &VmiInterceptor{}) client.AddInterceptor("virtual-network", &NetworkInterceptor{}) allocator := new(mocks.AddressAllocator) controller := NewTestController(kube, client, allocator, nil) pod := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "test", Namespace: "testns", UID: kubetypes.UID(uuid.New()), Labels: map[string]string{ "name": "testpod", }, }, } service := &api.Service{ ObjectMeta: api.ObjectMeta{ Name: "s1", Namespace: "testns", Labels: map[string]string{ "name": "x1", }, }, Spec: api.ServiceSpec{ Selector: map[string]string{ "name": "testpod", }, ClusterIP: "10.254.42.42", }, } netnsProject := new(types.Project) netnsProject.SetFQName("", []string{"default-domain", "testns"}) client.Create(netnsProject) allocator.On("LocateIpAddress", string(pod.ObjectMeta.UID)).Return("10.0.0.1", nil) kube.PodInterface.On("Update", pod).Return(pod, nil) shutdown := make(chan struct{}) go controller.Run(shutdown) controller.serviceStore.Add(service) controller.AddPod(pod) time.Sleep(100 * time.Millisecond) type shutdownMsg struct { } shutdown <- shutdownMsg{} kube.PodInterface.AssertExpectations(t) obj, err := client.FindByName("virtual-network", "default-domain:testns:service-x1") assert.NoError(t, err) serviceNet := obj.(*types.VirtualNetwork) sip, err := controller.networkMgr.LocateFloatingIp(serviceNet, service.Name, service.Spec.ClusterIP) assert.NoError(t, err) refList, err := sip.GetVirtualMachineInterfaceRefs() assert.Nil(t, err) assert.NotEmpty(t, refList) }
func TestServiceUpdatePublicIp(t *testing.T) { kube := mocks.NewKubeClient() client := new(contrail_mocks.ApiClient) client.Init() client.AddInterceptor("virtual-machine-interface", &VmiInterceptor{}) client.AddInterceptor("virtual-network", &NetworkInterceptor{}) client.AddInterceptor("instance-ip", &IpInterceptor{}) client.AddInterceptor("floating-ip", &FloatingIpInterceptor{}) controller := NewTestController(kube, client, nil, nil) pod1 := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "test-sv1", Namespace: "testns", UID: kubetypes.UID(uuid.New()), Labels: map[string]string{ "name": "service", }, }, } pod2 := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "test-sv2", Namespace: "testns", UID: kubetypes.UID(uuid.New()), Labels: map[string]string{ "name": "service", }, }, } pod3 := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "test-xz3", Namespace: "testns", UID: kubetypes.UID(uuid.New()), Labels: map[string]string{ "name": "client", "uses": "svc", }, }, } service := &api.Service{ ObjectMeta: api.ObjectMeta{ Name: "service", Namespace: "testns", Labels: map[string]string{ "name": "svc", }, }, Spec: api.ServiceSpec{ Selector: map[string]string{ "name": "service", }, ClusterIP: "10.254.42.42", Type: api.ServiceTypeLoadBalancer, }, } netnsProject := new(types.Project) netnsProject.SetFQName("", []string{"default-domain", "testns"}) client.Create(netnsProject) kube.PodInterface.On("Update", pod1).Return(pod1, nil) kube.PodInterface.On("Update", pod2).Return(pod2, nil) kube.PodInterface.On("Update", pod3).Return(pod3, nil) selectPods := labels.Set(map[string]string{"name": "service"}).AsSelector() kube.PodInterface.On("List", selectPods, mock.Anything).Return(&api.PodList{Items: []api.Pod{*pod1, *pod2}}, nil) kube.ServiceInterface.On("Update", service).Return(service, nil) shutdown := make(chan struct{}) go controller.Run(shutdown) controller.AddPod(pod1) controller.AddPod(pod2) controller.AddPod(pod3) controller.AddService(service) time.Sleep(100 * time.Millisecond) fqn := strings.Split(controller.config.PublicNetwork, ":") fqn = append(fqn, fqn[len(fqn)-1]) fqn = append(fqn, service.Name) fip, err := types.FloatingIpByName(client, strings.Join(fqn, ":")) assert.NoError(t, err) if err == nil { vmList, err := getFloatingIpToInstanceList(client, fip) assert.NoError(t, err) assert.Len(t, vmList, 2) assert.Contains(t, vmList, string(pod1.UID)) assert.Contains(t, vmList, string(pod2.UID)) } nService := new(api.Service) *nService = *service nService.Spec.Type = api.ServiceTypeClusterIP controller.UpdateService(service, nService) time.Sleep(100 * time.Millisecond) _, err = types.FloatingIpByName(client, strings.Join(fqn, ":")) assert.Error(t, err) controller.UpdateService(nService, service) time.Sleep(100 * time.Millisecond) type shutdownMsg struct { } shutdown <- shutdownMsg{} fip, err = types.FloatingIpByName(client, strings.Join(fqn, ":")) assert.NoError(t, err) if err == nil { vmList, err := getFloatingIpToInstanceList(client, fip) assert.NoError(t, err) assert.Len(t, vmList, 2) assert.Contains(t, vmList, string(pod1.UID)) assert.Contains(t, vmList, string(pod2.UID)) } policy, err := types.NetworkPolicyByName(client, "default-domain:testns:svc") assert.NoError(t, err) if err == nil { assert.Len(t, policy.GetNetworkPolicyEntries().PolicyRule, 1) assert.True(t, policyHasRule(policy, "default-domain:testns:client", "default-domain:testns:service-svc")) } }
func TestServiceUpdateLabel(t *testing.T) { kube := mocks.NewKubeClient() client := new(contrail_mocks.ApiClient) client.Init() client.AddInterceptor("virtual-machine-interface", &VmiInterceptor{}) client.AddInterceptor("virtual-network", &NetworkInterceptor{}) client.AddInterceptor("instance-ip", &IpInterceptor{}) client.AddInterceptor("floating-ip", &FloatingIpInterceptor{}) controller := NewTestController(kube, client, nil, nil) pod1 := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "test-sv1", Namespace: "testns", UID: kubetypes.UID(uuid.New()), Labels: map[string]string{ "name": "server", }, }, } pod2 := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "test-xz2", Namespace: "testns", UID: kubetypes.UID(uuid.New()), Labels: map[string]string{ "name": "client1", "uses": "red", }, }, } pod3 := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "test-xz3", Namespace: "testns", UID: kubetypes.UID(uuid.New()), Labels: map[string]string{ "name": "client2", "uses": "blue", }, }, } service := &api.Service{ ObjectMeta: api.ObjectMeta{ Name: "service", Namespace: "testns", Labels: map[string]string{ "name": "red", }, }, Spec: api.ServiceSpec{ Selector: map[string]string{ "name": "server", }, ClusterIP: "10.254.42.42", Type: api.ServiceTypeLoadBalancer, }, } netnsProject := new(types.Project) netnsProject.SetFQName("", []string{"default-domain", "testns"}) client.Create(netnsProject) kube.PodInterface.On("Update", pod1).Return(pod1, nil) kube.PodInterface.On("Update", pod2).Return(pod2, nil) kube.PodInterface.On("Update", pod3).Return(pod3, nil) selectServer := labels.Set(map[string]string{"name": "server"}).AsSelector() kube.PodInterface.On("List", selectServer, mock.Anything).Return(&api.PodList{Items: []api.Pod{*pod1}}, nil) kube.ServiceInterface.On("Update", service).Return(service, nil) shutdown := make(chan struct{}) go controller.Run(shutdown) controller.AddPod(pod1) controller.AddPod(pod2) controller.AddPod(pod3) controller.AddService(service) time.Sleep(100 * time.Millisecond) redPolicy, err := types.NetworkPolicyByName(client, "default-domain:testns:red") assert.NoError(t, err) if err == nil { assert.Len(t, redPolicy.GetNetworkPolicyEntries().PolicyRule, 1) assert.True(t, policyHasRule(redPolicy, "default-domain:testns:client1", "default-domain:testns:service-red")) refs, err := redPolicy.GetVirtualNetworkBackRefs() assert.NoError(t, err) nameList := getReferenceListNames(refs) assert.Contains(t, nameList, "default-domain:testns:client1") assert.Contains(t, nameList, "default-domain:testns:service-red") } bluePolicy, err := types.NetworkPolicyByName(client, "default-domain:testns:blue") assert.NoError(t, err) if err == nil { assert.Len(t, bluePolicy.GetNetworkPolicyEntries().PolicyRule, 0) refs, err := bluePolicy.GetVirtualNetworkBackRefs() assert.NoError(t, err) assert.Len(t, refs, 1) } nService := new(api.Service) *nService = *service nService.Labels = map[string]string{ "name": "blue", } // The service will receive a different PublicIP because this is translated into a service delete operation, // followed by an add. kube.ServiceInterface.On("Update", nService).Return(nService, nil) controller.UpdateService(service, nService) time.Sleep(100 * time.Millisecond) type shutdownMsg struct { } shutdown <- shutdownMsg{} bluePolicy, err = types.NetworkPolicyByName(client, "default-domain:testns:blue") assert.NoError(t, err) if err == nil { assert.Len(t, bluePolicy.GetNetworkPolicyEntries().PolicyRule, 1) assert.True(t, policyHasRule(bluePolicy, "default-domain:testns:client2", "default-domain:testns:service-blue")) refs, err := bluePolicy.GetVirtualNetworkBackRefs() assert.NoError(t, err) nameList := getReferenceListNames(refs) assert.Contains(t, nameList, "default-domain:testns:client2") assert.Contains(t, nameList, "default-domain:testns:service-blue") } redPolicy, err = types.NetworkPolicyByName(client, "default-domain:testns:red") assert.NoError(t, err) if err == nil { assert.Len(t, redPolicy.GetNetworkPolicyEntries().PolicyRule, 0) refs, err := redPolicy.GetVirtualNetworkBackRefs() assert.NoError(t, err) assert.Len(t, refs, 1) } fip, err := types.FloatingIpByName(client, "default-domain:testns:service-blue:service-blue:service") assert.NoError(t, err) if err == nil { vmList, err := getFloatingIpToInstanceList(client, fip) assert.NoError(t, err) assert.Len(t, vmList, 1) assert.Contains(t, vmList, string(pod1.UID)) } }
func TestServiceWithLoadBalancer(t *testing.T) { kube := mocks.NewKubeClient() client := new(contrail_mocks.ApiClient) client.Init() client.AddInterceptor("virtual-machine-interface", &VmiInterceptor{}) client.AddInterceptor("virtual-network", &NetworkInterceptor{}) client.AddInterceptor("instance-ip", &IpInterceptor{}) client.AddInterceptor("floating-ip", &FloatingIpInterceptor{}) controller := NewTestController(kube, client, nil, nil) pod1 := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "test-sv1", Namespace: "testns", UID: kubetypes.UID(uuid.New()), Labels: map[string]string{ "name": "backend", }, }, } pod2 := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "test-sv2", Namespace: "testns", UID: kubetypes.UID(uuid.New()), Labels: map[string]string{ "name": "backend", }, }, } service := &api.Service{ ObjectMeta: api.ObjectMeta{ Name: "service", Namespace: "testns", Labels: map[string]string{ "name": "svc", }, }, Spec: api.ServiceSpec{ Selector: map[string]string{ "name": "backend", }, ClusterIP: "10.254.42.42", Type: api.ServiceTypeLoadBalancer, }, } netnsProject := new(types.Project) netnsProject.SetFQName("", []string{"default-domain", "testns"}) client.Create(netnsProject) store := new(mocks.Store) controller.SetServiceStore(store) kube.PodInterface.On("Update", pod1).Return(pod1, nil) kube.PodInterface.On("Update", pod2).Return(pod2, nil) kube.PodInterface.On("List", mock.Anything, mock.Anything).Return(&api.PodList{Items: []api.Pod{*pod1}}, nil) kube.ServiceInterface.On("Update", service).Return(service, nil) store.On("List").Return([]interface{}{service}) shutdown := make(chan struct{}) go controller.Run(shutdown) controller.AddPod(pod1) controller.AddService(service) time.Sleep(100 * time.Millisecond) controller.AddPod(pod2) time.Sleep(100 * time.Millisecond) fqn := strings.Split(controller.config.PublicNetwork, ":") fqn = append(fqn, fqn[len(fqn)-1]) fqn = append(fqn, service.Name) fip, err := types.FloatingIpByName(client, strings.Join(fqn, ":")) assert.NoError(t, err) if err == nil { refs, err := fip.GetVirtualMachineInterfaceRefs() assert.NoError(t, err) assert.Len(t, refs, 2) } controller.DeleteService(service) time.Sleep(100 * time.Millisecond) type shutdownMsg struct { } shutdown <- shutdownMsg{} _, err = types.FloatingIpByName(client, strings.Join(fqn, ":")) assert.Error(t, err) }
func TestServiceWithMultipleBackends(t *testing.T) { kube := mocks.NewKubeClient() client := new(contrail_mocks.ApiClient) client.Init() client.AddInterceptor("virtual-machine-interface", &VmiInterceptor{}) client.AddInterceptor("virtual-network", &NetworkInterceptor{}) client.AddInterceptor("instance-ip", &IpInterceptor{}) controller := NewTestController(kube, client, nil, nil) pod1 := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "test-sv1", Namespace: "testns", UID: kubetypes.UID(uuid.New()), Labels: map[string]string{ "name": "backend", }, }, } pod2 := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "test-sv2", Namespace: "testns", UID: kubetypes.UID(uuid.New()), Labels: map[string]string{ "name": "backend", }, }, } service := &api.Service{ ObjectMeta: api.ObjectMeta{ Name: "service", Namespace: "testns", Labels: map[string]string{ "name": "svc", }, }, Spec: api.ServiceSpec{ Selector: map[string]string{ "name": "backend", }, ClusterIP: "10.254.42.42", }, } netnsProject := new(types.Project) netnsProject.SetFQName("", []string{"default-domain", "testns"}) client.Create(netnsProject) store := new(mocks.Store) controller.SetServiceStore(store) kube.PodInterface.On("Update", pod1).Return(pod1, nil) kube.PodInterface.On("Update", pod2).Return(pod2, nil) kube.PodInterface.On("List", mock.Anything, mock.Anything).Return(&api.PodList{Items: []api.Pod{*pod1}}, nil) store.On("List").Return([]interface{}{service}) shutdown := make(chan struct{}) go controller.Run(shutdown) controller.AddPod(pod1) controller.AddService(service) time.Sleep(100 * time.Millisecond) controller.AddPod(pod2) time.Sleep(100 * time.Millisecond) fip, err := types.FloatingIpByName(client, "default-domain:testns:service-svc:service-svc:service") assert.NoError(t, err) if err == nil { refs, err := fip.GetVirtualMachineInterfaceRefs() assert.NoError(t, err) assert.Len(t, refs, 2) } controller.DeletePod(pod1) time.Sleep(100 * time.Millisecond) fip, err = types.FloatingIpByName(client, "default-domain:testns:service-svc:service-svc:service") assert.NoError(t, err) if err == nil { refs, err := fip.GetVirtualMachineInterfaceRefs() assert.NoError(t, err) assert.Len(t, refs, 1) var uids []string for _, ref := range refs { uids = append(uids, ref.Uuid) } vmi, err := types.VirtualMachineInterfaceByName(client, "default-domain:testns:test-sv2") assert.NoError(t, err) if err == nil { assert.Contains(t, uids, vmi.GetUuid()) } } controller.AddPod(pod1) time.Sleep(100 * time.Millisecond) fip, err = types.FloatingIpByName(client, "default-domain:testns:service-svc:service-svc:service") assert.NoError(t, err) if err == nil { refs, err := fip.GetVirtualMachineInterfaceRefs() assert.NoError(t, err) assert.Len(t, refs, 2) } controller.DeletePod(pod1) controller.DeletePod(pod2) time.Sleep(100 * time.Millisecond) fip, err = types.FloatingIpByName(client, "default-domain:testns:service-svc:service-svc:service") assert.NoError(t, err) if err == nil { refs, err := fip.GetVirtualMachineInterfaceRefs() assert.NoError(t, err) assert.Len(t, refs, 0) } controller.DeleteService(service) time.Sleep(100 * time.Millisecond) type shutdownMsg struct { } shutdown <- shutdownMsg{} _, err = types.FloatingIpByName(client, "default-domain:testns:service-svc:service-svc:service") assert.Error(t, err) }