github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/controller/operators/olm/operatorgroup.go (about)

     1  package olm
     2  
     3  import (
     4  	"context"
     5  	"crypto/sha256"
     6  	"fmt"
     7  	"math/big"
     8  	"reflect"
     9  	"strings"
    10  
    11  	"k8s.io/apimachinery/pkg/api/equality"
    12  
    13  	"github.com/sirupsen/logrus"
    14  	corev1 "k8s.io/api/core/v1"
    15  	rbacv1 "k8s.io/api/rbac/v1"
    16  	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    17  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    18  	"k8s.io/apimachinery/pkg/api/meta"
    19  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    20  	"k8s.io/apimachinery/pkg/labels"
    21  	"k8s.io/apimachinery/pkg/util/errors"
    22  
    23  	utillabels "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/util/labels"
    24  
    25  	operatorsv1 "github.com/operator-framework/api/pkg/operators/v1"
    26  	"github.com/operator-framework/api/pkg/operators/v1alpha1"
    27  	opregistry "github.com/operator-framework/operator-registry/pkg/registry"
    28  
    29  	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
    30  	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/decorators"
    31  	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/cache"
    32  	hashutil "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/util/hash"
    33  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil"
    34  )
    35  
    36  const (
    37  	AdminSuffix = "admin"
    38  	EditSuffix  = "edit"
    39  	ViewSuffix  = "view"
    40  
    41  	// kubeResourceNameLimit is the maximum length of a Kubernetes resource name
    42  	kubeResourceNameLimit = 253
    43  
    44  	// operatorGroupClusterRoleNameFmt template for ClusterRole names owned by OperatorGroups\
    45  	// e.g. olm.og.my-group.admin-<hash>
    46  	operatorGroupClusterRoleNameFmt = "olm.og.%s.%s-%s"
    47  )
    48  
    49  var (
    50  	AdminVerbs     = []string{"*"}
    51  	EditVerbs      = []string{"create", "update", "patch", "delete"}
    52  	ViewVerbs      = []string{"get", "list", "watch"}
    53  	Suffices       = []string{AdminSuffix, EditSuffix, ViewSuffix}
    54  	VerbsForSuffix = map[string][]string{
    55  		AdminSuffix: AdminVerbs,
    56  		EditSuffix:  EditVerbs,
    57  		ViewSuffix:  ViewVerbs,
    58  	}
    59  )
    60  
    61  func aggregationLabelFromAPIKey(k opregistry.APIKey, suffix string) (string, error) {
    62  	hash, err := cache.APIKeyToGVKHash(k)
    63  	if err != nil {
    64  		return "", err
    65  	}
    66  	return fmt.Sprintf("olm.opgroup.permissions/aggregate-to-%s-%s", hash, suffix), nil
    67  }
    68  
    69  func (a *Operator) syncOperatorGroups(obj interface{}) error {
    70  	op, ok := obj.(*operatorsv1.OperatorGroup)
    71  	if !ok {
    72  		a.logger.Debugf("wrong type: %#v\n", obj)
    73  		return fmt.Errorf("casting OperatorGroup failed")
    74  	}
    75  
    76  	logger := a.logger.WithFields(logrus.Fields{
    77  		"operatorGroup": op.GetName(),
    78  		"namespace":     op.GetNamespace(),
    79  	})
    80  
    81  	// Query OG in this namespace
    82  	groups, err := a.lister.OperatorsV1().OperatorGroupLister().OperatorGroups(op.GetNamespace()).List(labels.Everything())
    83  	if err != nil {
    84  		logger.WithError(err).Warnf("failed to list OperatorGroups in the namespace")
    85  	}
    86  
    87  	// Check if there is a stale multiple OG condition and clear it if existed.
    88  	if len(groups) == 1 {
    89  		og := groups[0].DeepCopy()
    90  		if c := meta.FindStatusCondition(og.Status.Conditions, operatorsv1.MutlipleOperatorGroupCondition); c != nil {
    91  			meta.RemoveStatusCondition(&og.Status.Conditions, operatorsv1.MutlipleOperatorGroupCondition)
    92  			if og.GetName() == op.GetName() {
    93  				meta.RemoveStatusCondition(&op.Status.Conditions, operatorsv1.MutlipleOperatorGroupCondition)
    94  			}
    95  			_, err = a.client.OperatorsV1().OperatorGroups(op.GetNamespace()).UpdateStatus(context.TODO(), og, metav1.UpdateOptions{})
    96  			if err != nil {
    97  				logger.Warnf("fail to upgrade operator group status og=%s with condition %+v: %s", og.GetName(), c, err.Error())
    98  			}
    99  		}
   100  	} else if len(groups) > 1 {
   101  		// Add to all OG's status conditions to indicate they're multiple OGs in the
   102  		// same namespace which is not allowed.
   103  		cond := metav1.Condition{
   104  			Type:    operatorsv1.MutlipleOperatorGroupCondition,
   105  			Status:  metav1.ConditionTrue,
   106  			Reason:  operatorsv1.MultipleOperatorGroupsReason,
   107  			Message: "Multiple OperatorGroup found in the same namespace",
   108  		}
   109  		for i := range groups {
   110  			og := groups[i].DeepCopy()
   111  			if c := meta.FindStatusCondition(og.Status.Conditions, operatorsv1.MutlipleOperatorGroupCondition); c != nil {
   112  				continue
   113  			}
   114  			meta.SetStatusCondition(&og.Status.Conditions, cond)
   115  			if og.GetName() == op.GetName() {
   116  				meta.SetStatusCondition(&op.Status.Conditions, cond)
   117  			}
   118  			_, err = a.client.OperatorsV1().OperatorGroups(op.GetNamespace()).UpdateStatus(context.TODO(), og, metav1.UpdateOptions{})
   119  			if err != nil {
   120  				logger.Warnf("fail to upgrade operator group status og=%s with condition %+v: %s", og.GetName(), cond, err.Error())
   121  			}
   122  		}
   123  	}
   124  
   125  	previousRef := op.Status.ServiceAccountRef.DeepCopy()
   126  	op, err = a.serviceAccountSyncer.SyncOperatorGroup(op)
   127  	if err != nil {
   128  		logger.Errorf("error updating service account - %v", err)
   129  		return err
   130  	}
   131  	if op.Status.ServiceAccountRef != previousRef {
   132  		csvList, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().List(labels.Everything())
   133  		if err != nil {
   134  			return err
   135  		}
   136  		for i := range csvList {
   137  			csv := csvList[i].DeepCopy()
   138  			if group, ok := csv.GetAnnotations()[operatorsv1.OperatorGroupAnnotationKey]; !ok || group != op.GetName() {
   139  				continue
   140  			}
   141  			if csv.Status.Reason == v1alpha1.CSVReasonComponentFailedNoRetry {
   142  				csv.SetPhase(v1alpha1.CSVPhasePending, v1alpha1.CSVReasonDetectedClusterChange, "Cluster resources changed state", a.now())
   143  				_, err := a.client.OperatorsV1alpha1().ClusterServiceVersions(csv.GetNamespace()).UpdateStatus(context.TODO(), csv, metav1.UpdateOptions{})
   144  				if err != nil {
   145  					return err
   146  				}
   147  				if err := a.csvQueueSet.Requeue(csv.GetNamespace(), csv.GetName()); err != nil {
   148  					return err
   149  				}
   150  				logger.Debug("Requeuing CSV due to detected service account change")
   151  			}
   152  		}
   153  	}
   154  
   155  	targetNamespaces, err := a.updateNamespaceList(op)
   156  	if err != nil {
   157  		logger.WithError(err).Warn("issue getting operatorgroup target namespaces")
   158  		return err
   159  	}
   160  	logger.WithField("targetNamespaces", targetNamespaces).Debug("updated target namespaces")
   161  
   162  	if namespacesChanged(targetNamespaces, op.Status.Namespaces) {
   163  		logger.Debug("OperatorGroup namespaces change detected")
   164  		outOfSyncNamespaces := namespacesAddedOrRemoved(op.Status.Namespaces, targetNamespaces)
   165  
   166  		// Update operatorgroup target namespace selection
   167  		logger.WithField("targets", targetNamespaces).Debug("namespace change detected")
   168  		op.Status = operatorsv1.OperatorGroupStatus{
   169  			Namespaces:  targetNamespaces,
   170  			LastUpdated: a.now(),
   171  			Conditions:  op.Status.Conditions,
   172  		}
   173  
   174  		if _, err = a.client.OperatorsV1().OperatorGroups(op.GetNamespace()).UpdateStatus(context.TODO(), op, metav1.UpdateOptions{}); err != nil && !apierrors.IsNotFound(err) {
   175  			logger.WithError(err).Warn("operatorgroup update failed")
   176  			return err
   177  		}
   178  
   179  		logger.Debug("operatorgroup status updated")
   180  
   181  		// Requeueing out of sync namespaces
   182  		logger.Debug("Requeueing out of sync namespaces")
   183  		for _, ns := range outOfSyncNamespaces {
   184  			logger.WithField("namespace", ns).Debug("requeueing")
   185  			a.nsQueueSet.Add(ns)
   186  		}
   187  
   188  		// CSV requeue is handled by the succeeding sync in `annotateCSVs`
   189  		return nil
   190  	}
   191  
   192  	logger.Debug("check that operatorgroup has updated CSV anotations")
   193  	err = a.annotateCSVs(op, targetNamespaces, logger)
   194  	if err != nil {
   195  		logger.WithError(err).Warn("failed to annotate CSVs in operatorgroup after group change")
   196  		return err
   197  	}
   198  	logger.Debug("OperatorGroup CSV annotation completed")
   199  
   200  	// Requeue all CSVs that provide the same APIs (including those removed). This notifies conflicting CSVs in
   201  	// intersecting groups that their conflict has possibly been resolved, either through resizing or through
   202  	// deletion of the conflicting CSV.
   203  	groupSurface := NewOperatorGroup(op)
   204  	groupProvidedAPIs := groupSurface.ProvidedAPIs()
   205  	providedAPIsForCSVs := a.providedAPIsFromCSVs(op, logger)
   206  	providedAPIsForGroup := make(cache.APISet)
   207  	for api := range providedAPIsForCSVs {
   208  		providedAPIsForGroup[api] = struct{}{}
   209  	}
   210  	for api := range groupProvidedAPIs {
   211  		providedAPIsForGroup[api] = struct{}{}
   212  	}
   213  
   214  	if err := a.ensureOpGroupClusterRoles(op, providedAPIsForGroup); err != nil {
   215  		logger.WithError(err).Warn("failed to ensure operatorgroup clusterroles")
   216  		return err
   217  	}
   218  	logger.Debug("operatorgroup clusterroles ensured")
   219  
   220  	csvs, err := a.findCSVsThatProvideAnyOf(providedAPIsForGroup)
   221  	if err != nil {
   222  		logger.WithError(err).Warn("could not find csvs that provide group apis")
   223  	}
   224  	for _, csv := range csvs {
   225  		logger.WithFields(logrus.Fields{
   226  			"csv":       csv.GetName(),
   227  			"namespace": csv.GetNamespace(),
   228  		}).Debug("requeueing provider")
   229  		if err := a.csvQueueSet.Requeue(csv.GetNamespace(), csv.GetName()); err != nil {
   230  			logger.WithError(err).Warn("could not requeue provider")
   231  		}
   232  	}
   233  
   234  	a.pruneProvidedAPIs(op, groupProvidedAPIs, providedAPIsForCSVs, logger)
   235  	return nil
   236  }
   237  
   238  func (a *Operator) operatorGroupDeleted(obj interface{}) {
   239  	op, ok := obj.(*operatorsv1.OperatorGroup)
   240  	if !ok {
   241  		a.logger.Debugf("casting OperatorGroup failed, wrong type: %#v\n", obj)
   242  		return
   243  	}
   244  
   245  	logger := a.logger.WithFields(logrus.Fields{
   246  		"operatorGroup": op.GetName(),
   247  		"namespace":     op.GetNamespace(),
   248  	})
   249  
   250  	clusterRoles, err := a.lister.RbacV1().ClusterRoleLister().List(labels.SelectorFromSet(ownerutil.OwnerLabel(op, "OperatorGroup")))
   251  	if err != nil {
   252  		logger.WithError(err).Error("failed to list ClusterRoles for garbage collection")
   253  		return
   254  	}
   255  	for _, clusterRole := range clusterRoles {
   256  		err = a.opClient.KubernetesInterface().RbacV1().ClusterRoles().Delete(context.TODO(), clusterRole.GetName(), metav1.DeleteOptions{})
   257  		if err != nil {
   258  			logger.WithError(err).Error("failed to delete ClusterRole during garbage collection")
   259  		}
   260  	}
   261  
   262  	// Trigger a sync on namespaces
   263  	logger.Debug("OperatorGroup deleted, requeueing out of sync namespaces")
   264  	for _, ns := range op.Status.Namespaces {
   265  		logger.WithField("namespace", ns).Debug("requeueing")
   266  		a.nsQueueSet.Add(ns)
   267  	}
   268  }
   269  
   270  func (a *Operator) annotateCSVs(group *operatorsv1.OperatorGroup, targetNamespaces []string, logger *logrus.Entry) error {
   271  	updateErrs := []error{}
   272  	targetNamespaceSet := NewNamespaceSet(targetNamespaces)
   273  
   274  	for _, csv := range a.csvSet(group.GetNamespace(), v1alpha1.CSVPhaseAny) {
   275  		if csv.IsCopied() {
   276  			continue
   277  		}
   278  		logger := logger.WithField("csv", csv.GetName())
   279  
   280  		originalNamespacesAnnotation := a.copyOperatorGroupAnnotations(&csv.ObjectMeta)[operatorsv1.OperatorGroupTargetsAnnotationKey]
   281  		originalNamespaceSet := NewNamespaceSetFromString(originalNamespacesAnnotation)
   282  
   283  		if a.operatorGroupAnnotationsDiffer(&csv.ObjectMeta, group) {
   284  			a.setOperatorGroupAnnotations(&csv.ObjectMeta, group, true)
   285  			// CRDs don't support strategic merge patching, but in the future if they do this should be updated to patch
   286  			if _, err := a.client.OperatorsV1alpha1().ClusterServiceVersions(csv.GetNamespace()).Update(context.TODO(), csv, metav1.UpdateOptions{}); err != nil && !apierrors.IsNotFound(err) {
   287  				logger.WithError(err).Warnf("error adding operatorgroup annotations")
   288  				updateErrs = append(updateErrs, err)
   289  				continue
   290  			}
   291  		}
   292  
   293  		// requeue csvs in original namespaces or in new target namespaces (to capture removed/added namespaces)
   294  		requeueNamespaces := originalNamespaceSet.Union(targetNamespaceSet)
   295  		if !requeueNamespaces.IsAllNamespaces() {
   296  			for ns := range requeueNamespaces {
   297  				if err := a.csvQueueSet.Requeue(ns, csv.GetName()); err != nil {
   298  					logger.WithError(err).Warn("could not requeue csv")
   299  				}
   300  			}
   301  		}
   302  		// have to requeue in all namespaces, previous or new targets were AllNamespaces
   303  		if namespaces, err := a.lister.CoreV1().NamespaceLister().List(labels.Everything()); err != nil {
   304  			for _, ns := range namespaces {
   305  				if err := a.csvQueueSet.Requeue(ns.GetName(), csv.GetName()); err != nil {
   306  					logger.WithError(err).Warn("could not requeue csv")
   307  				}
   308  			}
   309  		}
   310  	}
   311  	return errors.NewAggregate(updateErrs)
   312  }
   313  
   314  func (a *Operator) providedAPIsFromCSVs(group *operatorsv1.OperatorGroup, logger *logrus.Entry) map[opregistry.APIKey]*v1alpha1.ClusterServiceVersion {
   315  	set := a.csvSet(group.Namespace, v1alpha1.CSVPhaseAny)
   316  	providedAPIsFromCSVs := make(map[opregistry.APIKey]*v1alpha1.ClusterServiceVersion)
   317  	for _, csv := range set {
   318  		// Don't union providedAPIsFromCSVs if the CSV is copied (member of another OperatorGroup)
   319  		if csv.IsCopied() {
   320  			logger.Debug("csv is copied. not updating annotations or including in operatorgroup's provided api set")
   321  			continue
   322  		}
   323  
   324  		// TODO: Throw out CSVs that aren't members of the group due to group related failures?
   325  
   326  		// Union the providedAPIsFromCSVs from existing members of the group
   327  		operatorSurface, err := apiSurfaceOfCSV(csv)
   328  		if err != nil {
   329  			logger.WithError(err).Warn("could not create OperatorSurface from csv")
   330  			continue
   331  		}
   332  		for providedAPI := range operatorSurface.ProvidedAPIs.StripPlural() {
   333  			providedAPIsFromCSVs[providedAPI] = csv
   334  		}
   335  	}
   336  	return providedAPIsFromCSVs
   337  }
   338  
   339  func (a *Operator) pruneProvidedAPIs(group *operatorsv1.OperatorGroup, groupProvidedAPIs cache.APISet, providedAPIsFromCSVs map[opregistry.APIKey]*v1alpha1.ClusterServiceVersion, logger *logrus.Entry) {
   340  	// Don't prune providedAPIsFromCSVs if static
   341  	if group.Spec.StaticProvidedAPIs {
   342  		a.logger.Debug("group has static provided apis. skipping provided api pruning")
   343  		return
   344  	}
   345  
   346  	intersection := make(cache.APISet)
   347  	for api := range providedAPIsFromCSVs {
   348  		if _, ok := groupProvidedAPIs[api]; ok {
   349  			intersection[api] = struct{}{}
   350  		} else {
   351  			csv := providedAPIsFromCSVs[api]
   352  			_, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(csv.GetNamespace()).Get(csv.GetName())
   353  			if apierrors.IsNotFound(err) {
   354  				continue
   355  			}
   356  			if csv.DeletionTimestamp == nil && (csv.Status.Phase == v1alpha1.CSVPhaseNone || csv.Status.Phase == v1alpha1.CSVPhasePending) {
   357  				logger.Debugf("aborting operator group provided API update due to CSV %v in phase %v", csv.GetName(), csv.Status.Phase)
   358  				return
   359  			}
   360  		}
   361  	}
   362  
   363  	// Prune providedAPIs annotation if the cluster has fewer providedAPIs (handles CSV deletion)
   364  	//if intersection := groupProvidedAPIs.Intersection(providedAPIsFromCSVs); len(intersection) < len(groupProvidedAPIs) {
   365  	if len(intersection) < len(groupProvidedAPIs) {
   366  		difference := groupProvidedAPIs.Difference(intersection)
   367  		logger := logger.WithFields(logrus.Fields{
   368  			"providedAPIsOnCluster":  providedAPIsFromCSVs,
   369  			"providedAPIsAnnotation": groupProvidedAPIs,
   370  			"providedAPIDifference":  difference,
   371  			"intersection":           intersection,
   372  		})
   373  
   374  		// Don't need to check for nil annotations since we already know |annotations| > 0
   375  		annotations := group.GetAnnotations()
   376  		annotations[operatorsv1.OperatorGroupProvidedAPIsAnnotationKey] = intersection.String()
   377  		group.SetAnnotations(annotations)
   378  		logger.Debug("removing provided apis from annotation to match cluster state")
   379  		if _, err := a.client.OperatorsV1().OperatorGroups(group.GetNamespace()).Update(context.TODO(), group, metav1.UpdateOptions{}); err != nil && !apierrors.IsNotFound(err) {
   380  			logger.WithError(err).Warn("could not update provided api annotations")
   381  		}
   382  	}
   383  }
   384  
   385  // ensureProvidedAPIClusterRole ensures that a clusterrole exists (admin, edit, or view) for a single provided API Type
   386  func (a *Operator) ensureProvidedAPIClusterRole(namePrefix, suffix string, verbs []string, group, resource string, resourceNames []string, api ownerutil.Owner, key opregistry.APIKey) error {
   387  	aggregationLabel, err := aggregationLabelFromAPIKey(key, suffix)
   388  	if err != nil {
   389  		return err
   390  	}
   391  	clusterRole := &rbacv1.ClusterRole{
   392  		ObjectMeta: metav1.ObjectMeta{
   393  			Name: namePrefix + suffix,
   394  			Labels: map[string]string{
   395  				// Matches aggregation rules on the bootstrap ClusterRoles.
   396  				// https://github.com/kubernetes/kubernetes/blob/61847eab61788fb0543b4cf147773c9da646ed2f/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go#L232
   397  				fmt.Sprintf("rbac.authorization.k8s.io/aggregate-to-%s", suffix): "true",
   398  				aggregationLabel:           "true",
   399  				install.OLMManagedLabelKey: install.OLMManagedLabelValue,
   400  			},
   401  			OwnerReferences: []metav1.OwnerReference{ownerutil.NonBlockingOwner(api)},
   402  		},
   403  		Rules: []rbacv1.PolicyRule{{Verbs: verbs, APIGroups: []string{group}, Resources: []string{resource}, ResourceNames: resourceNames}},
   404  	}
   405  
   406  	existingCR, err := a.lister.RbacV1().ClusterRoleLister().Get(clusterRole.Name)
   407  	if err != nil && !apierrors.IsNotFound(err) {
   408  		return err
   409  	}
   410  	if apierrors.IsNotFound(err) {
   411  		existingCR, err = a.opClient.CreateClusterRole(clusterRole)
   412  		if err != nil {
   413  			a.logger.WithError(err).Errorf("Create cluster role failed: %v", clusterRole)
   414  			return err
   415  		}
   416  	}
   417  
   418  	if existingCR != nil && reflect.DeepEqual(existingCR.Rules, clusterRole.Rules) && ownerutil.IsOwnedBy(existingCR, api) && labels.Equals(existingCR.Labels, clusterRole.Labels) {
   419  		return nil
   420  	}
   421  
   422  	if _, err := a.opClient.UpdateClusterRole(clusterRole); err != nil {
   423  		a.logger.WithError(err).Errorf("Update existing cluster role failed: %v", clusterRole)
   424  		return err
   425  	}
   426  	return nil
   427  }
   428  
   429  // ensureClusterRolesForCSV ensures that ClusterRoles for writing and reading provided APIs exist for each operator
   430  func (a *Operator) ensureClusterRolesForCSV(csv *v1alpha1.ClusterServiceVersion) error {
   431  	for _, owned := range csv.Spec.CustomResourceDefinitions.Owned {
   432  		crd, err := a.lister.APIExtensionsV1().CustomResourceDefinitionLister().Get(owned.Name)
   433  		if err != nil {
   434  			return fmt.Errorf("crd %q not found: %s", owned.Name, err.Error())
   435  		}
   436  		crd.SetGroupVersionKind(apiextensionsv1.SchemeGroupVersion.WithKind("customresourcedefinition"))
   437  		nameGroupPair := strings.SplitN(owned.Name, ".", 2) // -> etcdclusters etcd.database.coreos.com
   438  		if len(nameGroupPair) != 2 {
   439  			return fmt.Errorf("invalid parsing of name '%v', got %v", owned.Name, nameGroupPair)
   440  		}
   441  		plural := nameGroupPair[0]
   442  		group := nameGroupPair[1]
   443  		namePrefix := fmt.Sprintf("%s-%s-", owned.Name, owned.Version)
   444  		key := opregistry.APIKey{Group: group, Version: owned.Version, Kind: owned.Kind, Plural: plural}
   445  		for suffix, verbs := range VerbsForSuffix {
   446  			if err := a.ensureProvidedAPIClusterRole(namePrefix, suffix, verbs, group, plural, nil, crd, key); err != nil {
   447  				return err
   448  			}
   449  		}
   450  		if err := a.ensureProvidedAPIClusterRole(namePrefix+"crd", ViewSuffix, []string{"get"}, "apiextensions.k8s.io", "customresourcedefinitions", []string{owned.Name}, crd, key); err != nil {
   451  			return err
   452  		}
   453  	}
   454  	for _, owned := range csv.Spec.APIServiceDefinitions.Owned {
   455  		svcName := strings.Join([]string{owned.Version, owned.Group}, ".")
   456  		svc, err := a.lister.APIRegistrationV1().APIServiceLister().Get(svcName)
   457  		if err != nil {
   458  			return fmt.Errorf("apiservice %q not found: %s", svcName, err.Error())
   459  		}
   460  		namePrefix := fmt.Sprintf("%s-%s-", owned.Name, owned.Version)
   461  		key := opregistry.APIKey{Group: owned.Group, Version: owned.Version, Kind: owned.Kind}
   462  		for suffix, verbs := range VerbsForSuffix {
   463  			if err := a.ensureProvidedAPIClusterRole(namePrefix, suffix, verbs, owned.Group, owned.Name, nil, svc, key); err != nil {
   464  				return err
   465  			}
   466  		}
   467  	}
   468  	return nil
   469  }
   470  
   471  func (a *Operator) ensureRBACInTargetNamespace(csv *v1alpha1.ClusterServiceVersion, operatorGroup *operatorsv1.OperatorGroup) error {
   472  	targetNamespaces := operatorGroup.Status.Namespaces
   473  	if targetNamespaces == nil {
   474  		return nil
   475  	}
   476  
   477  	strategyResolver := install.StrategyResolver{}
   478  	strategy, err := strategyResolver.UnmarshalStrategy(csv.Spec.InstallStrategy)
   479  	if err != nil {
   480  		return err
   481  	}
   482  	strategyDetailsDeployment, ok := strategy.(*v1alpha1.StrategyDetailsDeployment)
   483  	if !ok {
   484  		return fmt.Errorf("could not cast install strategy as type %T", strategyDetailsDeployment)
   485  	}
   486  
   487  	logger := a.logger.WithField("opgroup", operatorGroup.GetName()).WithField("csv", csv.GetName())
   488  
   489  	// if OperatorGroup is global (all namespaces) we generate cluster roles / cluster role bindings instead
   490  	if len(targetNamespaces) == 1 && targetNamespaces[0] == corev1.NamespaceAll {
   491  		logger.Debug("opgroup is global")
   492  
   493  		// synthesize cluster permissions to verify rbac
   494  		strategyDetailsDeployment.ClusterPermissions = append(strategyDetailsDeployment.ClusterPermissions, strategyDetailsDeployment.Permissions...)
   495  		strategyDetailsDeployment.Permissions = nil
   496  		permMet, _, err := a.permissionStatus(strategyDetailsDeployment, corev1.NamespaceAll, csv)
   497  		if err != nil {
   498  			return err
   499  		}
   500  
   501  		// operator already has access at the cluster scope
   502  		if permMet {
   503  			logger.Debug("global operator has correct global permissions")
   504  			return nil
   505  		}
   506  		logger.Debug("lift roles/rolebindings to clusterroles/rolebindings")
   507  		if err := a.ensureSingletonRBAC(operatorGroup.GetNamespace(), csv); err != nil {
   508  			return err
   509  		}
   510  
   511  		return nil
   512  	}
   513  
   514  	return nil
   515  }
   516  
   517  func (a *Operator) ensureSingletonRBAC(operatorNamespace string, csv *v1alpha1.ClusterServiceVersion) error {
   518  	ownerSelector := ownerutil.CSVOwnerSelector(csv)
   519  	ownedRoles, err := a.lister.RbacV1().RoleLister().Roles(operatorNamespace).List(ownerSelector)
   520  	if err != nil {
   521  		return err
   522  	}
   523  	if len(ownedRoles) == 0 {
   524  		return fmt.Errorf("no owned roles found")
   525  	}
   526  
   527  	for _, r := range ownedRoles {
   528  		a.logger.Debug("processing role")
   529  		_, err := a.lister.RbacV1().ClusterRoleLister().Get(r.GetName())
   530  		if err != nil {
   531  			clusterRole := &rbacv1.ClusterRole{
   532  				TypeMeta: metav1.TypeMeta{
   533  					Kind:       "ClusterRole",
   534  					APIVersion: r.APIVersion,
   535  				},
   536  				ObjectMeta: metav1.ObjectMeta{
   537  					Name:   r.GetName(),
   538  					Labels: r.GetLabels(),
   539  				},
   540  				Rules: append(r.Rules, rbacv1.PolicyRule{
   541  					Verbs:     ViewVerbs,
   542  					APIGroups: []string{corev1.GroupName},
   543  					Resources: []string{"namespaces"},
   544  				}),
   545  			}
   546  			if _, err := a.opClient.CreateClusterRole(clusterRole); err != nil {
   547  				return err
   548  			}
   549  			a.logger.Debug("created cluster role")
   550  		}
   551  	}
   552  
   553  	ownedRoleBindings, err := a.lister.RbacV1().RoleBindingLister().RoleBindings(operatorNamespace).List(ownerSelector)
   554  	if err != nil {
   555  		return err
   556  	}
   557  	if len(ownedRoleBindings) == 0 {
   558  		return fmt.Errorf("no owned rolebindings found")
   559  	}
   560  
   561  	for _, r := range ownedRoleBindings {
   562  		_, err := a.lister.RbacV1().ClusterRoleBindingLister().Get(r.GetName())
   563  		if err != nil {
   564  			clusterRoleBinding := &rbacv1.ClusterRoleBinding{
   565  				TypeMeta: metav1.TypeMeta{
   566  					Kind:       "ClusterRoleBinding",
   567  					APIVersion: r.APIVersion,
   568  				},
   569  				ObjectMeta: metav1.ObjectMeta{
   570  					Name:   r.GetName(),
   571  					Labels: r.GetLabels(),
   572  				},
   573  				Subjects: r.Subjects,
   574  				RoleRef: rbacv1.RoleRef{
   575  					APIGroup: r.RoleRef.APIGroup,
   576  					Kind:     "ClusterRole",
   577  					Name:     r.RoleRef.Name,
   578  				},
   579  			}
   580  			if _, err := a.opClient.CreateClusterRoleBinding(clusterRoleBinding); err != nil {
   581  				return err
   582  			}
   583  		}
   584  	}
   585  	return nil
   586  }
   587  
   588  func (a *Operator) ensureTenantRBAC(operatorNamespace, targetNamespace string, csv *v1alpha1.ClusterServiceVersion, targetCSV *v1alpha1.ClusterServiceVersion) error {
   589  	if operatorNamespace == targetNamespace {
   590  		return nil
   591  	}
   592  
   593  	ownerSelector := ownerutil.CSVOwnerSelector(csv)
   594  	ownedRoles, err := a.lister.RbacV1().RoleLister().Roles(operatorNamespace).List(ownerSelector)
   595  	if err != nil {
   596  		return err
   597  	}
   598  
   599  	if len(ownedRoles) == 0 {
   600  		return fmt.Errorf("owned roles not found in cache")
   601  	}
   602  
   603  	targetRoles, err := a.lister.RbacV1().RoleLister().Roles(targetNamespace).List(ownerutil.CSVOwnerSelector(targetCSV))
   604  	if err != nil {
   605  		return err
   606  	}
   607  
   608  	targetRolesByName := map[string]*rbacv1.Role{}
   609  	for _, r := range targetRoles {
   610  		targetRolesByName[r.GetName()] = r
   611  	}
   612  
   613  	for _, ownedRole := range ownedRoles {
   614  		// don't trust the owner label
   615  		// TODO: this can skip objects that have owner labels but different ownerreferences
   616  		if !ownerutil.IsOwnedBy(ownedRole, csv) {
   617  			continue
   618  		}
   619  
   620  		existing, ok := targetRolesByName[ownedRole.GetName()]
   621  
   622  		// role already exists, update the rules
   623  		if ok {
   624  			existing.Rules = ownedRole.Rules
   625  			if _, err := a.opClient.UpdateRole(existing); err != nil {
   626  				return err
   627  			}
   628  			continue
   629  		}
   630  
   631  		// role doesn't exist, create it
   632  		// TODO: we can work around error cases here; if there's an un-owned role with a matching name we should generate instead
   633  		targetRole := ownedRole.DeepCopy()
   634  		targetRole.SetResourceVersion("0")
   635  		targetRole.SetNamespace(targetNamespace)
   636  		targetRole.SetOwnerReferences([]metav1.OwnerReference{ownerutil.NonBlockingOwner(targetCSV)})
   637  		if err := ownerutil.AddOwnerLabels(targetRole, targetCSV); err != nil {
   638  			return err
   639  		}
   640  		targetRole.SetLabels(utillabels.AddLabel(targetRole.GetLabels(), v1alpha1.CopiedLabelKey, operatorNamespace))
   641  		targetRole.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue
   642  		if _, err := a.opClient.CreateRole(targetRole); err != nil {
   643  			return err
   644  		}
   645  	}
   646  
   647  	ownedRoleBindings, err := a.lister.RbacV1().RoleBindingLister().RoleBindings(operatorNamespace).List(ownerSelector)
   648  	if err != nil {
   649  		return err
   650  	}
   651  
   652  	targetRoleBindings, err := a.lister.RbacV1().RoleBindingLister().RoleBindings(targetNamespace).List(ownerutil.CSVOwnerSelector(targetCSV))
   653  	if err != nil {
   654  		return err
   655  	}
   656  
   657  	targetRoleBindingsByName := map[string]*rbacv1.RoleBinding{}
   658  	for _, r := range targetRoleBindings {
   659  		targetRoleBindingsByName[r.GetName()] = r
   660  	}
   661  
   662  	// role bindings
   663  	for _, ownedRoleBinding := range ownedRoleBindings {
   664  		// don't trust the owner label
   665  		if !ownerutil.IsOwnedBy(ownedRoleBinding, csv) {
   666  			continue
   667  		}
   668  		_, ok := targetRoleBindingsByName[ownedRoleBinding.GetName()]
   669  
   670  		// role binding exists
   671  		if ok {
   672  			// TODO: we should check if SA/role has changed
   673  			continue
   674  		}
   675  
   676  		// role binding doesn't exist
   677  		// TODO: we can work around error cases here; if there's an un-owned role with a matching name we should generate instead
   678  		ownedRoleBinding = ownedRoleBinding.DeepCopy()
   679  		ownedRoleBinding.SetNamespace(targetNamespace)
   680  		ownedRoleBinding.SetResourceVersion("0")
   681  		ownedRoleBinding.SetOwnerReferences([]metav1.OwnerReference{ownerutil.NonBlockingOwner(targetCSV)})
   682  		if err := ownerutil.AddOwnerLabels(ownedRoleBinding, targetCSV); err != nil {
   683  			return err
   684  		}
   685  		ownedRoleBinding.SetLabels(utillabels.AddLabel(ownedRoleBinding.GetLabels(), v1alpha1.CopiedLabelKey, operatorNamespace))
   686  		ownedRoleBinding.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue
   687  		if _, err := a.opClient.CreateRoleBinding(ownedRoleBinding); err != nil {
   688  			return err
   689  		}
   690  	}
   691  	return nil
   692  }
   693  
   694  func (a *Operator) ensureCSVsInNamespaces(csv *v1alpha1.ClusterServiceVersion, operatorGroup *operatorsv1.OperatorGroup, targets NamespaceSet) error {
   695  	namespaces, err := a.lister.CoreV1().NamespaceLister().List(labels.Everything())
   696  	if err != nil {
   697  		return err
   698  	}
   699  
   700  	strategyDetailsDeployment := &csv.Spec.InstallStrategy.StrategySpec
   701  	logger := a.logger.WithField("opgroup", operatorGroup.GetName()).WithField("csv", csv.GetName())
   702  
   703  	targetCSVs := make(map[string]*v1alpha1.ClusterServiceVersion)
   704  
   705  	var copyPrototype v1alpha1.ClusterServiceVersion
   706  	csvCopyPrototype(csv, &copyPrototype)
   707  	nonstatus, status, err := copyableCSVHash(&copyPrototype)
   708  	if err != nil {
   709  		return err
   710  	}
   711  
   712  	for _, ns := range namespaces {
   713  		if ns.GetName() == operatorGroup.Namespace {
   714  			continue
   715  		}
   716  		if targets.Contains(ns.GetName()) {
   717  			var targetCSV *v1alpha1.ClusterServiceVersion
   718  			if targetCSV, err = a.copyToNamespace(&copyPrototype, csv.GetNamespace(), ns.GetName(), nonstatus, status); err != nil {
   719  				logger.WithError(err).Debug("error copying to target")
   720  				continue
   721  			}
   722  			targetCSVs[ns.GetName()] = targetCSV
   723  		} else {
   724  			if err := a.pruneFromNamespace(operatorGroup.GetName(), ns.GetName()); err != nil {
   725  				logger.WithError(err).Debug("error pruning from old target")
   726  			}
   727  		}
   728  	}
   729  
   730  	targetNamespaces := operatorGroup.Status.Namespaces
   731  	if targetNamespaces == nil {
   732  		logger.Errorf("operatorgroup '%v' should have non-nil status", operatorGroup.GetName())
   733  		return nil
   734  	}
   735  	if len(targetNamespaces) == 1 && targetNamespaces[0] == corev1.NamespaceAll {
   736  		// global operator group handled by ensureRBACInTargetNamespace
   737  		return nil
   738  	}
   739  	for _, ns := range targetNamespaces {
   740  		// create roles/rolebindings for each target namespace
   741  		permMet, _, err := a.permissionStatus(strategyDetailsDeployment, ns, csv)
   742  		if err != nil {
   743  			logger.WithError(err).Debug("permission status")
   744  			return err
   745  		}
   746  		logger.WithField("target", ns).WithField("permMet", permMet).Debug("permission status")
   747  
   748  		// operator already has access in the target namespace
   749  		if permMet {
   750  			logger.Debug("operator has access")
   751  			continue
   752  		} else {
   753  			logger.Debug("operator needs access, going to create permissions")
   754  		}
   755  
   756  		targetCSV, ok := targetCSVs[ns]
   757  		if !ok {
   758  			return fmt.Errorf("bug: no target CSV for namespace %v", ns)
   759  		}
   760  		if err := a.ensureTenantRBAC(operatorGroup.GetNamespace(), ns, csv, targetCSV); err != nil {
   761  			logger.WithError(err).Debug("ensuring tenant rbac")
   762  			return err
   763  		}
   764  		logger.Debug("permissions created")
   765  	}
   766  
   767  	return nil
   768  }
   769  
   770  // copyableCSVHash returns a hash of the parts of the given CSV that
   771  // are relevant to copied CSV projection.
   772  func copyableCSVHash(original *v1alpha1.ClusterServiceVersion) (string, string, error) {
   773  	shallow := v1alpha1.ClusterServiceVersion{
   774  		ObjectMeta: metav1.ObjectMeta{
   775  			Name:        original.Name,
   776  			Labels:      original.Labels,
   777  			Annotations: original.Annotations,
   778  		},
   779  		Spec: original.Spec,
   780  	}
   781  
   782  	newHash, err := hashutil.DeepHashObject(&shallow)
   783  	if err != nil {
   784  		return "", "", err
   785  	}
   786  	originalHash, err := hashutil.DeepHashObject(&original.Status)
   787  	if err != nil {
   788  		return "", "", err
   789  	}
   790  
   791  	return newHash, originalHash, nil
   792  }
   793  
   794  // If returned error is not nil, the returned ClusterServiceVersion
   795  // has only the Name, Namespace, and UID fields set.
   796  func (a *Operator) copyToNamespace(prototype *v1alpha1.ClusterServiceVersion, nsFrom, nsTo, nonstatus, status string) (*v1alpha1.ClusterServiceVersion, error) {
   797  	if nsFrom == nsTo {
   798  		return nil, fmt.Errorf("bug: can not copy to active namespace %v", nsFrom)
   799  	}
   800  
   801  	prototype.Namespace = nsTo
   802  	prototype.ResourceVersion = ""
   803  	prototype.UID = ""
   804  
   805  	existing, err := a.copiedCSVLister.Namespace(nsTo).Get(prototype.GetName())
   806  	if apierrors.IsNotFound(err) {
   807  		created, err := a.client.OperatorsV1alpha1().ClusterServiceVersions(nsTo).Create(context.TODO(), prototype, metav1.CreateOptions{})
   808  		if err != nil {
   809  			return nil, fmt.Errorf("failed to create new CSV: %w", err)
   810  		}
   811  		created.Status = prototype.Status
   812  		if _, err := a.client.OperatorsV1alpha1().ClusterServiceVersions(nsTo).UpdateStatus(context.TODO(), created, metav1.UpdateOptions{}); err != nil {
   813  			return nil, fmt.Errorf("failed to update status on new CSV: %w", err)
   814  		}
   815  		return &v1alpha1.ClusterServiceVersion{
   816  			ObjectMeta: metav1.ObjectMeta{
   817  				Name:      created.Name,
   818  				Namespace: created.Namespace,
   819  				UID:       created.UID,
   820  			},
   821  		}, nil
   822  	} else if err != nil {
   823  		return nil, err
   824  	}
   825  
   826  	prototype.Namespace = existing.Namespace
   827  	prototype.ResourceVersion = existing.ResourceVersion
   828  	prototype.UID = existing.UID
   829  	existingNonStatus := existing.Annotations["$copyhash-nonstatus"]
   830  	existingStatus := existing.Annotations["$copyhash-status"]
   831  
   832  	var updated *v1alpha1.ClusterServiceVersion
   833  	if existingNonStatus != nonstatus {
   834  		if updated, err = a.client.OperatorsV1alpha1().ClusterServiceVersions(nsTo).Update(context.TODO(), prototype, metav1.UpdateOptions{}); err != nil {
   835  			return nil, fmt.Errorf("failed to update: %w", err)
   836  		}
   837  	} else {
   838  		// Avoid mutating cached copied CSV.
   839  		updated = prototype
   840  	}
   841  
   842  	if existingStatus != status {
   843  		updated.Status = prototype.Status
   844  		if _, err = a.client.OperatorsV1alpha1().ClusterServiceVersions(nsTo).UpdateStatus(context.TODO(), updated, metav1.UpdateOptions{}); err != nil {
   845  			return nil, fmt.Errorf("failed to update status: %w", err)
   846  		}
   847  	}
   848  	return &v1alpha1.ClusterServiceVersion{
   849  		ObjectMeta: metav1.ObjectMeta{
   850  			Name:      updated.Name,
   851  			Namespace: updated.Namespace,
   852  			UID:       updated.UID,
   853  		},
   854  	}, nil
   855  }
   856  
   857  func (a *Operator) pruneFromNamespace(operatorGroupName, namespace string) error {
   858  	fetchedCSVs, err := a.copiedCSVLister.Namespace(namespace).List(labels.Everything())
   859  	if err != nil {
   860  		return err
   861  	}
   862  
   863  	for _, csv := range fetchedCSVs {
   864  		if v1alpha1.IsCopied(csv) && csv.GetAnnotations()[operatorsv1.OperatorGroupAnnotationKey] == operatorGroupName {
   865  			a.logger.Debugf("Found CSV '%v' in namespace %v to delete", csv.GetName(), namespace)
   866  			if err := a.copiedCSVGCQueueSet.Requeue(csv.GetNamespace(), csv.GetName()); err != nil {
   867  				return err
   868  			}
   869  		}
   870  	}
   871  	return nil
   872  }
   873  
   874  func (a *Operator) setOperatorGroupAnnotations(obj *metav1.ObjectMeta, op *operatorsv1.OperatorGroup, addTargets bool) {
   875  	metav1.SetMetaDataAnnotation(obj, operatorsv1.OperatorGroupNamespaceAnnotationKey, op.GetNamespace())
   876  	metav1.SetMetaDataAnnotation(obj, operatorsv1.OperatorGroupAnnotationKey, op.GetName())
   877  
   878  	if addTargets && op.Status.Namespaces != nil {
   879  		metav1.SetMetaDataAnnotation(obj, operatorsv1.OperatorGroupTargetsAnnotationKey, op.BuildTargetNamespaces())
   880  	}
   881  }
   882  
   883  func (a *Operator) operatorGroupAnnotationsDiffer(obj *metav1.ObjectMeta, op *operatorsv1.OperatorGroup) bool {
   884  	annotations := obj.GetAnnotations()
   885  	if annotations == nil {
   886  		return true
   887  	}
   888  	if operatorGroupNamespace, ok := annotations[operatorsv1.OperatorGroupNamespaceAnnotationKey]; !ok || operatorGroupNamespace != op.GetNamespace() {
   889  		return true
   890  	}
   891  	if operatorGroup, ok := annotations[operatorsv1.OperatorGroupAnnotationKey]; !ok || operatorGroup != op.GetName() {
   892  		return true
   893  	}
   894  	if targets, ok := annotations[operatorsv1.OperatorGroupTargetsAnnotationKey]; !ok || targets != op.BuildTargetNamespaces() {
   895  		a.logger.WithFields(logrus.Fields{
   896  			"annotationTargets": annotations[operatorsv1.OperatorGroupTargetsAnnotationKey],
   897  			"opgroupTargets":    op.BuildTargetNamespaces(),
   898  		}).Debug("annotations different")
   899  		return true
   900  	}
   901  
   902  	a.logger.WithFields(logrus.Fields{
   903  		"annotationTargets": annotations[operatorsv1.OperatorGroupTargetsAnnotationKey],
   904  		"opgroupTargets":    op.BuildTargetNamespaces(),
   905  	}).Debug("annotations correct")
   906  	return false
   907  }
   908  
   909  func (a *Operator) copyOperatorGroupAnnotations(obj *metav1.ObjectMeta) map[string]string {
   910  	copiedAnnotations := make(map[string]string)
   911  	for k, v := range obj.GetAnnotations() {
   912  		switch k {
   913  		case operatorsv1.OperatorGroupNamespaceAnnotationKey:
   914  			fallthrough
   915  		case operatorsv1.OperatorGroupAnnotationKey:
   916  			fallthrough
   917  		case operatorsv1.OperatorGroupTargetsAnnotationKey:
   918  			copiedAnnotations[k] = v
   919  		}
   920  	}
   921  	return copiedAnnotations
   922  }
   923  
   924  func namespacesChanged(clusterNamespaces []string, statusNamespaces []string) bool {
   925  	if len(clusterNamespaces) != len(statusNamespaces) {
   926  		return true
   927  	}
   928  
   929  	nsMap := map[string]struct{}{}
   930  	for _, v := range clusterNamespaces {
   931  		nsMap[v] = struct{}{}
   932  	}
   933  	for _, v := range statusNamespaces {
   934  		if _, ok := nsMap[v]; !ok {
   935  			return true
   936  		}
   937  	}
   938  	return false
   939  }
   940  
   941  func (a *Operator) getOperatorGroupTargets(op *operatorsv1.OperatorGroup) (map[string]struct{}, error) {
   942  	selector, err := metav1.LabelSelectorAsSelector(op.Spec.Selector)
   943  
   944  	if err != nil {
   945  		return nil, err
   946  	}
   947  
   948  	namespaceSet := make(map[string]struct{})
   949  	if len(op.Spec.TargetNamespaces) > 0 {
   950  		for _, ns := range op.Spec.TargetNamespaces {
   951  			if ns == corev1.NamespaceAll {
   952  				return nil, fmt.Errorf("TargetNamespaces cannot contain NamespaceAll: %v", op.Spec.TargetNamespaces)
   953  			}
   954  			namespaceSet[ns] = struct{}{}
   955  		}
   956  	} else if selector == nil || selector.Empty() || selector == labels.Nothing() {
   957  		namespaceSet[corev1.NamespaceAll] = struct{}{}
   958  	} else {
   959  		matchedNamespaces, err := a.lister.CoreV1().NamespaceLister().List(selector)
   960  		if err != nil {
   961  			return nil, err
   962  		} else if len(matchedNamespaces) == 0 {
   963  			a.logger.Debugf("No matched TargetNamespaces are found for given selector: %#v\n", selector)
   964  		}
   965  
   966  		for _, ns := range matchedNamespaces {
   967  			namespaceSet[ns.GetName()] = struct{}{}
   968  		}
   969  	}
   970  	return namespaceSet, nil
   971  }
   972  
   973  func (a *Operator) updateNamespaceList(op *operatorsv1.OperatorGroup) ([]string, error) {
   974  	namespaceSet, err := a.getOperatorGroupTargets(op)
   975  	if err != nil {
   976  		return nil, err
   977  	}
   978  	namespaceList := []string{}
   979  	for ns := range namespaceSet {
   980  		namespaceList = append(namespaceList, ns)
   981  	}
   982  
   983  	return namespaceList, nil
   984  }
   985  
   986  func (a *Operator) getClusterRoleName(op *operatorsv1.OperatorGroup, roleType string) (string, error) {
   987  	roleSuffix := hash(fmt.Sprintf("%s/%s/%s", op.GetNamespace(), op.GetName(), roleType))
   988  	// calculate how many characters are left for the operator group name
   989  	nameLimit := kubeResourceNameLimit - len(strings.Replace(operatorGroupClusterRoleNameFmt, "%s", "", -1)) - len(roleType) - len(roleSuffix)
   990  	if len(op.GetName()) < nameLimit {
   991  		return fmt.Sprintf(operatorGroupClusterRoleNameFmt, op.GetName(), roleType, roleSuffix), nil
   992  	}
   993  	return fmt.Sprintf(operatorGroupClusterRoleNameFmt, op.GetName()[:nameLimit], roleType, roleSuffix), nil
   994  }
   995  
   996  func (a *Operator) ensureOpGroupClusterRole(op *operatorsv1.OperatorGroup, suffix string, apis cache.APISet) error {
   997  	// create target cluster role spec
   998  	var clusterRole *rbacv1.ClusterRole
   999  	clusterRoleName, err := a.getClusterRoleName(op, suffix)
  1000  	if err != nil {
  1001  		return err
  1002  	}
  1003  	aggregationRule, err := a.getClusterRoleAggregationRule(apis, suffix)
  1004  	if err != nil {
  1005  		return err
  1006  	}
  1007  
  1008  	// get existing cluster role for this level (suffix: admin, edit, view))
  1009  	existingRole, err := a.lister.RbacV1().ClusterRoleLister().Get(clusterRoleName)
  1010  	if err != nil && !apierrors.IsNotFound(err) {
  1011  		return err
  1012  	}
  1013  
  1014  	if existingRole != nil {
  1015  		// if the existing role conforms to the naming convention, check for skew
  1016  		cp := existingRole.DeepCopy()
  1017  		if err := ownerutil.AddOwnerLabels(cp, op); err != nil {
  1018  			return err
  1019  		}
  1020  
  1021  		// ensure that the labels and aggregation rules are correct
  1022  		if labels.Equals(existingRole.Labels, cp.Labels) && equality.Semantic.DeepEqual(existingRole.AggregationRule, aggregationRule) {
  1023  			return nil
  1024  		}
  1025  
  1026  		cp.AggregationRule = aggregationRule
  1027  		if _, err := a.opClient.UpdateClusterRole(cp); err != nil {
  1028  			a.logger.WithError(err).Errorf("update existing cluster role failed: %v", clusterRole)
  1029  		}
  1030  		return err
  1031  	}
  1032  
  1033  	clusterRole = &rbacv1.ClusterRole{
  1034  		ObjectMeta: metav1.ObjectMeta{
  1035  			Name: clusterRoleName,
  1036  		},
  1037  		AggregationRule: aggregationRule,
  1038  	}
  1039  
  1040  	if err := ownerutil.AddOwnerLabels(clusterRole, op); err != nil {
  1041  		return err
  1042  	}
  1043  	clusterRole.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue
  1044  
  1045  	a.logger.Infof("creating cluster role: %s owned by operator group: %s/%s", clusterRole.GetName(), op.GetNamespace(), op.GetName())
  1046  	_, err = a.opClient.CreateClusterRole(clusterRole)
  1047  	return err
  1048  }
  1049  
  1050  func (a *Operator) getClusterRoleAggregationRule(apis cache.APISet, suffix string) (*rbacv1.AggregationRule, error) {
  1051  	var selectors []metav1.LabelSelector
  1052  	for api := range apis {
  1053  		aggregationLabel, err := aggregationLabelFromAPIKey(api, suffix)
  1054  		if err != nil {
  1055  			return nil, err
  1056  		}
  1057  		selectors = append(selectors, metav1.LabelSelector{
  1058  			MatchLabels: map[string]string{
  1059  				aggregationLabel: "true",
  1060  			},
  1061  		})
  1062  	}
  1063  	if len(selectors) > 0 {
  1064  		return &rbacv1.AggregationRule{
  1065  			ClusterRoleSelectors: selectors,
  1066  		}, nil
  1067  	}
  1068  	return nil, nil
  1069  }
  1070  
  1071  func (a *Operator) ensureOpGroupClusterRoles(op *operatorsv1.OperatorGroup, apis cache.APISet) error {
  1072  	for _, suffix := range Suffices {
  1073  		if err := a.ensureOpGroupClusterRole(op, suffix, apis); err != nil {
  1074  			return err
  1075  		}
  1076  	}
  1077  	return nil
  1078  }
  1079  
  1080  func (a *Operator) findCSVsThatProvideAnyOf(provide cache.APISet) ([]*v1alpha1.ClusterServiceVersion, error) {
  1081  	csvs, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(metav1.NamespaceAll).List(labels.Everything())
  1082  	if err != nil {
  1083  		return nil, err
  1084  	}
  1085  
  1086  	providers := []*v1alpha1.ClusterServiceVersion{}
  1087  	for i := 0; i < len(csvs); i++ {
  1088  		csv := csvs[i]
  1089  		if csv.IsCopied() {
  1090  			continue
  1091  		}
  1092  
  1093  		operatorSurface, err := apiSurfaceOfCSV(csv)
  1094  		if err != nil {
  1095  			continue
  1096  		}
  1097  
  1098  		if len(operatorSurface.ProvidedAPIs.StripPlural().Intersection(provide)) > 0 {
  1099  			providers = append(providers, csv)
  1100  		}
  1101  	}
  1102  
  1103  	return providers, nil
  1104  }
  1105  
  1106  // namespacesAddedOrRemoved returns the union of:
  1107  // - the set of elements in A but not in B
  1108  // - the set of elements in B but not in A
  1109  func namespacesAddedOrRemoved(a, b []string) []string {
  1110  	check := make(map[string]struct{})
  1111  
  1112  	for _, namespace := range a {
  1113  		check[namespace] = struct{}{}
  1114  	}
  1115  
  1116  	for _, namespace := range b {
  1117  		if _, ok := check[namespace]; !ok {
  1118  			check[namespace] = struct{}{}
  1119  		} else {
  1120  			delete(check, namespace)
  1121  		}
  1122  	}
  1123  
  1124  	// Remove global namespace name if added
  1125  	delete(check, "")
  1126  
  1127  	var keys []string
  1128  	for key := range check {
  1129  		keys = append(keys, key)
  1130  	}
  1131  
  1132  	return keys
  1133  }
  1134  
  1135  func csvCopyPrototype(src, dst *v1alpha1.ClusterServiceVersion) {
  1136  	*dst = v1alpha1.ClusterServiceVersion{
  1137  		TypeMeta: src.TypeMeta,
  1138  		ObjectMeta: metav1.ObjectMeta{
  1139  			Name:        src.Name,
  1140  			Annotations: map[string]string{},
  1141  			Labels:      map[string]string{},
  1142  		},
  1143  		Spec:   src.Spec,
  1144  		Status: src.Status,
  1145  	}
  1146  	for k, v := range src.Annotations {
  1147  		if k == operatorsv1.OperatorGroupTargetsAnnotationKey {
  1148  			continue
  1149  		}
  1150  		if k == "kubectl.kubernetes.io/last-applied-configuration" {
  1151  			continue // big
  1152  		}
  1153  		dst.Annotations[k] = v
  1154  	}
  1155  	for k, v := range src.Labels {
  1156  		if strings.HasPrefix(k, decorators.ComponentLabelKeyPrefix) {
  1157  			continue
  1158  		}
  1159  		dst.Labels[k] = v
  1160  	}
  1161  	dst.Labels[v1alpha1.CopiedLabelKey] = src.Namespace
  1162  	dst.Status.Reason = v1alpha1.CSVReasonCopied
  1163  	dst.Status.Message = fmt.Sprintf("The operator is running in %s but is managing this namespace", src.GetNamespace())
  1164  }
  1165  
  1166  func hash(s string) string {
  1167  	return toBase62(sha256.Sum224([]byte(s)))
  1168  }
  1169  
  1170  func toBase62(hash [28]byte) string {
  1171  	var i big.Int
  1172  	i.SetBytes(hash[:])
  1173  	return i.Text(62)
  1174  }