diff --git a/pkg/cmd/spoke/operator.go b/pkg/cmd/spoke/operator.go index c90a65cfb..f6d2e594c 100644 --- a/pkg/cmd/spoke/operator.go +++ b/pkg/cmd/spoke/operator.go @@ -45,6 +45,9 @@ func NewKlusterletOperatorCmd() *cobra.Command { flags.BoolVar(&klOptions.DisableAddonNamespace, "disable-default-addon-namespace", false, "If set, will not create default open-cluster-management-agent-addon ns") + flags.BoolVar(&klOptions.EnableSyncLabels, "enable-sync-labels", false, + "If set, will sync the labels of Klusterlet CR to all agent resources") + opts.AddFlags(flags) return cmd diff --git a/pkg/operator/operators/klusterlet/controllers/klusterletcontroller/klusterlet_cleanup_controller_test.go b/pkg/operator/operators/klusterlet/controllers/klusterletcontroller/klusterlet_cleanup_controller_test.go index 966723fd6..4c08dcc22 100644 --- a/pkg/operator/operators/klusterlet/controllers/klusterletcontroller/klusterlet_cleanup_controller_test.go +++ b/pkg/operator/operators/klusterlet/controllers/klusterletcontroller/klusterlet_cleanup_controller_test.go @@ -33,7 +33,8 @@ func TestSyncDelete(t *testing.T) { newAppliedManifestWorks("testhost-2", []string{workv1.AppliedManifestWorkFinalizer}, false), } syncContext := testingcommon.NewFakeSyncContext(t, "klusterlet") - controller := newTestController(t, klusterlet, syncContext.Recorder(), appliedManifestWorks, namespace, bootstrapKubeConfigSecret) + controller := newTestController(t, klusterlet, syncContext.Recorder(), appliedManifestWorks, false, + namespace, bootstrapKubeConfigSecret) err := controller.cleanupController.sync(context.TODO(), syncContext) if err != nil { diff --git a/pkg/operator/operators/klusterlet/controllers/klusterletcontroller/klusterlet_controller.go b/pkg/operator/operators/klusterlet/controllers/klusterletcontroller/klusterlet_controller.go index 3d9bf1c45..4ac05b899 100644 --- a/pkg/operator/operators/klusterlet/controllers/klusterletcontroller/klusterlet_controller.go +++ b/pkg/operator/operators/klusterlet/controllers/klusterletcontroller/klusterlet_controller.go @@ -55,6 +55,7 @@ type klusterletController struct { controlPlaneNodeLabelSelector string deploymentReplicas int32 disableAddonNamespace bool + enableSyncLabels bool } type klusterletReconcile interface { @@ -83,6 +84,7 @@ func NewKlusterletController( controlPlaneNodeLabelSelector string, deploymentReplicas int32, disableAddonNamespace bool, + enableSyncLabels bool, recorder events.Recorder) factory.Controller { controller := &klusterletController{ kubeClient: kubeClient, @@ -96,6 +98,7 @@ func NewKlusterletController( controlPlaneNodeLabelSelector: controlPlaneNodeLabelSelector, deploymentReplicas: deploymentReplicas, disableAddonNamespace: disableAddonNamespace, + enableSyncLabels: enableSyncLabels, } return factory.New().WithSync(controller.sync). @@ -225,7 +228,10 @@ func (n *klusterletController) sync(ctx context.Context, controllerContext facto ResourceRequirementResourceType: helpers.ResourceType(klusterlet), ResourceRequirements: resourceRequirements, DisableAddonNamespace: n.disableAddonNamespace, - Labels: helpers.GetKlusterletAgentLabels(klusterlet), + } + + if n.enableSyncLabels { + config.Labels = helpers.GetKlusterletAgentLabels(klusterlet) } managedClusterClients, err := n.managedClusterClientsBuilder. diff --git a/pkg/operator/operators/klusterlet/controllers/klusterletcontroller/klusterlet_controller_test.go b/pkg/operator/operators/klusterlet/controllers/klusterletcontroller/klusterlet_controller_test.go index 97e7f9f0c..e5642dd10 100644 --- a/pkg/operator/operators/klusterlet/controllers/klusterletcontroller/klusterlet_controller_test.go +++ b/pkg/operator/operators/klusterlet/controllers/klusterletcontroller/klusterlet_controller_test.go @@ -174,7 +174,7 @@ func newServiceAccount(name, namespace string, referenceSecret string) *corev1.S } func newTestController(t *testing.T, klusterlet *operatorapiv1.Klusterlet, recorder events.Recorder, - appliedManifestWorks []runtime.Object, objects ...runtime.Object) *testController { + appliedManifestWorks []runtime.Object, enableSyncLabels bool, objects ...runtime.Object) *testController { fakeKubeClient := fakekube.NewSimpleClientset(objects...) fakeAPIExtensionClient := fakeapiextensions.NewSimpleClientset() fakeOperatorClient := fakeoperatorclient.NewSimpleClientset(klusterlet) @@ -192,6 +192,7 @@ func newTestController(t *testing.T, klusterlet *operatorapiv1.Klusterlet, recor cache: resourceapply.NewResourceCache(), managedClusterClientsBuilder: newManagedClusterClientsBuilder(fakeKubeClient, fakeAPIExtensionClient, fakeWorkClient.WorkV1().AppliedManifestWorks(), recorder), + enableSyncLabels: enableSyncLabels, } cleanupController := &klusterletCleanupController{ @@ -456,14 +457,14 @@ func assertWorkDeployment(t *testing.T, actions []clienttesting.Action, verb, cl } } -func ensureObject(t *testing.T, object runtime.Object, klusterlet *operatorapiv1.Klusterlet) { +func ensureObject(t *testing.T, object runtime.Object, klusterlet *operatorapiv1.Klusterlet, enableSyncLabels bool) { access, err := meta.Accessor(object) if err != nil { t.Errorf("Unable to access objectmeta: %v", err) return } - if !helpers.MapCompare(helpers.GetKlusterletAgentLabels(klusterlet), access.GetLabels()) { + if enableSyncLabels && !helpers.MapCompare(helpers.GetKlusterletAgentLabels(klusterlet), access.GetLabels()) { t.Errorf("the labels of klusterlet are not synced to %v", access.GetName()) return } @@ -504,125 +505,164 @@ func ensureObject(t *testing.T, object runtime.Object, klusterlet *operatorapiv1 // TestSyncDeploy test deployment of klusterlet components func TestSyncDeploy(t *testing.T) { - klusterlet := newKlusterlet("klusterlet", "testns", "cluster1") - bootStrapSecret := newSecret(helpers.BootstrapHubKubeConfig, "testns") - hubKubeConfigSecret := newSecret(helpers.HubKubeConfig, "testns") - hubKubeConfigSecret.Data["kubeconfig"] = []byte("dummuykubeconnfig") - namespace := newNamespace("testns") - syncContext := testingcommon.NewFakeSyncContext(t, "klusterlet") - controller := newTestController(t, klusterlet, syncContext.Recorder(), nil, bootStrapSecret, hubKubeConfigSecret, namespace) - - err := controller.controller.sync(context.TODO(), syncContext) - if err != nil { - t.Errorf("Expected non error when sync, %v", err) + cases := []struct { + name string + enableSyncLabels bool + }{ + { + name: "disable sync labels", + enableSyncLabels: false, + }, + { + name: "enable sync labels", + enableSyncLabels: true, + }, } - var createObjects []runtime.Object - kubeActions := controller.kubeClient.Actions() - for _, action := range kubeActions { - if action.GetVerb() == createVerb { - object := action.(clienttesting.CreateActionImpl).Object - createObjects = append(createObjects, object) + for _, c := range cases { + klusterlet := newKlusterlet("klusterlet", "testns", "cluster1") + bootStrapSecret := newSecret(helpers.BootstrapHubKubeConfig, "testns") + hubKubeConfigSecret := newSecret(helpers.HubKubeConfig, "testns") + hubKubeConfigSecret.Data["kubeconfig"] = []byte("dummuykubeconnfig") + namespace := newNamespace("testns") + syncContext := testingcommon.NewFakeSyncContext(t, "klusterlet") - } - } + t.Run(c.name, func(t *testing.T) { + controller := newTestController(t, klusterlet, syncContext.Recorder(), nil, c.enableSyncLabels, + bootStrapSecret, hubKubeConfigSecret, namespace) - // Check if resources are created as expected - // 11 managed static manifests + 12 management static manifests - 2 duplicated service account manifests + 1 addon namespace + 2 deployments - if len(createObjects) != 24 { - t.Errorf("Expect 24 objects created in the sync loop, actual %d", len(createObjects)) - } - for _, object := range createObjects { - ensureObject(t, object, klusterlet) - } + err := controller.controller.sync(context.TODO(), syncContext) + if err != nil { + t.Errorf("Expected non error when sync, %v", err) + } - apiExtenstionAction := controller.apiExtensionClient.Actions() - var createCRDObjects []runtime.Object - for _, action := range apiExtenstionAction { - if action.GetVerb() == createVerb && action.GetResource().Resource == crdResourceName { - object := action.(clienttesting.CreateActionImpl).Object - createCRDObjects = append(createCRDObjects, object) - } - } - if len(createCRDObjects) != 2 { - t.Errorf("Expect 2 objects created in the sync loop, actual %d", len(createCRDObjects)) - } + var createObjects []runtime.Object + kubeActions := controller.kubeClient.Actions() + for _, action := range kubeActions { + if action.GetVerb() == createVerb { + object := action.(clienttesting.CreateActionImpl).Object + createObjects = append(createObjects, object) + } + } - operatorAction := controller.operatorClient.Actions() - testingcommon.AssertActions(t, operatorAction, "patch") - klusterlet = &operatorapiv1.Klusterlet{} - patchData := operatorAction[0].(clienttesting.PatchActionImpl).Patch - err = json.Unmarshal(patchData, klusterlet) - if err != nil { - t.Fatal(err) + // Check if resources are created as expected + // 11 managed static manifests + 12 management static manifests - 2 duplicated service account manifests + 1 addon namespace + 2 deployments + if len(createObjects) != 24 { + t.Errorf("Expect 24 objects created in the sync loop, actual %d", len(createObjects)) + } + for _, object := range createObjects { + ensureObject(t, object, klusterlet, false) + } + + apiExtenstionAction := controller.apiExtensionClient.Actions() + var createCRDObjects []runtime.Object + for _, action := range apiExtenstionAction { + if action.GetVerb() == createVerb && action.GetResource().Resource == crdResourceName { + object := action.(clienttesting.CreateActionImpl).Object + createCRDObjects = append(createCRDObjects, object) + } + } + if len(createCRDObjects) != 2 { + t.Errorf("Expect 2 objects created in the sync loop, actual %d", len(createCRDObjects)) + } + + operatorAction := controller.operatorClient.Actions() + testingcommon.AssertActions(t, operatorAction, "patch") + klusterlet = &operatorapiv1.Klusterlet{} + patchData := operatorAction[0].(clienttesting.PatchActionImpl).Patch + err = json.Unmarshal(patchData, klusterlet) + if err != nil { + t.Fatal(err) + } + testinghelper.AssertOnlyConditions( + t, klusterlet, + testinghelper.NamedCondition(operatorapiv1.ConditionKlusterletApplied, "KlusterletApplied", metav1.ConditionTrue), + testinghelper.NamedCondition(helpers.FeatureGatesTypeValid, helpers.FeatureGatesReasonAllValid, metav1.ConditionTrue), + ) + }) } - testinghelper.AssertOnlyConditions( - t, klusterlet, - testinghelper.NamedCondition(operatorapiv1.ConditionKlusterletApplied, "KlusterletApplied", metav1.ConditionTrue), - testinghelper.NamedCondition(helpers.FeatureGatesTypeValid, helpers.FeatureGatesReasonAllValid, metav1.ConditionTrue), - ) } func TestSyncDeploySingleton(t *testing.T) { - klusterlet := newKlusterlet("klusterlet", "testns", "cluster1") - klusterlet.SetLabels(map[string]string{"test": "test", "abc": "abc"}) - klusterlet.Spec.DeployOption.Mode = operatorapiv1.InstallModeSingleton - bootStrapSecret := newSecret(helpers.BootstrapHubKubeConfig, "testns") - hubKubeConfigSecret := newSecret(helpers.HubKubeConfig, "testns") - hubKubeConfigSecret.Data["kubeconfig"] = []byte("dummuykubeconnfig") - namespace := newNamespace("testns") - syncContext := testingcommon.NewFakeSyncContext(t, "klusterlet") - controller := newTestController(t, klusterlet, syncContext.Recorder(), nil, bootStrapSecret, hubKubeConfigSecret, namespace) - - err := controller.controller.sync(context.TODO(), syncContext) - if err != nil { - t.Errorf("Expected non error when sync, %v", err) + cases := []struct { + name string + enableSyncLabels bool + }{ + { + name: "disable sync labels", + enableSyncLabels: false, + }, + { + name: "enable sync labels", + enableSyncLabels: true, + }, } - var createObjects []runtime.Object - kubeActions := controller.kubeClient.Actions() - for _, action := range kubeActions { - if action.GetVerb() == createVerb { - object := action.(clienttesting.CreateActionImpl).Object - createObjects = append(createObjects, object) + for _, c := range cases { + klusterlet := newKlusterlet("klusterlet", "testns", "cluster1") + klusterlet.SetLabels(map[string]string{"test": "test", "abc": "abc"}) + klusterlet.Spec.DeployOption.Mode = operatorapiv1.InstallModeSingleton + bootStrapSecret := newSecret(helpers.BootstrapHubKubeConfig, "testns") + hubKubeConfigSecret := newSecret(helpers.HubKubeConfig, "testns") + hubKubeConfigSecret.Data["kubeconfig"] = []byte("dummuykubeconnfig") + namespace := newNamespace("testns") + syncContext := testingcommon.NewFakeSyncContext(t, "klusterlet") - } - } + t.Run(c.name, func(t *testing.T) { + controller := newTestController(t, klusterlet, syncContext.Recorder(), nil, + c.enableSyncLabels, bootStrapSecret, hubKubeConfigSecret, namespace) - // Check if resources are created as expected - // 10 managed static manifests + 11 management static manifests - 1 service account manifests + 1 addon namespace + 1 deployments - if len(createObjects) != 22 { - t.Errorf("Expect 21 objects created in the sync loop, actual %d", len(createObjects)) - } - for _, object := range createObjects { - ensureObject(t, object, klusterlet) - } + err := controller.controller.sync(context.TODO(), syncContext) + if err != nil { + t.Errorf("Expected non error when sync, %v", err) + } - apiExtenstionAction := controller.apiExtensionClient.Actions() - var createCRDObjects []runtime.Object - for _, action := range apiExtenstionAction { - if action.GetVerb() == createVerb && action.GetResource().Resource == crdResourceName { - object := action.(clienttesting.CreateActionImpl).Object - createCRDObjects = append(createCRDObjects, object) - } - } - if len(createCRDObjects) != 2 { - t.Errorf("Expect 2 objects created in the sync loop, actual %d", len(createCRDObjects)) - } + var createObjects []runtime.Object + kubeActions := controller.kubeClient.Actions() + for _, action := range kubeActions { + if action.GetVerb() == createVerb { + object := action.(clienttesting.CreateActionImpl).Object + createObjects = append(createObjects, object) - operatorAction := controller.operatorClient.Actions() - testingcommon.AssertActions(t, operatorAction, "patch") - klusterlet = &operatorapiv1.Klusterlet{} - patchData := operatorAction[0].(clienttesting.PatchActionImpl).Patch - err = json.Unmarshal(patchData, klusterlet) - if err != nil { - t.Fatal(err) + } + } + + // Check if resources are created as expected + // 10 managed static manifests + 11 management static manifests - 1 service account manifests + 1 addon namespace + 1 deployments + if len(createObjects) != 22 { + t.Errorf("Expect 21 objects created in the sync loop, actual %d", len(createObjects)) + } + for _, object := range createObjects { + ensureObject(t, object, klusterlet, false) + } + + apiExtenstionAction := controller.apiExtensionClient.Actions() + var createCRDObjects []runtime.Object + for _, action := range apiExtenstionAction { + if action.GetVerb() == createVerb && action.GetResource().Resource == crdResourceName { + object := action.(clienttesting.CreateActionImpl).Object + createCRDObjects = append(createCRDObjects, object) + } + } + if len(createCRDObjects) != 2 { + t.Errorf("Expect 2 objects created in the sync loop, actual %d", len(createCRDObjects)) + } + + operatorAction := controller.operatorClient.Actions() + testingcommon.AssertActions(t, operatorAction, "patch") + klusterlet = &operatorapiv1.Klusterlet{} + patchData := operatorAction[0].(clienttesting.PatchActionImpl).Patch + err = json.Unmarshal(patchData, klusterlet) + if err != nil { + t.Fatal(err) + } + testinghelper.AssertOnlyConditions( + t, klusterlet, + testinghelper.NamedCondition(operatorapiv1.ConditionKlusterletApplied, "KlusterletApplied", metav1.ConditionTrue), + testinghelper.NamedCondition(helpers.FeatureGatesTypeValid, helpers.FeatureGatesReasonAllValid, metav1.ConditionTrue), + ) + }) } - testinghelper.AssertOnlyConditions( - t, klusterlet, - testinghelper.NamedCondition(operatorapiv1.ConditionKlusterletApplied, "KlusterletApplied", metav1.ConditionTrue), - testinghelper.NamedCondition(helpers.FeatureGatesTypeValid, helpers.FeatureGatesReasonAllValid, metav1.ConditionTrue), - ) } // TestSyncDeployHosted test deployment of klusterlet components in hosted mode @@ -666,7 +706,7 @@ func TestSyncDeployHosted(t *testing.T) { t.Errorf("Expect 16 objects created in the sync loop, actual %d", len(createObjectsManagement)) } for _, object := range createObjectsManagement { - ensureObject(t, object, klusterlet) + ensureObject(t, object, klusterlet, false) } var createObjectsManaged []runtime.Object @@ -684,7 +724,7 @@ func TestSyncDeployHosted(t *testing.T) { t.Errorf("Expect 15 objects created in the sync loop, actual %d", len(createObjectsManaged)) } for _, object := range createObjectsManaged { - ensureObject(t, object, klusterlet) + ensureObject(t, object, klusterlet, false) } apiExtenstionAction := controller.apiExtensionClient.Actions() @@ -764,7 +804,8 @@ func TestRemoveOldNamespace(t *testing.T) { klusterletNamespaceLabelKey: "klusterlet", } syncContext := testingcommon.NewFakeSyncContext(t, "klusterlet") - controller := newTestController(t, klusterlet, syncContext.Recorder(), nil, bootStrapSecret, hubKubeConfigSecret, namespace, oldNamespace) + controller := newTestController(t, klusterlet, syncContext.Recorder(), nil, false, + bootStrapSecret, hubKubeConfigSecret, namespace, oldNamespace) err := controller.controller.sync(context.TODO(), syncContext) if err != nil { @@ -819,7 +860,8 @@ func TestSyncDisableAddonNamespace(t *testing.T) { hubKubeConfigSecret.Data["kubeconfig"] = []byte("dummuykubeconnfig") namespace := newNamespace("testns") syncContext := testingcommon.NewFakeSyncContext(t, "klusterlet") - controller := newTestController(t, klusterlet, syncContext.Recorder(), nil, bootStrapSecret, hubKubeConfigSecret, namespace) + controller := newTestController(t, klusterlet, syncContext.Recorder(), nil, false, + bootStrapSecret, hubKubeConfigSecret, namespace) controller.controller.disableAddonNamespace = true err := controller.controller.sync(context.TODO(), syncContext) @@ -914,7 +956,8 @@ func TestReplica(t *testing.T) { } syncContext := testingcommon.NewFakeSyncContext(t, "klusterlet") - controller := newTestController(t, klusterlet, syncContext.Recorder(), nil, objects...) + controller := newTestController(t, klusterlet, syncContext.Recorder(), nil, false, + objects...) err := controller.controller.sync(context.TODO(), syncContext) if err != nil { @@ -979,7 +1022,8 @@ func TestClusterNameChange(t *testing.T) { hubSecret.Data["kubeconfig"] = []byte("dummuykubeconnfig") hubSecret.Data["cluster-name"] = []byte("cluster1") syncContext := testingcommon.NewFakeSyncContext(t, "klusterlet") - controller := newTestController(t, klusterlet, syncContext.Recorder(), nil, bootStrapSecret, hubSecret, namespace) + controller := newTestController(t, klusterlet, syncContext.Recorder(), nil, false, + bootStrapSecret, hubSecret, namespace) err := controller.controller.sync(context.TODO(), syncContext) if err != nil { @@ -1067,7 +1111,8 @@ func TestSyncWithPullSecret(t *testing.T) { namespace := newNamespace("testns") pullSecret := newSecret(helpers.ImagePullSecret, "open-cluster-management") syncContext := testingcommon.NewFakeSyncContext(t, "klusterlet") - controller := newTestController(t, klusterlet, syncContext.Recorder(), nil, bootStrapSecret, hubKubeConfigSecret, namespace, pullSecret) + controller := newTestController(t, klusterlet, syncContext.Recorder(), nil, false, + bootStrapSecret, hubKubeConfigSecret, namespace, pullSecret) err := controller.controller.sync(context.TODO(), syncContext) if err != nil { @@ -1096,7 +1141,8 @@ func TestDeployOnKube111(t *testing.T) { hubKubeConfigSecret.Data["kubeconfig"] = []byte("dummuykubeconnfig") namespace := newNamespace("testns") syncContext := testingcommon.NewFakeSyncContext(t, "klusterlet") - controller := newTestController(t, klusterlet, syncContext.Recorder(), nil, bootStrapSecret, hubKubeConfigSecret, namespace) + controller := newTestController(t, klusterlet, syncContext.Recorder(), nil, false, + bootStrapSecret, hubKubeConfigSecret, namespace) kubeVersion, _ := version.ParseGeneric("v1.11.0") controller.controller.kubeVersion = kubeVersion controller.cleanupController.kubeVersion = kubeVersion @@ -1123,7 +1169,7 @@ func TestDeployOnKube111(t *testing.T) { t.Errorf("Expect 26 objects created in the sync loop, actual %d", len(createObjects)) } for _, object := range createObjects { - ensureObject(t, object, klusterlet) + ensureObject(t, object, klusterlet, false) } operatorAction := controller.operatorClient.Actions() diff --git a/pkg/operator/operators/klusterlet/options.go b/pkg/operator/operators/klusterlet/options.go index d9fd68a5d..2906e53d7 100644 --- a/pkg/operator/operators/klusterlet/options.go +++ b/pkg/operator/operators/klusterlet/options.go @@ -29,6 +29,7 @@ type Options struct { ControlPlaneNodeLabelSelector string DeploymentReplicas int32 DisableAddonNamespace bool + EnableSyncLabels bool } // RunKlusterletOperator starts a new klusterlet operator @@ -110,6 +111,7 @@ func (o *Options) RunKlusterletOperator(ctx context.Context, controllerContext * o.ControlPlaneNodeLabelSelector, o.DeploymentReplicas, o.DisableAddonNamespace, + o.EnableSyncLabels, controllerContext.EventRecorder) klusterletCleanupController := klusterletcontroller.NewKlusterletCleanupController( diff --git a/test/integration/operator/klusterlet_test.go b/test/integration/operator/klusterlet_test.go index 9ab27cb2e..ea66d9abe 100644 --- a/test/integration/operator/klusterlet_test.go +++ b/test/integration/operator/klusterlet_test.go @@ -23,7 +23,7 @@ import ( ) func startKlusterletOperator(ctx context.Context) { - o := &klusterlet.Options{} + o := &klusterlet.Options{EnableSyncLabels: true} err := o.RunKlusterletOperator(ctx, &controllercmd.ControllerContext{ KubeConfig: restConfig, EventRecorder: util.NewIntegrationTestEventRecorder("integration"), @@ -167,14 +167,14 @@ var _ = ginkgo.Describe("Klusterlet", func() { }, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue()) // Check clusterrole/clusterrolebinding - gomega.Eventually(func() bool { + gomega.Eventually(func() error { clusterRoles, err := kubeClient.RbacV1().ClusterRoles().List(context.Background(), metav1.ListOptions{LabelSelector: agentLabelSelector}) if err != nil { - return false + return fmt.Errorf("unable to list cluster roles: %v", err) } if len(clusterRoles.Items) != 6 { - return false + return fmt.Errorf("expected 6 clusterRoles.Items, got %v", len(clusterRoles.Items)) } for _, clusterRole := range clusterRoles.Items { if clusterRole.GetName() != registrationManagedRoleName && @@ -183,11 +183,11 @@ var _ = ginkgo.Describe("Klusterlet", func() { clusterRole.GetName() != addonManagementRoleName2 && clusterRole.GetName() != workExecutionRoleName && clusterRole.GetName() != workAggregateRoleName { - return false + return fmt.Errorf("unexpected clusterRole %s", clusterRole.GetName()) } } - return true - }, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue()) + return nil + }, eventuallyTimeout, eventuallyInterval).ShouldNot(gomega.HaveOccurred()) gomega.Eventually(func() bool { clusterRoleBindings, err := kubeClient.RbacV1().ClusterRoleBindings().List(context.Background(),