From 6394066c32de97caddb240a1d8506aa22d7cce74 Mon Sep 17 00:00:00 2001 From: Per Goncalves da Silva Date: Thu, 13 Jul 2023 16:31:52 +0200 Subject: [PATCH] refactor operator group cluster role name Signed-off-by: Per Goncalves da Silva --- pkg/controller/operators/olm/operator_test.go | 453 +++++++++++++++++- pkg/controller/operators/olm/operatorgroup.go | 89 +++- pkg/lib/ownerutil/util.go | 11 +- test/e2e/operator_groups_e2e_test.go | 40 +- 4 files changed, 541 insertions(+), 52 deletions(-) diff --git a/pkg/controller/operators/olm/operator_test.go b/pkg/controller/operators/olm/operator_test.go index 86e331c2aa7..94e47d790e2 100644 --- a/pkg/controller/operators/olm/operator_test.go +++ b/pkg/controller/operators/olm/operator_test.go @@ -8,6 +8,7 @@ import ( "crypto/x509" "crypto/x509/pkix" "encoding/pem" + "errors" "fmt" "math" "math/big" @@ -51,6 +52,9 @@ import ( operatorsv1 "github.com/operator-framework/api/pkg/operators/v1" "github.com/operator-framework/api/pkg/operators/v1alpha1" + opregistry "github.com/operator-framework/operator-registry/pkg/registry" + clienttesting "k8s.io/client-go/testing" + "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned" "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned/fake" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/certs" @@ -65,8 +69,6 @@ import ( "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/scoped" - opregistry "github.com/operator-framework/operator-registry/pkg/registry" - clienttesting "k8s.io/client-go/testing" ) type TestStrategy struct{} @@ -4518,6 +4520,433 @@ func TestSyncOperatorGroups(t *testing.T) { LastUpdated: &now, }, }, + { + name: "MatchingNamespace/NoCSVs/CreatesClusterRoles", + expectedEqual: true, + initial: initial{ + operatorGroup: &operatorsv1.OperatorGroup{ + ObjectMeta: metav1.ObjectMeta{ + Name: "operator-group-1", + Namespace: operatorNamespace, + }, + Spec: operatorsv1.OperatorGroupSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "app-a"}, + }, + }, + }, + k8sObjs: []runtime.Object{ + &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: operatorNamespace, + }, + }, + &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: targetNamespace, + Labels: map[string]string{"app": "app-a"}, + }, + }, + }, + }, + expectedStatus: operatorsv1.OperatorGroupStatus{ + Namespaces: []string{targetNamespace}, + LastUpdated: &now, + }, + final: final{objects: map[string][]runtime.Object{ + "": { + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "", + Name: "olm.operatorgroup.admin-aaaaa", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "", + Name: "olm.operatorgroup.edit-aaaaa", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "", + Name: "olm.operatorgroup.view-aaaaa", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + }, + }}, + }, + { + // check that even if old cluster roles exist, we create the new ones and leave the old ones unchanged + name: "MatchingNamespace/NoCSVs/UpdatesOldClusterRoles", + expectedEqual: true, + initial: initial{ + operatorGroup: &operatorsv1.OperatorGroup{ + ObjectMeta: metav1.ObjectMeta{ + Name: "operator-group-1", + Namespace: operatorNamespace, + }, + Spec: operatorsv1.OperatorGroupSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "app-a"}, + }, + }, + }, + k8sObjs: []runtime.Object{ + &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: operatorNamespace, + }, + }, + &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: targetNamespace, + Labels: map[string]string{"app": "app-a"}, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "", + Name: "operator-group-1-admin", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "", + Name: "operator-group-1-view", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "", + Name: "operator-group-1-edit", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + }, + }, + expectedStatus: operatorsv1.OperatorGroupStatus{ + Namespaces: []string{targetNamespace}, + LastUpdated: &now, + }, + final: final{objects: map[string][]runtime.Object{ + "": { + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "", + Name: "olm.operatorgroup.admin-aaaaa", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "", + Name: "olm.operatorgroup.edit-aaaaa", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "", + Name: "olm.operatorgroup.view-aaaaa", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "", + Name: "operator-group-1-admin", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "", + Name: "operator-group-1-view", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "", + Name: "operator-group-1-edit", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + }, + }}, + }, + { + // check that even if old cluster roles exist, we create the new ones and leave the old ones unchanged + name: "MatchingNamespace/NoCSVs/DoesNotUpdatesClusterRoles", + expectedEqual: true, + initial: initial{ + operatorGroup: &operatorsv1.OperatorGroup{ + ObjectMeta: metav1.ObjectMeta{ + Name: "operator-group-1", + Namespace: operatorNamespace, + }, + Spec: operatorsv1.OperatorGroupSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "app-a"}, + }, + }, + }, + k8sObjs: []runtime.Object{ + &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: operatorNamespace, + }, + }, + &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: targetNamespace, + Labels: map[string]string{"app": "app-a"}, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "", + Name: "olm.operatorgroup.admin-xxxxx", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "", + Name: "olm.operatorgroup.edit-yyyyy", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "", + Name: "olm.operatorgroup.view-zzzzz", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }}, + }, + expectedStatus: operatorsv1.OperatorGroupStatus{ + Namespaces: []string{targetNamespace}, + LastUpdated: &now, + }, + final: final{objects: map[string][]runtime.Object{ + "": { + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "", + Name: "olm.operatorgroup.admin-xxxxx", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "", + Name: "olm.operatorgroup.edit-yyyyy", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "", + Name: "olm.operatorgroup.view-zzzzz", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "", + Name: "operator-group-1-admin", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "", + Name: "operator-group-1-view", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "", + Name: "operator-group-1-edit", + Labels: map[string]string{ + "olm.owner": "operator-group-1", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + }, + }, + }, + }, + { + name: "MatchingNamespace/NoCSVs/Updates" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "ClusterRoles", + expectedEqual: true, + initial: initial{ + operatorGroup: &operatorsv1.OperatorGroup{ + ObjectMeta: metav1.ObjectMeta{ + Name: "operator-group-1", + Namespace: operatorNamespace, + UID: "1234", + }, + Spec: operatorsv1.OperatorGroupSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "app-a"}, + }, + }, + }, + k8sObjs: []runtime.Object{ + &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: operatorNamespace, + }, + }, + &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: targetNamespace, + Labels: map[string]string{"app": "app-a"}, + }, + }, + }, + }, + expectedStatus: operatorsv1.OperatorGroupStatus{ + Namespaces: []string{targetNamespace}, + LastUpdated: &now, + }, + final: final{objects: map[string][]runtime.Object{ + "": { + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "", + Name: "olm.operatorgroup.admin-aaaaa", + Labels: map[string]string{ + "olm.owner": "1234", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "", + Name: "olm.operatorgroup.edit-aaaaa", + Labels: map[string]string{ + "olm.owner": "1234", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "", + Name: "olm.operatorgroup.view-aaaaa", + Labels: map[string]string{ + "olm.owner": "1234", + "olm.owner.namespace": "operator-ns", + "olm.owner.kind": "OperatorGroup", + }, + }, + }, + }, + }}, + }, { name: "MatchingNamespace/CSVPresent/Found", expectedEqual: true, @@ -4967,6 +5396,16 @@ func TestSyncOperatorGroups(t *testing.T) { return copied } + // change the genName function to return a predictable value + oldGenName := genName + genName = func(prefix string) string { + return fmt.Sprintf("%saaaaa", prefix) + } + defer func() { + // make sure to change it back! + genName = oldGenName + }() + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Pick out Namespaces @@ -5106,7 +5545,10 @@ func TestSyncOperatorGroups(t *testing.T) { for namespace, objects := range tt.final.objects { if err := RequireObjectsInCache(t, op.lister, namespace, objects, true); err != nil { foundErr = err - return false, nil + if apierrors.IsNotFound(err) { + return false, nil + } + return false, err } } @@ -5349,7 +5791,10 @@ func RequireObjectsInCache(t *testing.T, lister operatorlister.OperatorLister, n require.Failf(t, "couldn't find expected object", "%#v", object) } if err != nil { - return fmt.Errorf("namespace: %v, error: %v", namespace, err) + if apierrors.IsNotFound(err) { + return err + } + return errors.Join(err, fmt.Errorf("namespace: %v, error: %v", namespace, err)) } if doCompare { if !reflect.DeepEqual(object, fetched) { diff --git a/pkg/controller/operators/olm/operatorgroup.go b/pkg/controller/operators/olm/operatorgroup.go index 745048cbb02..110b33b5cd5 100644 --- a/pkg/controller/operators/olm/operatorgroup.go +++ b/pkg/controller/operators/olm/operatorgroup.go @@ -7,7 +7,8 @@ import ( "reflect" "strings" - utillabels "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/util/labels" + "k8s.io/apiserver/pkg/storage/names" + "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" @@ -17,14 +18,17 @@ import ( "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/errors" + utillabels "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/util/labels" + operatorsv1 "github.com/operator-framework/api/pkg/operators/v1" "github.com/operator-framework/api/pkg/operators/v1alpha1" + opregistry "github.com/operator-framework/operator-registry/pkg/registry" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/decorators" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/cache" hashutil "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/util/hash" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil" - opregistry "github.com/operator-framework/operator-registry/pkg/registry" ) const ( @@ -43,6 +47,7 @@ var ( EditSuffix: EditVerbs, ViewSuffix: ViewVerbs, } + genName = names.SimpleNameGenerator.GenerateName ) func aggregationLabelFromAPIKey(k opregistry.APIKey, suffix string) (string, error) { @@ -979,38 +984,30 @@ func (a *Operator) updateNamespaceList(op *operatorsv1.OperatorGroup) ([]string, } func (a *Operator) ensureOpGroupClusterRole(op *operatorsv1.OperatorGroup, suffix string, apis cache.APISet) error { + // create target cluster role spec + clusterRolePrefix := fmt.Sprintf("olm.operatorgroup.%s-", suffix) clusterRole := &rbacv1.ClusterRole{ ObjectMeta: metav1.ObjectMeta{ - Name: strings.Join([]string{op.GetName(), suffix}, "-"), + Name: genName(clusterRolePrefix), }, } - var selectors []metav1.LabelSelector - for api := range apis { - aggregationLabel, err := aggregationLabelFromAPIKey(api, suffix) - if err != nil { - return err - } - selectors = append(selectors, metav1.LabelSelector{ - MatchLabels: map[string]string{ - aggregationLabel: "true", - }, - }) - } - if len(selectors) > 0 { - clusterRole.AggregationRule = &rbacv1.AggregationRule{ - ClusterRoleSelectors: selectors, - } - } - err := ownerutil.AddOwnerLabels(clusterRole, op) + + var err error + clusterRole.AggregationRule, err = a.getClusterRoleAggregationRule(apis, suffix) if err != nil { return err } - existingRole, err := a.lister.RbacV1().ClusterRoleLister().Get(clusterRole.Name) - if err != nil && !apierrors.IsNotFound(err) { + if err := ownerutil.AddOwnerLabels(clusterRole, op); err != nil { return err } - if apierrors.IsNotFound(err) { + + // get existing cluster role for this level (suffix: admin, edit, view)) + existingRole, err := a.getExistingClusterRoleByOwnerAndLevel(op, suffix) + if err != nil { + return err + } + if existingRole == nil { existingRole, err = a.opClient.KubernetesInterface().RbacV1().ClusterRoles().Create(context.TODO(), clusterRole, metav1.CreateOptions{}) if err == nil { return nil @@ -1021,10 +1018,14 @@ func (a *Operator) ensureOpGroupClusterRole(op *operatorsv1.OperatorGroup, suffi } } - if existingRole != nil && labels.Equals(existingRole.Labels, clusterRole.Labels) && reflect.DeepEqual(existingRole.AggregationRule, clusterRole.AggregationRule) { - return nil + // if the existing role conforms to the naming convention, check for skew + if existingRole != nil && strings.HasPrefix(existingRole.Name, clusterRolePrefix) { + if labels.Equals(existingRole.Labels, clusterRole.Labels) && reflect.DeepEqual(existingRole.AggregationRule, clusterRole.AggregationRule) { + return nil + } } + // if the existing role does not conform to the naming convention, or it has skewed from the existing, update it if _, err := a.opClient.UpdateClusterRole(clusterRole); err != nil { a.logger.WithError(err).Errorf("Update existing cluster role failed: %v", clusterRole) return err @@ -1032,6 +1033,42 @@ func (a *Operator) ensureOpGroupClusterRole(op *operatorsv1.OperatorGroup, suffi return nil } +func (a *Operator) getExistingClusterRoleByOwnerAndLevel(op *operatorsv1.OperatorGroup, suffix string) (*rbacv1.ClusterRole, error) { + existingClusterRoleList, err := a.lister.RbacV1().ClusterRoleLister().List(labels.SelectorFromSet(ownerutil.OwnerLabel(op, "OperatorGroup"))) + if err != nil { + return nil, err + } + + for _, existingRole := range existingClusterRoleList { + if strings.HasSuffix(existingRole.Name, suffix) { + return existingRole.DeepCopy(), nil + } + } + + return nil, nil +} + +func (a *Operator) getClusterRoleAggregationRule(apis cache.APISet, suffix string) (*rbacv1.AggregationRule, error) { + var selectors []metav1.LabelSelector + for api := range apis { + aggregationLabel, err := aggregationLabelFromAPIKey(api, suffix) + if err != nil { + return nil, err + } + selectors = append(selectors, metav1.LabelSelector{ + MatchLabels: map[string]string{ + aggregationLabel: "true", + }, + }) + } + if len(selectors) > 0 { + return &rbacv1.AggregationRule{ + ClusterRoleSelectors: selectors, + }, nil + } + return nil, nil +} + func (a *Operator) ensureOpGroupClusterRoles(op *operatorsv1.OperatorGroup, apis cache.APISet) error { for _, suffix := range Suffices { if err := a.ensureOpGroupClusterRole(op, suffix, apis); err != nil { diff --git a/pkg/lib/ownerutil/util.go b/pkg/lib/ownerutil/util.go index 24ff1afe2e0..40a9cd8bab8 100644 --- a/pkg/lib/ownerutil/util.go +++ b/pkg/lib/ownerutil/util.go @@ -20,10 +20,13 @@ import ( ) const ( - OwnerKey = "olm.owner" - OwnerNamespaceKey = "olm.owner.namespace" - OwnerKind = "olm.owner.kind" - OwnerPackageServer = "packageserver" + OwnerKey = "olm.owner" + OwnerNamespaceKey = "olm.owner.namespace" + OwnerKind = "olm.owner.kind" + ClusterRoleLevelAdmin = "admin" + ClusterRoleLevelEdit = "edit" + ClusterRoleLevelView = "view" + OwnerPackageServer = "packageserver" ) var ( diff --git a/test/e2e/operator_groups_e2e_test.go b/test/e2e/operator_groups_e2e_test.go index 743f8ff37df..521a041d439 100644 --- a/test/e2e/operator_groups_e2e_test.go +++ b/test/e2e/operator_groups_e2e_test.go @@ -340,27 +340,31 @@ var _ = Describe("Operator Group", func() { }) // validate provided API clusterroles for the operatorgroup - adminRole, err := c.KubernetesInterface().RbacV1().ClusterRoles().Get(context.TODO(), operatorGroup.Name+"-admin", metav1.GetOptions{}) - require.NoError(GinkgoT(), err) - adminPolicyRules := []rbacv1.PolicyRule{ - {Verbs: []string{"*"}, APIGroups: []string{mainCRD.Spec.Group}, Resources: []string{mainCRDPlural}}, - } - require.Equal(GinkgoT(), adminPolicyRules, adminRole.Rules) - - editRole, err := c.KubernetesInterface().RbacV1().ClusterRoles().Get(context.TODO(), operatorGroup.Name+"-edit", metav1.GetOptions{}) + existingClusterRoleList, err := c.KubernetesInterface().RbacV1().ClusterRoles().List(context.TODO(), metav1.ListOptions{ + LabelSelector: labels.SelectorFromSet(ownerutil.OwnerLabel(&operatorGroup, "OperatorGroup")).String(), + }) require.NoError(GinkgoT(), err) - editPolicyRules := []rbacv1.PolicyRule{ - {Verbs: []string{"create", "update", "patch", "delete"}, APIGroups: []string{mainCRD.Spec.Group}, Resources: []string{mainCRDPlural}}, - } - require.Equal(GinkgoT(), editPolicyRules, editRole.Rules) + require.Len(GinkgoT(), existingClusterRoleList.Items, 3) - viewRole, err := c.KubernetesInterface().RbacV1().ClusterRoles().Get(context.TODO(), operatorGroup.Name+"-view", metav1.GetOptions{}) - require.NoError(GinkgoT(), err) - viewPolicyRules := []rbacv1.PolicyRule{ - {Verbs: []string{"get"}, APIGroups: []string{"apiextensions.k8s.io"}, Resources: []string{"customresourcedefinitions"}, ResourceNames: []string{mainCRD.Name}}, - {Verbs: []string{"get", "list", "watch"}, APIGroups: []string{mainCRD.Spec.Group}, Resources: []string{mainCRDPlural}}, + for _, role := range existingClusterRoleList.Items { + if strings.HasSuffix(role.Name, "admin") { + adminPolicyRules := []rbacv1.PolicyRule{ + {Verbs: []string{"*"}, APIGroups: []string{mainCRD.Spec.Group}, Resources: []string{mainCRDPlural}}, + } + require.Equal(GinkgoT(), adminPolicyRules, role.Rules) + } else if strings.HasSuffix(role.Name, "edit") { + editPolicyRules := []rbacv1.PolicyRule{ + {Verbs: []string{"create", "update", "patch", "delete"}, APIGroups: []string{mainCRD.Spec.Group}, Resources: []string{mainCRDPlural}}, + } + require.Equal(GinkgoT(), editPolicyRules, role.Rules) + } else if strings.HasSuffix(role.Name, "view") { + viewPolicyRules := []rbacv1.PolicyRule{ + {Verbs: []string{"get"}, APIGroups: []string{"apiextensions.k8s.io"}, Resources: []string{"customresourcedefinitions"}, ResourceNames: []string{mainCRD.Name}}, + {Verbs: []string{"get", "list", "watch"}, APIGroups: []string{mainCRD.Spec.Group}, Resources: []string{mainCRDPlural}}, + } + require.Equal(GinkgoT(), viewPolicyRules, role.Rules) + } } - require.Equal(GinkgoT(), viewPolicyRules, viewRole.Rules) // Unsupport all InstallModes log("unsupporting all csv installmodes")