// updateNamespaceStatusFunc will verify that the status of the namespace is correct func updateNamespaceStatusFunc(kubeClient clientset.Interface, namespace *v1.Namespace) (*v1.Namespace, error) { if namespace.DeletionTimestamp.IsZero() || namespace.Status.Phase == v1.NamespaceTerminating { return namespace, nil } newNamespace := v1.Namespace{} newNamespace.ObjectMeta = namespace.ObjectMeta newNamespace.Status = namespace.Status newNamespace.Status.Phase = v1.NamespaceTerminating return kubeClient.Core().Namespaces().UpdateStatus(&newNamespace) }
// finalizeNamespace removes the specified finalizerToken and finalizes the namespace func finalizeNamespace(kubeClient clientset.Interface, namespace *v1.Namespace, finalizerToken v1.FinalizerName) (*v1.Namespace, error) { namespaceFinalize := v1.Namespace{} namespaceFinalize.ObjectMeta = namespace.ObjectMeta namespaceFinalize.Spec = namespace.Spec finalizerSet := sets.NewString() for i := range namespace.Spec.Finalizers { if namespace.Spec.Finalizers[i] != finalizerToken { finalizerSet.Insert(string(namespace.Spec.Finalizers[i])) } } namespaceFinalize.Spec.Finalizers = make([]v1.FinalizerName, 0, len(finalizerSet)) for _, value := range finalizerSet.List() { namespaceFinalize.Spec.Finalizers = append(namespaceFinalize.Spec.Finalizers, v1.FinalizerName(value)) } namespace, err := kubeClient.Core().Namespaces().Finalize(&namespaceFinalize) if err != nil { // it was removed already, so life is good if errors.IsNotFound(err) { return namespace, nil } } return namespace, err }
func fakeInitHostFactory(federationName, namespaceName, ip, dnsZoneName, image, dnsProvider string) (cmdutil.Factory, error) { svcName := federationName + "-apiserver" svcUrlPrefix := "/api/v1/namespaces/federation-system/services" credSecretName := svcName + "-credentials" cmKubeconfigSecretName := federationName + "-controller-manager-kubeconfig" capacity, err := resource.ParseQuantity("10Gi") if err != nil { return nil, err } pvcName := svcName + "-etcd-claim" replicas := int32(1) namespace := v1.Namespace{ TypeMeta: unversioned.TypeMeta{ Kind: "Namespace", APIVersion: testapi.Default.GroupVersion().String(), }, ObjectMeta: v1.ObjectMeta{ Name: namespaceName, }, } svc := v1.Service{ TypeMeta: unversioned.TypeMeta{ Kind: "Service", APIVersion: testapi.Default.GroupVersion().String(), }, ObjectMeta: v1.ObjectMeta{ Namespace: namespaceName, Name: svcName, Labels: componentLabel, }, Spec: v1.ServiceSpec{ Type: v1.ServiceTypeLoadBalancer, Selector: apiserverSvcSelector, Ports: []v1.ServicePort{ { Name: "https", Protocol: "TCP", Port: 443, TargetPort: intstr.FromInt(443), }, }, }, } svcWithLB := svc svcWithLB.Status = v1.ServiceStatus{ LoadBalancer: v1.LoadBalancerStatus{ Ingress: []v1.LoadBalancerIngress{ { IP: ip, }, }, }, } credSecret := v1.Secret{ TypeMeta: unversioned.TypeMeta{ Kind: "Secret", APIVersion: testapi.Default.GroupVersion().String(), }, ObjectMeta: v1.ObjectMeta{ Name: credSecretName, Namespace: namespaceName, }, Data: nil, } cmKubeconfigSecret := v1.Secret{ TypeMeta: unversioned.TypeMeta{ Kind: "Secret", APIVersion: testapi.Default.GroupVersion().String(), }, ObjectMeta: v1.ObjectMeta{ Name: cmKubeconfigSecretName, Namespace: namespaceName, }, Data: nil, } pvc := v1.PersistentVolumeClaim{ TypeMeta: unversioned.TypeMeta{ Kind: "PersistentVolumeClaim", APIVersion: testapi.Default.GroupVersion().String(), }, ObjectMeta: v1.ObjectMeta{ Name: pvcName, Namespace: namespaceName, Labels: componentLabel, Annotations: map[string]string{ "volume.alpha.kubernetes.io/storage-class": "yes", }, }, Spec: v1.PersistentVolumeClaimSpec{ AccessModes: []v1.PersistentVolumeAccessMode{ v1.ReadWriteOnce, }, Resources: v1.ResourceRequirements{ Requests: v1.ResourceList{ v1.ResourceStorage: capacity, }, }, }, } apiserver := v1beta1.Deployment{ TypeMeta: unversioned.TypeMeta{ Kind: "Deployment", APIVersion: testapi.Extensions.GroupVersion().String(), }, ObjectMeta: v1.ObjectMeta{ Name: svcName, Namespace: namespaceName, Labels: componentLabel, }, Spec: v1beta1.DeploymentSpec{ Replicas: &replicas, Selector: nil, Template: v1.PodTemplateSpec{ ObjectMeta: v1.ObjectMeta{ Name: svcName, Labels: apiserverPodLabels, }, Spec: v1.PodSpec{ Containers: []v1.Container{ { Name: "apiserver", Image: image, Command: []string{ "/hyperkube", "federation-apiserver", "--bind-address=0.0.0.0", "--etcd-servers=http://localhost:2379", "--service-cluster-ip-range=10.0.0.0/16", "--secure-port=443", "--client-ca-file=/etc/federation/apiserver/ca.crt", "--tls-cert-file=/etc/federation/apiserver/server.crt", "--tls-private-key-file=/etc/federation/apiserver/server.key", "--advertise-address=" + ip, }, Ports: []v1.ContainerPort{ { Name: "https", ContainerPort: 443, }, { Name: "local", ContainerPort: 8080, }, }, VolumeMounts: []v1.VolumeMount{ { Name: credSecretName, MountPath: "/etc/federation/apiserver", ReadOnly: true, }, }, }, { Name: "etcd", Image: "quay.io/coreos/etcd:v2.3.3", Command: []string{ "/etcd", "--data-dir", "/var/etcd/data", }, VolumeMounts: []v1.VolumeMount{ { Name: "etcddata", MountPath: "/var/etcd", }, }, }, }, Volumes: []v1.Volume{ { Name: credSecretName, VolumeSource: v1.VolumeSource{ Secret: &v1.SecretVolumeSource{ SecretName: credSecretName, }, }, }, { Name: "etcddata", VolumeSource: v1.VolumeSource{ PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ ClaimName: pvcName, }, }, }, }, }, }, }, } cmName := federationName + "-controller-manager" cm := v1beta1.Deployment{ TypeMeta: unversioned.TypeMeta{ Kind: "Deployment", APIVersion: testapi.Extensions.GroupVersion().String(), }, ObjectMeta: v1.ObjectMeta{ Name: cmName, Namespace: namespaceName, Labels: componentLabel, }, Spec: v1beta1.DeploymentSpec{ Replicas: &replicas, Selector: nil, Template: v1.PodTemplateSpec{ ObjectMeta: v1.ObjectMeta{ Name: cmName, Labels: controllerManagerPodLabels, }, Spec: v1.PodSpec{ Containers: []v1.Container{ { Name: "controller-manager", Image: image, Command: []string{ "/hyperkube", "federation-controller-manager", "--master=https://federation-apiserver", "--kubeconfig=/etc/federation/controller-manager/kubeconfig", fmt.Sprintf("--dns-provider=%s", dnsProvider), "--dns-provider-config=", fmt.Sprintf("--federation-name=%s", federationName), fmt.Sprintf("--zone-name=%s", dnsZoneName), }, VolumeMounts: []v1.VolumeMount{ { Name: cmKubeconfigSecretName, MountPath: "/etc/federation/controller-manager", ReadOnly: true, }, }, Env: []v1.EnvVar{ { Name: "POD_NAMESPACE", ValueFrom: &v1.EnvVarSource{ FieldRef: &v1.ObjectFieldSelector{ FieldPath: "metadata.namespace", }, }, }, }, }, }, Volumes: []v1.Volume{ { Name: cmKubeconfigSecretName, VolumeSource: v1.VolumeSource{ Secret: &v1.SecretVolumeSource{ SecretName: cmKubeconfigSecretName, }, }, }, }, }, }, }, } f, tf, codec, _ := cmdtesting.NewAPIFactory() extCodec := testapi.Extensions.Codec() ns := dynamic.ContentConfig().NegotiatedSerializer tf.ClientConfig = kubefedtesting.DefaultClientConfig() tf.Client = &fake.RESTClient{ NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { case p == "/api/v1/namespaces" && m == http.MethodPost: body, err := ioutil.ReadAll(req.Body) if err != nil { return nil, err } var got v1.Namespace _, _, err = codec.Decode(body, nil, &got) if err != nil { return nil, err } if !api.Semantic.DeepEqual(got, namespace) { return nil, fmt.Errorf("Unexpected namespace object\n\tDiff: %s", diff.ObjectGoPrintDiff(got, namespace)) } return &http.Response{StatusCode: http.StatusCreated, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(codec, &namespace)}, nil case p == svcUrlPrefix && m == http.MethodPost: body, err := ioutil.ReadAll(req.Body) if err != nil { return nil, err } var got v1.Service _, _, err = codec.Decode(body, nil, &got) if err != nil { return nil, err } if !api.Semantic.DeepEqual(got, svc) { return nil, fmt.Errorf("Unexpected service object\n\tDiff: %s", diff.ObjectGoPrintDiff(got, svc)) } return &http.Response{StatusCode: http.StatusCreated, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(codec, &svc)}, nil case strings.HasPrefix(p, svcUrlPrefix) && m == http.MethodGet: got := strings.TrimPrefix(p, svcUrlPrefix+"/") if got != svcName { return nil, errors.NewNotFound(api.Resource("services"), got) } return &http.Response{StatusCode: http.StatusOK, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(codec, &svcWithLB)}, nil case p == "/api/v1/namespaces/federation-system/secrets" && m == http.MethodPost: body, err := ioutil.ReadAll(req.Body) if err != nil { return nil, err } var got, want v1.Secret _, _, err = codec.Decode(body, nil, &got) if err != nil { return nil, err } // Obtained secret contains generated data which cannot // be compared, so we just nullify the generated part // and compare the rest of the secret. The generated // parts are tested in other tests. got.Data = nil switch got.Name { case credSecretName: want = credSecret case cmKubeconfigSecretName: want = cmKubeconfigSecret } if !api.Semantic.DeepEqual(got, want) { return nil, fmt.Errorf("Unexpected secret object\n\tDiff: %s", diff.ObjectGoPrintDiff(got, want)) } return &http.Response{StatusCode: http.StatusCreated, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(codec, &want)}, nil case p == "/api/v1/namespaces/federation-system/persistentvolumeclaims" && m == http.MethodPost: body, err := ioutil.ReadAll(req.Body) if err != nil { return nil, err } var got v1.PersistentVolumeClaim _, _, err = codec.Decode(body, nil, &got) if err != nil { return nil, err } if !api.Semantic.DeepEqual(got, pvc) { return nil, fmt.Errorf("Unexpected PVC object\n\tDiff: %s", diff.ObjectGoPrintDiff(got, pvc)) } return &http.Response{StatusCode: http.StatusCreated, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(codec, &pvc)}, nil case p == "/apis/extensions/v1beta1/namespaces/federation-system/deployments" && m == http.MethodPost: body, err := ioutil.ReadAll(req.Body) if err != nil { return nil, err } var got, want v1beta1.Deployment _, _, err = codec.Decode(body, nil, &got) if err != nil { return nil, err } switch got.Name { case svcName: want = apiserver case cmName: want = cm } if !api.Semantic.DeepEqual(got, want) { return nil, fmt.Errorf("Unexpected deployment object\n\tDiff: %s", diff.ObjectGoPrintDiff(got, want)) } return &http.Response{StatusCode: http.StatusCreated, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(extCodec, &want)}, nil default: return nil, fmt.Errorf("unexpected request: %#v\n%#v", req.URL, req) } }), } return f, nil }
func TestNamespaceController(t *testing.T) { cluster1 := NewCluster("cluster1", apiv1.ConditionTrue) cluster2 := NewCluster("cluster2", apiv1.ConditionTrue) ns1 := apiv1.Namespace{ ObjectMeta: apiv1.ObjectMeta{ Name: "test-namespace", SelfLink: "/api/v1/namespaces/test-namespace", }, Spec: apiv1.NamespaceSpec{ Finalizers: []apiv1.FinalizerName{apiv1.FinalizerKubernetes}, }, } fakeClient := &fakefedclientset.Clientset{} RegisterFakeList("clusters", &fakeClient.Fake, &federationapi.ClusterList{Items: []federationapi.Cluster{*cluster1}}) RegisterFakeList("namespaces", &fakeClient.Fake, &apiv1.NamespaceList{Items: []apiv1.Namespace{}}) namespaceWatch := RegisterFakeWatch("namespaces", &fakeClient.Fake) namespaceCreateChan := RegisterFakeCopyOnCreate("namespaces", &fakeClient.Fake, namespaceWatch) clusterWatch := RegisterFakeWatch("clusters", &fakeClient.Fake) cluster1Client := &fakekubeclientset.Clientset{} cluster1Watch := RegisterFakeWatch("namespaces", &cluster1Client.Fake) RegisterFakeList("namespaces", &cluster1Client.Fake, &apiv1.NamespaceList{Items: []apiv1.Namespace{}}) cluster1CreateChan := RegisterFakeCopyOnCreate("namespaces", &cluster1Client.Fake, cluster1Watch) // cluster1UpdateChan := RegisterFakeCopyOnUpdate("namespaces", &cluster1Client.Fake, cluster1Watch) cluster2Client := &fakekubeclientset.Clientset{} cluster2Watch := RegisterFakeWatch("namespaces", &cluster2Client.Fake) RegisterFakeList("namespaces", &cluster2Client.Fake, &apiv1.NamespaceList{Items: []apiv1.Namespace{}}) cluster2CreateChan := RegisterFakeCopyOnCreate("namespaces", &cluster2Client.Fake, cluster2Watch) RegisterFakeList("replicasets", &fakeClient.Fake, &extensionsv1.ReplicaSetList{Items: []extensionsv1.ReplicaSet{ { ObjectMeta: apiv1.ObjectMeta{ Name: "test-rs", Namespace: ns1.Namespace, }}}}) RegisterFakeList("secrets", &fakeClient.Fake, &apiv1.SecretList{Items: []apiv1.Secret{ { ObjectMeta: apiv1.ObjectMeta{ Name: "test-secret", Namespace: ns1.Namespace, }}}}) RegisterFakeList("services", &fakeClient.Fake, &apiv1.ServiceList{Items: []apiv1.Service{ { ObjectMeta: apiv1.ObjectMeta{ Name: "test-service", Namespace: ns1.Namespace, }}}}) nsDeleteChan := RegisterDelete(&fakeClient.Fake, "namespaces") rsDeleteChan := RegisterDeleteCollection(&fakeClient.Fake, "replicasets") serviceDeleteChan := RegisterDeleteCollection(&fakeClient.Fake, "services") secretDeleteChan := RegisterDeleteCollection(&fakeClient.Fake, "secrets") namespaceController := NewNamespaceController(fakeClient) informerClientFactory := func(cluster *federationapi.Cluster) (kubeclientset.Interface, error) { switch cluster.Name { case cluster1.Name: return cluster1Client, nil case cluster2.Name: return cluster2Client, nil default: return nil, fmt.Errorf("Unknown cluster") } } setClientFactory(namespaceController.namespaceFederatedInformer, informerClientFactory) namespaceController.clusterAvailableDelay = time.Second namespaceController.namespaceReviewDelay = 50 * time.Millisecond namespaceController.smallDelay = 20 * time.Millisecond namespaceController.updateTimeout = 5 * time.Second stop := make(chan struct{}) namespaceController.Run(stop) // Test add federated namespace. namespaceWatch.Add(&ns1) // Verify that the DeleteFromUnderlyingClusters finalizer is added to the namespace. // Note: finalize invokes the create action in Fake client. // TODO: Seems like a bug. Should invoke update. Fix it. updatedNamespace := GetNamespaceFromChan(namespaceCreateChan) assert.True(t, namespaceController.hasFinalizerFunc(updatedNamespace, deletionhelper.FinalizerDeleteFromUnderlyingClusters)) ns1 = *updatedNamespace // Verify that the namespace is created in underlying cluster1. createdNamespace := GetNamespaceFromChan(cluster1CreateChan) assert.NotNil(t, createdNamespace) assert.Equal(t, ns1.Name, createdNamespace.Name) // Wait for the namespace to appear in the informer store err := WaitForStoreUpdate( namespaceController.namespaceFederatedInformer.GetTargetStore(), cluster1.Name, ns1.Name, wait.ForeverTestTimeout) assert.Nil(t, err, "namespace should have appeared in the informer store") /* // TODO: Uncomment this once we have figured out why this is flaky. // Test update federated namespace. ns1.Annotations = map[string]string{ "A": "B", } namespaceWatch.Modify(&ns1) updatedNamespace = GetNamespaceFromChan(cluster1UpdateChan) assert.NotNil(t, updatedNamespace) assert.Equal(t, ns1.Name, updatedNamespace.Name) // assert.Contains(t, updatedNamespace.Annotations, "A") */ // Test add cluster clusterWatch.Add(cluster2) createdNamespace2 := GetNamespaceFromChan(cluster2CreateChan) assert.NotNil(t, createdNamespace2) assert.Equal(t, ns1.Name, createdNamespace2.Name) // assert.Contains(t, createdNamespace2.Annotations, "A") // Delete the namespace with orphan finalizer (let namespaces // in underlying clusters be as is). // TODO: Add a test without orphan finalizer. ns1.ObjectMeta.Finalizers = append(ns1.ObjectMeta.Finalizers, apiv1.FinalizerOrphan) ns1.DeletionTimestamp = &metav1.Time{Time: time.Now()} namespaceWatch.Modify(&ns1) assert.Equal(t, ns1.Name, GetStringFromChan(nsDeleteChan)) assert.Equal(t, "all", GetStringFromChan(rsDeleteChan)) assert.Equal(t, "all", GetStringFromChan(serviceDeleteChan)) assert.Equal(t, "all", GetStringFromChan(secretDeleteChan)) close(stop) }
func TestNamespaceController(t *testing.T) { cluster1 := NewCluster("cluster1", api_v1.ConditionTrue) cluster2 := NewCluster("cluster2", api_v1.ConditionTrue) fakeClient := &fake_federation_release_1_4.Clientset{} RegisterFakeList("clusters", &fakeClient.Fake, &federation_api.ClusterList{Items: []federation_api.Cluster{*cluster1}}) RegisterFakeList("namespaces", &fakeClient.Fake, &api_v1.NamespaceList{Items: []api_v1.Namespace{}}) namespaceWatch := RegisterFakeWatch("namespaces", &fakeClient.Fake) clusterWatch := RegisterFakeWatch("clusters", &fakeClient.Fake) cluster1Client := &fake_kube_release_1_4.Clientset{} cluster1Watch := RegisterFakeWatch("namespaces", &cluster1Client.Fake) RegisterFakeList("namespaces", &cluster1Client.Fake, &api_v1.NamespaceList{Items: []api_v1.Namespace{}}) cluster1CreateChan := RegisterFakeCopyOnCreate("namespaces", &cluster1Client.Fake, cluster1Watch) cluster1UpdateChan := RegisterFakeCopyOnUpdate("namespaces", &cluster1Client.Fake, cluster1Watch) cluster2Client := &fake_kube_release_1_4.Clientset{} cluster2Watch := RegisterFakeWatch("namespaces", &cluster2Client.Fake) RegisterFakeList("namespaces", &cluster2Client.Fake, &api_v1.NamespaceList{Items: []api_v1.Namespace{}}) cluster2CreateChan := RegisterFakeCopyOnCreate("namespaces", &cluster2Client.Fake, cluster2Watch) namespaceController := NewNamespaceController(fakeClient) informer := ToFederatedInformerForTestOnly(namespaceController.namespaceFederatedInformer) informer.SetClientFactory(func(cluster *federation_api.Cluster) (kube_release_1_4.Interface, error) { switch cluster.Name { case cluster1.Name: return cluster1Client, nil case cluster2.Name: return cluster2Client, nil default: return nil, fmt.Errorf("Unknown cluster") } }) namespaceController.clusterAvailableDelay = time.Second namespaceController.namespaceReviewDelay = 50 * time.Millisecond namespaceController.smallDelay = 20 * time.Millisecond namespaceController.updateTimeout = 5 * time.Second stop := make(chan struct{}) namespaceController.Run(stop) ns1 := api_v1.Namespace{ ObjectMeta: api_v1.ObjectMeta{ Name: "test-namespace", SelfLink: "/api/v1/namespaces/test-namespace", }, } // Test add federated namespace. namespaceWatch.Add(&ns1) createdNamespace := GetNamespaceFromChan(cluster1CreateChan) assert.NotNil(t, createdNamespace) assert.Equal(t, ns1.Name, createdNamespace.Name) // Test update federated namespace. ns1.Annotations = map[string]string{ "A": "B", } namespaceWatch.Modify(&ns1) updatedNamespace := GetNamespaceFromChan(cluster1UpdateChan) assert.NotNil(t, updatedNamespace) assert.Equal(t, ns1.Name, updatedNamespace.Name) // assert.Contains(t, updatedNamespace.Annotations, "A") // Test add cluster clusterWatch.Add(cluster2) createdNamespace2 := GetNamespaceFromChan(cluster2CreateChan) assert.NotNil(t, createdNamespace2) assert.Equal(t, ns1.Name, createdNamespace2.Name) // assert.Contains(t, createdNamespace2.Annotations, "A") close(stop) }
func TestNamespaceController(t *testing.T) { cluster1 := NewCluster("cluster1", api_v1.ConditionTrue) cluster2 := NewCluster("cluster2", api_v1.ConditionTrue) ns1 := api_v1.Namespace{ ObjectMeta: api_v1.ObjectMeta{ Name: "test-namespace", SelfLink: "/api/v1/namespaces/test-namespace", }, } fakeClient := &fake_fedclientset.Clientset{} RegisterFakeList("clusters", &fakeClient.Fake, &federation_api.ClusterList{Items: []federation_api.Cluster{*cluster1}}) RegisterFakeList("namespaces", &fakeClient.Fake, &api_v1.NamespaceList{Items: []api_v1.Namespace{}}) namespaceWatch := RegisterFakeWatch("namespaces", &fakeClient.Fake) clusterWatch := RegisterFakeWatch("clusters", &fakeClient.Fake) cluster1Client := &fake_kubeclientset.Clientset{} cluster1Watch := RegisterFakeWatch("namespaces", &cluster1Client.Fake) RegisterFakeList("namespaces", &cluster1Client.Fake, &api_v1.NamespaceList{Items: []api_v1.Namespace{}}) cluster1CreateChan := RegisterFakeCopyOnCreate("namespaces", &cluster1Client.Fake, cluster1Watch) cluster1UpdateChan := RegisterFakeCopyOnUpdate("namespaces", &cluster1Client.Fake, cluster1Watch) cluster2Client := &fake_kubeclientset.Clientset{} cluster2Watch := RegisterFakeWatch("namespaces", &cluster2Client.Fake) RegisterFakeList("namespaces", &cluster2Client.Fake, &api_v1.NamespaceList{Items: []api_v1.Namespace{}}) cluster2CreateChan := RegisterFakeCopyOnCreate("namespaces", &cluster2Client.Fake, cluster2Watch) RegisterFakeList("replicasets", &fakeClient.Fake, &extensionsv1.ReplicaSetList{Items: []extensionsv1.ReplicaSet{ { ObjectMeta: api_v1.ObjectMeta{ Name: "test-rs", Namespace: ns1.Namespace, }}}}) RegisterFakeList("secrets", &fakeClient.Fake, &api_v1.SecretList{Items: []api_v1.Secret{ { ObjectMeta: api_v1.ObjectMeta{ Name: "test-secret", Namespace: ns1.Namespace, }}}}) RegisterFakeList("services", &fakeClient.Fake, &api_v1.ServiceList{Items: []api_v1.Service{ { ObjectMeta: api_v1.ObjectMeta{ Name: "test-service", Namespace: ns1.Namespace, }}}}) nsDeleteChan := RegisterDelete(&fakeClient.Fake, "namespaces") rsDeleteChan := RegisterDeleteCollection(&fakeClient.Fake, "replicasets") serviceDeleteChan := RegisterDeleteCollection(&fakeClient.Fake, "services") secretDeleteChan := RegisterDeleteCollection(&fakeClient.Fake, "secrets") namespaceController := NewNamespaceController(fakeClient) informer := ToFederatedInformerForTestOnly(namespaceController.namespaceFederatedInformer) informer.SetClientFactory(func(cluster *federation_api.Cluster) (kubeclientset.Interface, error) { switch cluster.Name { case cluster1.Name: return cluster1Client, nil case cluster2.Name: return cluster2Client, nil default: return nil, fmt.Errorf("Unknown cluster") } }) namespaceController.clusterAvailableDelay = time.Second namespaceController.namespaceReviewDelay = 50 * time.Millisecond namespaceController.smallDelay = 20 * time.Millisecond namespaceController.updateTimeout = 5 * time.Second stop := make(chan struct{}) namespaceController.Run(stop) // Test add federated namespace. namespaceWatch.Add(&ns1) createdNamespace := GetNamespaceFromChan(cluster1CreateChan) assert.NotNil(t, createdNamespace) assert.Equal(t, ns1.Name, createdNamespace.Name) // Wait for the secret to appear in the informer store err := WaitForStoreUpdate( namespaceController.namespaceFederatedInformer.GetTargetStore(), cluster1.Name, ns1.Name, wait.ForeverTestTimeout) assert.Nil(t, err, "namespace should have appeared in the informer store") // Test update federated namespace. ns1.Annotations = map[string]string{ "A": "B", } namespaceWatch.Modify(&ns1) updatedNamespace := GetNamespaceFromChan(cluster1UpdateChan) assert.NotNil(t, updatedNamespace) assert.Equal(t, ns1.Name, updatedNamespace.Name) // assert.Contains(t, updatedNamespace.Annotations, "A") // Test add cluster clusterWatch.Add(cluster2) createdNamespace2 := GetNamespaceFromChan(cluster2CreateChan) assert.NotNil(t, createdNamespace2) assert.Equal(t, ns1.Name, createdNamespace2.Name) // assert.Contains(t, createdNamespace2.Annotations, "A") ns1.DeletionTimestamp = &unversioned.Time{Time: time.Now()} namespaceWatch.Modify(&ns1) assert.Equal(t, ns1.Name, GetStringFromChan(nsDeleteChan)) assert.Equal(t, "all", GetStringFromChan(rsDeleteChan)) assert.Equal(t, "all", GetStringFromChan(serviceDeleteChan)) assert.Equal(t, "all", GetStringFromChan(secretDeleteChan)) close(stop) }