From 8f62294760592630353c78732a9cb33e854f31fb Mon Sep 17 00:00:00 2001 From: wanjunlei Date: Wed, 7 Apr 2021 16:23:28 +0800 Subject: [PATCH 1/2] fix bug member cluster can not view the notification channels Signed-off-by: wanjunlei --- .../notification/notification_controller.go | 151 +++++++++++++++--- .../notification_controller_suite_test.go | 37 +---- .../notification_controller_test.go | 28 ++-- 3 files changed, 151 insertions(+), 65 deletions(-) diff --git a/pkg/controller/notification/notification_controller.go b/pkg/controller/notification/notification_controller.go index 543450bd3..d66b37cc2 100644 --- a/pkg/controller/notification/notification_controller.go +++ b/pkg/controller/notification/notification_controller.go @@ -18,6 +18,7 @@ package notification import ( "context" + "encoding/json" "fmt" "reflect" "time" @@ -40,6 +41,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "kubesphere.io/kubesphere/pkg/apis/cluster/v1alpha1" "kubesphere.io/kubesphere/pkg/apis/notification/v2beta1" "kubesphere.io/kubesphere/pkg/apis/types/v1beta1" "kubesphere.io/kubesphere/pkg/constants" @@ -47,8 +49,9 @@ import ( const ( // SuccessSynced is used as part of the Event 'reason' when a Foo is synced - successSynced = "Synced" - controllerName = "notification-controller" + successSynced = "Synced" + controllerName = "notification-controller" + messageResourceSynced = "Notification synced successfully" ) type Controller struct { @@ -121,6 +124,18 @@ func (c *Controller) setEventHandlers() error { } } + // Watch the cluster add and delete operator. + if informer, err := c.ksCache.GetInformer(context.Background(), &v1alpha1.Cluster{}); err != nil { + klog.Errorf("get cluster informer error, %v", err) + return err + } else { + informer.AddEventHandler(toolscache.ResourceEventHandlerFuncs{ + AddFunc: c.enqueue, + DeleteFunc: c.enqueue, + }) + c.informerSynced = append(c.informerSynced, informer.HasSynced) + } + return nil } @@ -224,15 +239,28 @@ func (c *Controller) reconcile(obj interface{}) error { } name := accessor.GetName() - kind := runtimeObj.GetObjectKind().GroupVersionKind().String() + + // If the cluster changed, add or delete, it should update the annotations of secrets + // which the notification controller managed, then the notification controller + // will receiver a event to reconcile the secret. + if _, ok := obj.(*v1alpha1.Cluster); ok { + err = c.updateSecret() + if err != nil { + klog.Errorf("update secret failed, %s", err) + return err + } + + return nil + } + err = c.Get(context.Background(), client.ObjectKey{Name: accessor.GetName(), Namespace: accessor.GetNamespace()}, runtimeObj) if err != nil { // The user may no longer exist, in which case we stop // processing. if errors.IsNotFound(err) { - utilruntime.HandleError(fmt.Errorf("obj '%s, %s' in work queue no longer exists", kind, name)) - c.recorder.Event(runtimeObj, corev1.EventTypeNormal, successSynced, fmt.Sprintf("%s synced successfully", kind)) - klog.Infof("Successfully synced %s:%s", kind, name) + utilruntime.HandleError(fmt.Errorf("obj '%s' in work queue no longer exists", name)) + c.recorder.Event(runtimeObj, corev1.EventTypeNormal, successSynced, messageResourceSynced) + klog.Infof("Successfully synced %s", name) return nil } klog.Error(err) @@ -243,8 +271,8 @@ func (c *Controller) reconcile(obj interface{}) error { return err } - c.recorder.Event(runtimeObj, corev1.EventTypeNormal, successSynced, fmt.Sprintf("%s synced successfully", kind)) - klog.Infof("Successfully synced %s:%s", kind, name) + c.recorder.Event(runtimeObj, corev1.EventTypeNormal, successSynced, messageResourceSynced) + klog.Infof("Successfully synced %s", name) return nil } @@ -299,18 +327,20 @@ func (c *Controller) syncFederatedConfig(obj *v2beta1.Config) error { }, } - err := controllerutil.SetControllerReference(obj, fedObj, scheme.Scheme) + err = controllerutil.SetControllerReference(obj, fedObj, scheme.Scheme) if err != nil { + klog.Errorf("FederatedNotificationConfig '%s' SetControllerReference failed, %s", obj.Name, err) return err } - if err := c.Create(context.Background(), fedObj); err != nil { - klog.Errorf("create '%s:%s' failed, %s", fedObj.GetObjectKind().GroupVersionKind().String(), obj.Name, err) + + if err = c.Create(context.Background(), fedObj); err != nil { + klog.Errorf("create FederatedNotificationConfig '%s' failed, %s", obj.Name, err) return err } return nil } - klog.Error(err) + klog.Errorf("get FederatedNotificationConfig '%s' failed, %s", obj.Name, err) return err } @@ -320,7 +350,7 @@ func (c *Controller) syncFederatedConfig(obj *v2beta1.Config) error { fedObj.Spec.Template.Labels = obj.Labels if err := c.Update(context.Background(), fedObj); err != nil { - klog.Errorf("update '%s:%s' failed, %s", fedObj.GetObjectKind().GroupVersionKind().String(), obj.Name, err) + klog.Errorf("update FederatedNotificationConfig '%s' failed, %s", obj.Name, err) return err } } @@ -355,18 +385,20 @@ func (c *Controller) syncFederatedReceiver(obj *v2beta1.Receiver) error { }, } - err := controllerutil.SetControllerReference(obj, fedObj, scheme.Scheme) + err = controllerutil.SetControllerReference(obj, fedObj, scheme.Scheme) if err != nil { + klog.Errorf("FederatedNotificationReceiver '%s' SetControllerReference failed, %s", obj.Name, err) return err } - if err := c.Create(context.Background(), fedObj); err != nil { - klog.Errorf("create '%s:%s' failed, %s", fedObj.GetObjectKind().GroupVersionKind().String(), obj.Name, err) + + if err = c.Create(context.Background(), fedObj); err != nil { + klog.Errorf("create FederatedNotificationReceiver '%s' failed, %s", obj.Name, err) return err } return nil } - klog.Error(err) + klog.Errorf("get FederatedNotificationReceiver '%s' failed, %s", obj.Name, err) return err } @@ -376,7 +408,7 @@ func (c *Controller) syncFederatedReceiver(obj *v2beta1.Receiver) error { fedObj.Spec.Template.Labels = obj.Labels if err := c.Update(context.Background(), fedObj); err != nil { - klog.Errorf("update '%s:%s' failed, %s", fedObj.GetObjectKind().GroupVersionKind().String(), obj.Name, err) + klog.Errorf("update FederatedNotificationReceiver '%s' failed, %s", obj.Name, err) return err } } @@ -411,18 +443,26 @@ func (c *Controller) syncFederatedSecret(obj *corev1.Secret) error { }, } - err := controllerutil.SetControllerReference(obj, fedObj, scheme.Scheme) + err = c.updateOverrides(obj, fedObj) if err != nil { + klog.Errorf("update FederatedSecret '%s' overrides failed, %s", obj.Name, err) return err } - if err := c.Create(context.Background(), fedObj); err != nil { - klog.Errorf("create '%s:%s' failed, %s", fedObj.GetObjectKind().GroupVersionKind().String(), obj.Name, err) + + err = controllerutil.SetControllerReference(obj, fedObj, scheme.Scheme) + if err != nil { + klog.Errorf("FederatedSecret '%s' SetControllerReference failed, %s", obj.Name, err) + return err + } + + if err = c.Create(context.Background(), fedObj); err != nil { + klog.Errorf("create FederatedSecret '%s' failed, %s", obj.Name, err) return err } return nil } - klog.Error(err) + klog.Errorf("get FederatedSecret '%s' failed, %s", obj.Name, err) return err } @@ -433,9 +473,72 @@ func (c *Controller) syncFederatedSecret(obj *corev1.Secret) error { fedObj.Spec.Template.Data = obj.Data fedObj.Spec.Template.StringData = obj.StringData fedObj.Spec.Template.Type = obj.Type + } - if err := c.Update(context.Background(), fedObj); err != nil { - klog.Errorf("update '%s:%s' failed, %s", fedObj.GetObjectKind().GroupVersionKind().String(), obj.Name, err) + err = c.updateOverrides(obj, fedObj) + if err != nil { + klog.Errorf("update FederatedSecret '%s' overrides failed, %s", obj.Name, err) + return err + } + + if err := c.Update(context.Background(), fedObj); err != nil { + klog.Errorf("update FederatedSecret '%s' failed, %s", obj.Name, err) + return err + } + + return nil +} + +func (c *Controller) updateOverrides(obj *corev1.Secret, fedSecret *v1beta1.FederatedSecret) error { + clusterList := &v1alpha1.ClusterList{} + err := c.ksCache.List(context.Background(), clusterList) + if err != nil { + return err + } + + bs, err := json.Marshal(obj.Labels) + if err != nil { + return err + } + + fedSecret.Spec.Overrides = fedSecret.Spec.Overrides[:0] + for _, cluster := range clusterList.Items { + fedSecret.Spec.Overrides = append(fedSecret.Spec.Overrides, v1beta1.GenericOverrideItem{ + ClusterName: cluster.Name, + ClusterOverrides: []v1beta1.ClusterOverride{ + { + Path: "/metadata/labels", + Value: runtime.RawExtension{ + Raw: bs, + }, + }, + }, + }) + } + + return nil +} + +// Update the annotations of secrets which the notification controller managed, rigger a reconcile. +func (c *Controller) updateSecret() error { + + secretList := &corev1.SecretList{} + err := c.ksCache.List(context.Background(), secretList, + client.InNamespace(constants.NotificationSecretNamespace), + client.MatchingLabels{ + constants.NotificationManagedLabel: "true", + }) + if err != nil { + return err + } + + for _, secret := range secretList.Items { + if secret.Annotations == nil { + secret.Annotations = make(map[string]string) + } + + secret.Annotations["reloadtimestamp"] = time.Now().String() + if err := c.Update(context.Background(), &secret); err != nil { return err } } diff --git a/pkg/controller/notification/notification_controller_suite_test.go b/pkg/controller/notification/notification_controller_suite_test.go index 5c559285b..077000e38 100644 --- a/pkg/controller/notification/notification_controller_suite_test.go +++ b/pkg/controller/notification/notification_controller_suite_test.go @@ -20,18 +20,15 @@ import ( "path/filepath" "testing" - "k8s.io/client-go/kubernetes/fake" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/envtest" + "sigs.k8s.io/controller-runtime/pkg/envtest/printer" "kubesphere.io/kubesphere/pkg/apis" "kubesphere.io/kubesphere/pkg/apis/notification/v2beta1" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "k8s.io/client-go/rest" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/envtest" - "sigs.k8s.io/controller-runtime/pkg/envtest/printer" ) func TestSource(t *testing.T) { @@ -42,7 +39,6 @@ func TestSource(t *testing.T) { var testenv *envtest.Environment var cfg *rest.Config -var k8sManager ctrl.Manager var _ = BeforeSuite(func(done Done) { @@ -55,27 +51,8 @@ var _ = BeforeSuite(func(done Done) { Expect(err).NotTo(HaveOccurred()) Expect(cfg).ToNot(BeNil()) - err = v2beta1.AddToScheme(scheme.Scheme) - Expect(err).NotTo(HaveOccurred()) - - err = apis.AddToScheme(scheme.Scheme) - Expect(err).NotTo(HaveOccurred()) - - k8sManager, err = ctrl.NewManager(cfg, ctrl.Options{ - Scheme: scheme.Scheme, - MetricsBindAddress: "0", - }) - Expect(err).ToNot(HaveOccurred()) - - r, err := NewController(fake.NewSimpleClientset(), k8sManager.GetClient(), k8sManager.GetCache()) - Expect(err).ToNot(HaveOccurred()) - err = k8sManager.Add(r) - Expect(err).ToNot(HaveOccurred()) - - go func() { - err = k8sManager.Start(ctrl.SetupSignalHandler()) - Expect(err).ToNot(HaveOccurred()) - }() + Expect(v2beta1.AddToScheme(scheme.Scheme)).NotTo(HaveOccurred()) + Expect(apis.AddToScheme(scheme.Scheme)).NotTo(HaveOccurred()) close(done) }, 60) diff --git a/pkg/controller/notification/notification_controller_test.go b/pkg/controller/notification/notification_controller_test.go index d6f5894c0..e119e1d52 100644 --- a/pkg/controller/notification/notification_controller_test.go +++ b/pkg/controller/notification/notification_controller_test.go @@ -25,6 +25,7 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + fakek8s "k8s.io/client-go/kubernetes/fake" "sigs.k8s.io/controller-runtime/pkg/cache" "sigs.k8s.io/controller-runtime/pkg/client" @@ -91,16 +92,19 @@ var ( informerCacheCancel() }) - // Add Tests for OpenAPI validation (or additonal CRD features) specified in + // Add Tests for OpenAPI validation (or additional CRD features) specified in // your API definition. // Avoid adding tests for vanilla CRUD operations because they would // test Kubernetes API server, which isn't the goal here. Context("Notification Controller", func() { It("Should create successfully", func() { + r, err := NewController(fakek8s.NewSimpleClientset(), cl, ksCache) + Expect(err).ToNot(HaveOccurred()) + // Create a secret Expect(cl.Create(context.Background(), secret)).Should(Succeed()) - time.Sleep(time.Second) + Expect(r.reconcile(secret)).Should(Succeed()) fedSecret := &v1beta1.FederatedSecret{} By("Expecting to create federated secret successfully") @@ -110,11 +114,11 @@ var ( return !fedSecret.CreationTimestamp.IsZero() }, timeout, interval).Should(BeTrue()) - err := ksCache.Get(context.Background(), client.ObjectKey{Name: secret.Name, Namespace: constants.NotificationSecretNamespace}, secret) + err = ksCache.Get(context.Background(), client.ObjectKey{Name: secret.Name, Namespace: constants.NotificationSecretNamespace}, secret) Expect(err).Should(Succeed()) secret.StringData = map[string]string{"foo": "bar"} Expect(cl.Update(context.Background(), secret)).Should(Succeed()) - time.Sleep(time.Second) + Expect(r.reconcile(secret)).Should(Succeed()) By("Expecting to update federated secret successfully") Eventually(func() bool { @@ -133,8 +137,7 @@ var ( obj := &v2beta1.Config{ ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: constants.NotificationSecretNamespace, + Name: "foo", Labels: map[string]string{ "type": "default", }, @@ -169,16 +172,19 @@ var ( informerCacheCancel() }) - // Add Tests for OpenAPI validation (or additonal CRD features) specified in + // Add Tests for OpenAPI validation (or additional CRD features) specified in // your API definition. // Avoid adding tests for vanilla CRUD operations because they would // test Kubernetes API server, which isn't the goal here. Context("Notification Controller", func() { It("Should create successfully", func() { - // Create a bject + r, err := NewController(fakek8s.NewSimpleClientset(), cl, ksCache) + Expect(err).ToNot(HaveOccurred()) + + // Create a object Expect(cl.Create(context.Background(), obj)).Should(Succeed()) - time.Sleep(time.Second) + Expect(r.reconcile(obj)).Should(Succeed()) fedObj := &v1beta1.FederatedNotificationConfig{} By("Expecting to create federated object successfully") @@ -188,11 +194,11 @@ var ( return !fedObj.CreationTimestamp.IsZero() }, timeout, interval).Should(BeTrue()) - err := ksCache.Get(context.Background(), client.ObjectKey{Name: obj.Name}, obj) + err = ksCache.Get(context.Background(), client.ObjectKey{Name: obj.Name}, obj) Expect(err).Should(Succeed()) obj.Labels = map[string]string{"foo": "bar"} Expect(cl.Update(context.Background(), obj)).Should(Succeed()) - time.Sleep(time.Second) + Expect(r.reconcile(obj)).Should(Succeed()) By("Expecting to update federated object successfully") Eventually(func() bool { From cbdc81a10a4a0e8050d361fbe0ca2f0d41157731 Mon Sep 17 00:00:00 2001 From: wanjunlei Date: Thu, 8 Apr 2021 11:45:21 +0800 Subject: [PATCH 2/2] resolve conversation and add some test code Signed-off-by: wanjunlei --- .../notification/notification_controller.go | 9 +- .../notification_controller_test.go | 167 +++++++++++------- 2 files changed, 104 insertions(+), 72 deletions(-) diff --git a/pkg/controller/notification/notification_controller.go b/pkg/controller/notification/notification_controller.go index d66b37cc2..b2ab84c90 100644 --- a/pkg/controller/notification/notification_controller.go +++ b/pkg/controller/notification/notification_controller.go @@ -124,7 +124,7 @@ func (c *Controller) setEventHandlers() error { } } - // Watch the cluster add and delete operator. + // Watch the cluster add and delete operations. if informer, err := c.ksCache.GetInformer(context.Background(), &v1alpha1.Cluster{}); err != nil { klog.Errorf("get cluster informer error, %v", err) return err @@ -240,9 +240,8 @@ func (c *Controller) reconcile(obj interface{}) error { name := accessor.GetName() - // If the cluster changed, add or delete, it should update the annotations of secrets - // which the notification controller managed, then the notification controller - // will receiver a event to reconcile the secret. + // The notification controller should update the annotations of secrets managed by itself + // whenever a cluster is added or deleted. This way, the controller will have a chance to override the secret. if _, ok := obj.(*v1alpha1.Cluster); ok { err = c.updateSecret() if err != nil { @@ -519,7 +518,7 @@ func (c *Controller) updateOverrides(obj *corev1.Secret, fedSecret *v1beta1.Fede return nil } -// Update the annotations of secrets which the notification controller managed, rigger a reconcile. +// Update the annotations of secrets managed by the notification controller to trigger a reconcile. func (c *Controller) updateSecret() error { secretList := &corev1.SecretList{} diff --git a/pkg/controller/notification/notification_controller_test.go b/pkg/controller/notification/notification_controller_test.go index e119e1d52..a9dda73d1 100644 --- a/pkg/controller/notification/notification_controller_test.go +++ b/pkg/controller/notification/notification_controller_test.go @@ -29,6 +29,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/cache" "sigs.k8s.io/controller-runtime/pkg/client" + "kubesphere.io/kubesphere/pkg/apis/cluster/v1alpha1" "kubesphere.io/kubesphere/pkg/apis/notification/v2beta1" "kubesphere.io/kubesphere/pkg/apis/types/v1beta1" "kubesphere.io/kubesphere/pkg/constants" @@ -56,6 +57,30 @@ var ( }, } + config := &v2beta1.Config{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Labels: map[string]string{ + "type": "global", + }, + }, + } + + receiver := &v2beta1.Receiver{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Labels: map[string]string{ + "type": "default", + }, + }, + } + + host := &v1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "host", + }, + } + var ( cl client.Client ksCache cache.Cache @@ -114,6 +139,7 @@ var ( return !fedSecret.CreationTimestamp.IsZero() }, timeout, interval).Should(BeTrue()) + // Update a secret err = ksCache.Get(context.Background(), client.ObjectKey{Name: secret.Name, Namespace: constants.NotificationSecretNamespace}, secret) Expect(err).Should(Succeed()) secret.StringData = map[string]string{"foo": "bar"} @@ -126,85 +152,92 @@ var ( Expect(err).Should(Succeed()) return string(fedSecret.Spec.Template.Data["foo"]) == "bar" }, timeout, interval).Should(BeTrue()) - }) - }) - }) - _ = Describe("Notification", func() { + // Create a Config + Expect(cl.Create(context.Background(), config)).Should(Succeed()) + Expect(r.reconcile(config)).Should(Succeed()) - const timeout = time.Second * 30 - const interval = time.Second * 1 - - obj := &v2beta1.Config{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Labels: map[string]string{ - "type": "default", - }, - }, - } - - var ( - cl client.Client - ksCache cache.Cache - informerCacheCtx context.Context - informerCacheCancel context.CancelFunc - ) - - BeforeEach(func() { - var err error - cl, err = client.New(cfg, client.Options{}) - Expect(err).NotTo(HaveOccurred()) - - ksCache, err = cache.New(cfg, cache.Options{}) - Expect(err).NotTo(HaveOccurred()) - - informerCacheCtx, informerCacheCancel = context.WithCancel(context.Background()) - go func(ctx context.Context) { - defer GinkgoRecover() - Expect(ksCache.Start(ctx.Done())).To(Succeed()) - }(informerCacheCtx) - Expect(ksCache.WaitForCacheSync(informerCacheCtx.Done())).To(BeTrue()) - }) - - AfterEach(func() { - By("cleaning up") - informerCacheCancel() - }) - - // Add Tests for OpenAPI validation (or additional CRD features) specified in - // your API definition. - // Avoid adding tests for vanilla CRUD operations because they would - // test Kubernetes API server, which isn't the goal here. - Context("Notification Controller", func() { - It("Should create successfully", func() { - - r, err := NewController(fakek8s.NewSimpleClientset(), cl, ksCache) - Expect(err).ToNot(HaveOccurred()) - - // Create a object - Expect(cl.Create(context.Background(), obj)).Should(Succeed()) - Expect(r.reconcile(obj)).Should(Succeed()) - - fedObj := &v1beta1.FederatedNotificationConfig{} + fedConfig := &v1beta1.FederatedNotificationConfig{} By("Expecting to create federated object successfully") Eventually(func() bool { - err := ksCache.Get(context.Background(), client.ObjectKey{Name: obj.Name}, fedObj) + err := ksCache.Get(context.Background(), client.ObjectKey{Name: config.Name}, fedConfig) Expect(err).Should(Succeed()) - return !fedObj.CreationTimestamp.IsZero() + return !fedConfig.CreationTimestamp.IsZero() }, timeout, interval).Should(BeTrue()) - err = ksCache.Get(context.Background(), client.ObjectKey{Name: obj.Name}, obj) + // Update a config + err = ksCache.Get(context.Background(), client.ObjectKey{Name: config.Name}, config) Expect(err).Should(Succeed()) - obj.Labels = map[string]string{"foo": "bar"} - Expect(cl.Update(context.Background(), obj)).Should(Succeed()) - Expect(r.reconcile(obj)).Should(Succeed()) + config.Labels = map[string]string{"foo": "bar"} + Expect(cl.Update(context.Background(), config)).Should(Succeed()) + Expect(r.reconcile(config)).Should(Succeed()) By("Expecting to update federated object successfully") Eventually(func() bool { - err := ksCache.Get(context.Background(), client.ObjectKey{Name: obj.Name}, fedObj) + err := ksCache.Get(context.Background(), client.ObjectKey{Name: config.Name}, fedConfig) Expect(err).Should(Succeed()) - return fedObj.Spec.Template.Labels["foo"] == "bar" + return fedConfig.Spec.Template.Labels["foo"] == "bar" + }, timeout, interval).Should(BeTrue()) + + // Create a receiver + Expect(cl.Create(context.Background(), receiver)).Should(Succeed()) + Expect(r.reconcile(receiver)).Should(Succeed()) + + fedReceiver := &v1beta1.FederatedNotificationReceiver{} + By("Expecting to create federated object successfully") + Eventually(func() bool { + err := ksCache.Get(context.Background(), client.ObjectKey{Name: receiver.Name}, fedReceiver) + Expect(err).Should(Succeed()) + return !fedReceiver.CreationTimestamp.IsZero() + }, timeout, interval).Should(BeTrue()) + + // Update a receiver + err = ksCache.Get(context.Background(), client.ObjectKey{Name: receiver.Name}, receiver) + Expect(err).Should(Succeed()) + receiver.Labels = map[string]string{"foo": "bar"} + Expect(cl.Update(context.Background(), receiver)).Should(Succeed()) + Expect(r.reconcile(receiver)).Should(Succeed()) + + By("Expecting to update federated object successfully") + Eventually(func() bool { + err := ksCache.Get(context.Background(), client.ObjectKey{Name: receiver.Name}, fedReceiver) + Expect(err).Should(Succeed()) + return fedReceiver.Spec.Template.Labels["foo"] == "bar" + }, timeout, interval).Should(BeTrue()) + + // Add a cluster + Expect(cl.Create(informerCacheCtx, host)).Should(Succeed()) + Expect(r.reconcile(secret)).Should(Succeed()) + + By("Expecting to update federated secret successfully") + Eventually(func() bool { + err := ksCache.Get(context.Background(), client.ObjectKey{Name: secret.Name, Namespace: constants.NotificationSecretNamespace}, fedSecret) + Expect(err).Should(Succeed()) + + if fedSecret.Spec.Overrides == nil || + len(fedSecret.Spec.Overrides) != 1 || + fedSecret.Spec.Overrides[0].ClusterName != "host" { + return false + } + + return true + }, timeout, interval).Should(BeTrue()) + + // Delete a cluster + Expect(cl.Delete(informerCacheCtx, host)).Should(Succeed()) + Expect(r.reconcile(secret)).Should(Succeed()) + + By("Expecting to update federated secret successfully") + Eventually(func() bool { + err := ksCache.Get(context.Background(), client.ObjectKey{Name: secret.Name, Namespace: constants.NotificationSecretNamespace}, fedSecret) + Expect(err).Should(Succeed()) + + if fedSecret.Spec.Overrides != nil || + len(fedSecret.Spec.Overrides) != 0 { + return false + } + + return true }, timeout, interval).Should(BeTrue()) }) })