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

     1  package olm
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"strings"
     8  	"sync"
     9  	"time"
    10  
    11  	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/labeller"
    12  	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/plugins"
    13  	"github.com/sirupsen/logrus"
    14  	appsv1 "k8s.io/api/apps/v1"
    15  	corev1 "k8s.io/api/core/v1"
    16  	rbacv1 "k8s.io/api/rbac/v1"
    17  	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    18  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    19  	"k8s.io/apimachinery/pkg/api/meta"
    20  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    21  	"k8s.io/apimachinery/pkg/labels"
    22  	"k8s.io/apimachinery/pkg/runtime"
    23  	"k8s.io/apimachinery/pkg/runtime/schema"
    24  	"k8s.io/apimachinery/pkg/selection"
    25  	utilerrors "k8s.io/apimachinery/pkg/util/errors"
    26  	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
    27  	appsv1applyconfigurations "k8s.io/client-go/applyconfigurations/apps/v1"
    28  	rbacv1applyconfigurations "k8s.io/client-go/applyconfigurations/rbac/v1"
    29  	"k8s.io/client-go/informers"
    30  	k8sscheme "k8s.io/client-go/kubernetes/scheme"
    31  	"k8s.io/client-go/metadata/metadatainformer"
    32  	"k8s.io/client-go/metadata/metadatalister"
    33  	"k8s.io/client-go/tools/cache"
    34  	"k8s.io/client-go/tools/record"
    35  	"k8s.io/client-go/util/workqueue"
    36  	apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
    37  	kagg "k8s.io/kube-aggregator/pkg/client/informers/externalversions"
    38  	utilclock "k8s.io/utils/clock"
    39  	"sigs.k8s.io/controller-runtime/pkg/client"
    40  	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
    41  
    42  	operatorsv1 "github.com/operator-framework/api/pkg/operators/v1"
    43  	"github.com/operator-framework/api/pkg/operators/v1alpha1"
    44  	"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned"
    45  	"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/informers/externalversions"
    46  	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/certs"
    47  	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
    48  	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/overrides"
    49  	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver"
    50  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/clients"
    51  	csvutility "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/csv"
    52  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/event"
    53  	index "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/index"
    54  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/labeler"
    55  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
    56  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorlister"
    57  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil"
    58  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/proxy"
    59  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer"
    60  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/scoped"
    61  	"github.com/operator-framework/operator-lifecycle-manager/pkg/metrics"
    62  )
    63  
    64  var (
    65  	ErrRequirementsNotMet      = errors.New("requirements were not met")
    66  	ErrCRDOwnerConflict        = errors.New("conflicting CRD owner in namespace")
    67  	ErrAPIServiceOwnerConflict = errors.New("unable to adopt APIService")
    68  )
    69  
    70  // this unexported operator plugin slice provides an entrypoint for
    71  // downstream to inject its own plugins to augment the controller behavior
    72  var operatorPlugInFactoryFuncs []plugins.OperatorPlugInFactoryFunc
    73  
    74  type Operator struct {
    75  	queueinformer.Operator
    76  
    77  	clock                        utilclock.Clock
    78  	logger                       *logrus.Logger
    79  	opClient                     operatorclient.ClientInterface
    80  	client                       versioned.Interface
    81  	lister                       operatorlister.OperatorLister
    82  	protectedCopiedCSVNamespaces map[string]struct{}
    83  	copiedCSVLister              metadatalister.Lister
    84  	ogQueueSet                   *queueinformer.ResourceQueueSet
    85  	csvQueueSet                  *queueinformer.ResourceQueueSet
    86  	olmConfigQueue               workqueue.TypedRateLimitingInterface[any]
    87  	csvCopyQueueSet              *queueinformer.ResourceQueueSet
    88  	copiedCSVGCQueueSet          *queueinformer.ResourceQueueSet
    89  	nsQueueSet                   workqueue.TypedRateLimitingInterface[any]
    90  	apiServiceQueue              workqueue.TypedRateLimitingInterface[any]
    91  	csvIndexers                  map[string]cache.Indexer
    92  	recorder                     record.EventRecorder
    93  	resolver                     install.StrategyResolverInterface
    94  	apiReconciler                APIIntersectionReconciler
    95  	apiLabeler                   labeler.Labeler
    96  	csvSetGenerator              csvutility.SetGenerator
    97  	csvReplaceFinder             csvutility.ReplaceFinder
    98  	csvNotification              csvutility.WatchNotification
    99  	serviceAccountSyncer         *scoped.UserDefinedServiceAccountSyncer
   100  	clientAttenuator             *scoped.ClientAttenuator
   101  	serviceAccountQuerier        *scoped.UserDefinedServiceAccountQuerier
   102  	clientFactory                clients.Factory
   103  	plugins                      []plugins.OperatorPlugin
   104  	informersByNamespace         map[string]*plugins.Informers
   105  	informersFiltered            bool
   106  
   107  	ruleChecker     func(*v1alpha1.ClusterServiceVersion) *install.CSVRuleChecker
   108  	ruleCheckerLock sync.RWMutex
   109  	resyncPeriod    func() time.Duration
   110  	ctx             context.Context
   111  }
   112  
   113  func (a *Operator) Informers() map[string]*plugins.Informers {
   114  	return a.informersByNamespace
   115  }
   116  
   117  func (a *Operator) getRuleChecker() func(*v1alpha1.ClusterServiceVersion) *install.CSVRuleChecker {
   118  	var ruleChecker func(*v1alpha1.ClusterServiceVersion) *install.CSVRuleChecker
   119  	a.ruleCheckerLock.RLock()
   120  	ruleChecker = a.ruleChecker
   121  	a.ruleCheckerLock.RUnlock()
   122  	if ruleChecker != nil {
   123  		return ruleChecker
   124  	}
   125  
   126  	a.ruleCheckerLock.Lock()
   127  	defer a.ruleCheckerLock.Unlock()
   128  	if a.ruleChecker != nil {
   129  		return a.ruleChecker
   130  	}
   131  
   132  	sif := informers.NewSharedInformerFactoryWithOptions(a.opClient.KubernetesInterface(), a.resyncPeriod())
   133  	rolesLister := sif.Rbac().V1().Roles().Lister()
   134  	roleBindingsLister := sif.Rbac().V1().RoleBindings().Lister()
   135  	clusterRolesLister := sif.Rbac().V1().ClusterRoles().Lister()
   136  	clusterRoleBindingsLister := sif.Rbac().V1().ClusterRoleBindings().Lister()
   137  
   138  	sif.Start(a.ctx.Done())
   139  	sif.WaitForCacheSync(a.ctx.Done())
   140  
   141  	if a.ctx.Err() != nil {
   142  		a.ruleChecker = nil
   143  		return nil
   144  	}
   145  
   146  	a.ruleChecker = func(csv *v1alpha1.ClusterServiceVersion) *install.CSVRuleChecker {
   147  		return install.NewCSVRuleChecker(
   148  			rolesLister, roleBindingsLister,
   149  			clusterRolesLister, clusterRoleBindingsLister,
   150  			csv,
   151  		)
   152  	}
   153  	return a.ruleChecker
   154  }
   155  
   156  func NewOperator(ctx context.Context, options ...OperatorOption) (*Operator, error) {
   157  	config := defaultOperatorConfig()
   158  	config.apply(options)
   159  
   160  	return newOperatorWithConfig(ctx, config)
   161  }
   162  
   163  func newOperatorWithConfig(ctx context.Context, config *operatorConfig) (*Operator, error) {
   164  	if err := config.validate(); err != nil {
   165  		return nil, err
   166  	}
   167  
   168  	queueOperator, err := queueinformer.NewOperator(config.operatorClient.KubernetesInterface().Discovery(), queueinformer.WithOperatorLogger(config.logger))
   169  	if err != nil {
   170  		return nil, err
   171  	}
   172  
   173  	eventRecorder, err := event.NewRecorder(config.operatorClient.KubernetesInterface().CoreV1().Events(metav1.NamespaceAll))
   174  	if err != nil {
   175  		return nil, err
   176  	}
   177  
   178  	lister := operatorlister.NewLister()
   179  
   180  	scheme := runtime.NewScheme()
   181  	if err := k8sscheme.AddToScheme(scheme); err != nil {
   182  		return nil, err
   183  	}
   184  	if err := metav1.AddMetaToScheme(scheme); err != nil {
   185  		return nil, err
   186  	}
   187  
   188  	canFilter, err := labeller.Validate(ctx, config.logger, config.metadataClient, config.externalClient, labeller.IdentityOLMOperator)
   189  	if err != nil {
   190  		return nil, err
   191  	}
   192  
   193  	op := &Operator{
   194  		Operator:    queueOperator,
   195  		clock:       config.clock,
   196  		logger:      config.logger,
   197  		opClient:    config.operatorClient,
   198  		client:      config.externalClient,
   199  		ogQueueSet:  queueinformer.NewEmptyResourceQueueSet(),
   200  		csvQueueSet: queueinformer.NewEmptyResourceQueueSet(),
   201  		olmConfigQueue: workqueue.NewTypedRateLimitingQueueWithConfig[any](
   202  			workqueue.DefaultTypedControllerRateLimiter[any](),
   203  			workqueue.TypedRateLimitingQueueConfig[any]{
   204  				Name: "olmConfig",
   205  			}),
   206  
   207  		csvCopyQueueSet:     queueinformer.NewEmptyResourceQueueSet(),
   208  		copiedCSVGCQueueSet: queueinformer.NewEmptyResourceQueueSet(),
   209  		apiServiceQueue: workqueue.NewTypedRateLimitingQueueWithConfig[any](
   210  			workqueue.DefaultTypedControllerRateLimiter[any](),
   211  			workqueue.TypedRateLimitingQueueConfig[any]{
   212  				Name: "apiservice",
   213  			}),
   214  		resolver:                     config.strategyResolver,
   215  		apiReconciler:                config.apiReconciler,
   216  		lister:                       lister,
   217  		recorder:                     eventRecorder,
   218  		apiLabeler:                   config.apiLabeler,
   219  		csvIndexers:                  map[string]cache.Indexer{},
   220  		csvSetGenerator:              csvutility.NewSetGenerator(config.logger, lister),
   221  		csvReplaceFinder:             csvutility.NewReplaceFinder(config.logger, config.externalClient),
   222  		serviceAccountSyncer:         scoped.NewUserDefinedServiceAccountSyncer(config.logger, scheme, config.operatorClient, config.externalClient),
   223  		clientAttenuator:             scoped.NewClientAttenuator(config.logger, config.restConfig, config.operatorClient),
   224  		serviceAccountQuerier:        scoped.NewUserDefinedServiceAccountQuerier(config.logger, config.externalClient),
   225  		clientFactory:                clients.NewFactory(config.restConfig),
   226  		protectedCopiedCSVNamespaces: config.protectedCopiedCSVNamespaces,
   227  		resyncPeriod:                 config.resyncPeriod,
   228  		ruleCheckerLock:              sync.RWMutex{},
   229  		ctx:                          ctx,
   230  		informersFiltered:            canFilter,
   231  	}
   232  
   233  	informersByNamespace := map[string]*plugins.Informers{}
   234  	// Set up syncing for namespace-scoped resources
   235  	k8sSyncer := queueinformer.LegacySyncHandler(op.syncObject).ToSyncerWithDelete(op.handleDeletion)
   236  	for _, namespace := range config.watchedNamespaces {
   237  		informersByNamespace[namespace] = &plugins.Informers{}
   238  		// Wire CSVs
   239  		csvInformer := externalversions.NewSharedInformerFactoryWithOptions(
   240  			op.client,
   241  			config.resyncPeriod(),
   242  			externalversions.WithNamespace(namespace),
   243  			externalversions.WithTweakListOptions(func(options *metav1.ListOptions) {
   244  				options.LabelSelector = fmt.Sprintf("!%s", v1alpha1.CopiedLabelKey)
   245  			}),
   246  		).Operators().V1alpha1().ClusterServiceVersions()
   247  		informersByNamespace[namespace].CSVInformer = csvInformer
   248  		op.lister.OperatorsV1alpha1().RegisterClusterServiceVersionLister(namespace, csvInformer.Lister())
   249  		csvQueue := workqueue.NewTypedRateLimitingQueueWithConfig[any](
   250  			workqueue.DefaultTypedControllerRateLimiter[any](),
   251  			workqueue.TypedRateLimitingQueueConfig[any]{
   252  				Name: fmt.Sprintf("%s/csv", namespace),
   253  			})
   254  		op.csvQueueSet.Set(namespace, csvQueue)
   255  		csvQueueInformer, err := queueinformer.NewQueueInformer(
   256  			ctx,
   257  			queueinformer.WithMetricsProvider(metrics.NewMetricsCSV(csvInformer.Lister())),
   258  			queueinformer.WithLogger(op.logger),
   259  			queueinformer.WithQueue(csvQueue),
   260  			queueinformer.WithInformer(csvInformer.Informer()),
   261  			queueinformer.WithSyncer(queueinformer.LegacySyncHandler(op.syncClusterServiceVersion).ToSyncerWithDelete(op.handleClusterServiceVersionDeletion)),
   262  		)
   263  		if err != nil {
   264  			return nil, err
   265  		}
   266  		if err := op.RegisterQueueInformer(csvQueueInformer); err != nil {
   267  			return nil, err
   268  		}
   269  		if err := csvInformer.Informer().AddIndexers(cache.Indexers{index.MetaLabelIndexFuncKey: index.MetaLabelIndexFunc}); err != nil {
   270  			return nil, err
   271  		}
   272  		csvIndexer := csvInformer.Informer().GetIndexer()
   273  		op.csvIndexers[namespace] = csvIndexer
   274  
   275  		// Register separate queue for copying csvs
   276  		csvCopyQueue := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultTypedControllerRateLimiter[any](), fmt.Sprintf("%s/csv-copy", namespace))
   277  		op.csvCopyQueueSet.Set(namespace, csvCopyQueue)
   278  		csvCopyQueueInformer, err := queueinformer.NewQueueInformer(
   279  			ctx,
   280  			queueinformer.WithLogger(op.logger),
   281  			queueinformer.WithQueue(csvCopyQueue),
   282  			queueinformer.WithIndexer(csvIndexer),
   283  			queueinformer.WithSyncer(queueinformer.LegacySyncHandler(op.syncCopyCSV).ToSyncer()),
   284  		)
   285  		if err != nil {
   286  			return nil, err
   287  		}
   288  		if err := op.RegisterQueueInformer(csvCopyQueueInformer); err != nil {
   289  			return nil, err
   290  		}
   291  
   292  		// A separate informer solely for CSV copies. Object metadata requests are used
   293  		// by this informer in order to reduce cached size.
   294  		gvr := v1alpha1.SchemeGroupVersion.WithResource("clusterserviceversions")
   295  		copiedCSVInformer := metadatainformer.NewFilteredMetadataInformer(
   296  			config.metadataClient,
   297  			gvr,
   298  			namespace,
   299  			config.resyncPeriod(),
   300  			cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
   301  			func(options *metav1.ListOptions) {
   302  				options.LabelSelector = v1alpha1.CopiedLabelKey
   303  			},
   304  		).Informer()
   305  		op.copiedCSVLister = metadatalister.New(copiedCSVInformer.GetIndexer(), gvr)
   306  		informersByNamespace[namespace].CopiedCSVInformer = copiedCSVInformer
   307  		informersByNamespace[namespace].CopiedCSVLister = op.copiedCSVLister
   308  
   309  		// Register separate queue for gcing copied csvs
   310  		copiedCSVGCQueue := workqueue.NewTypedRateLimitingQueueWithConfig[any](
   311  			workqueue.DefaultTypedControllerRateLimiter[any](),
   312  			workqueue.TypedRateLimitingQueueConfig[any]{
   313  				Name: fmt.Sprintf("%s/csv-gc", namespace),
   314  			})
   315  		op.copiedCSVGCQueueSet.Set(namespace, copiedCSVGCQueue)
   316  		copiedCSVGCQueueInformer, err := queueinformer.NewQueueInformer(
   317  			ctx,
   318  			queueinformer.WithInformer(copiedCSVInformer),
   319  			queueinformer.WithLogger(op.logger),
   320  			queueinformer.WithQueue(copiedCSVGCQueue),
   321  			queueinformer.WithIndexer(copiedCSVInformer.GetIndexer()),
   322  			queueinformer.WithSyncer(queueinformer.LegacySyncHandler(op.syncGcCsv).ToSyncer()),
   323  		)
   324  		if err != nil {
   325  			return nil, err
   326  		}
   327  		if err := op.RegisterQueueInformer(copiedCSVGCQueueInformer); err != nil {
   328  			return nil, err
   329  		}
   330  
   331  		// Wire OperatorGroup reconciliation
   332  		extInformerFactory := externalversions.NewSharedInformerFactoryWithOptions(op.client, config.resyncPeriod(), externalversions.WithNamespace(namespace))
   333  		operatorGroupInformer := extInformerFactory.Operators().V1().OperatorGroups()
   334  		informersByNamespace[namespace].OperatorGroupInformer = operatorGroupInformer
   335  		op.lister.OperatorsV1().RegisterOperatorGroupLister(namespace, operatorGroupInformer.Lister())
   336  		ogQueue := workqueue.NewTypedRateLimitingQueueWithConfig[any](
   337  			workqueue.DefaultTypedControllerRateLimiter[any](),
   338  			workqueue.TypedRateLimitingQueueConfig[any]{
   339  				Name: fmt.Sprintf("%s/og", namespace),
   340  			})
   341  		op.ogQueueSet.Set(namespace, ogQueue)
   342  		operatorGroupQueueInformer, err := queueinformer.NewQueueInformer(
   343  			ctx,
   344  			queueinformer.WithLogger(op.logger),
   345  			queueinformer.WithQueue(ogQueue),
   346  			queueinformer.WithInformer(operatorGroupInformer.Informer()),
   347  			queueinformer.WithSyncer(queueinformer.LegacySyncHandler(op.syncOperatorGroups).ToSyncerWithDelete(op.operatorGroupDeleted)),
   348  		)
   349  		if err != nil {
   350  			return nil, err
   351  		}
   352  		if err := op.RegisterQueueInformer(operatorGroupQueueInformer); err != nil {
   353  			return nil, err
   354  		}
   355  
   356  		// Register OperatorCondition QueueInformer
   357  		opConditionInformer := extInformerFactory.Operators().V2().OperatorConditions()
   358  		informersByNamespace[namespace].OperatorConditionInformer = opConditionInformer
   359  		op.lister.OperatorsV2().RegisterOperatorConditionLister(namespace, opConditionInformer.Lister())
   360  		opConditionQueueInformer, err := queueinformer.NewQueueInformer(
   361  			ctx,
   362  			queueinformer.WithLogger(op.logger),
   363  			queueinformer.WithInformer(opConditionInformer.Informer()),
   364  			queueinformer.WithSyncer(k8sSyncer),
   365  		)
   366  		if err != nil {
   367  			return nil, err
   368  		}
   369  		if err := op.RegisterQueueInformer(opConditionQueueInformer); err != nil {
   370  			return nil, err
   371  		}
   372  
   373  		subInformer := extInformerFactory.Operators().V1alpha1().Subscriptions()
   374  		informersByNamespace[namespace].SubscriptionInformer = subInformer
   375  		op.lister.OperatorsV1alpha1().RegisterSubscriptionLister(namespace, subInformer.Lister())
   376  		subQueueInformer, err := queueinformer.NewQueueInformer(
   377  			ctx,
   378  			queueinformer.WithLogger(op.logger),
   379  			queueinformer.WithInformer(subInformer.Informer()),
   380  			queueinformer.WithSyncer(queueinformer.LegacySyncHandler(op.syncSubscription).ToSyncerWithDelete(op.syncSubscriptionDeleted)),
   381  		)
   382  		if err != nil {
   383  			return nil, err
   384  		}
   385  		if err := op.RegisterQueueInformer(subQueueInformer); err != nil {
   386  			return nil, err
   387  		}
   388  
   389  		// Wire Deployments
   390  		k8sInformerFactory := informers.NewSharedInformerFactoryWithOptions(op.opClient.KubernetesInterface(), config.resyncPeriod(), func() []informers.SharedInformerOption {
   391  			opts := []informers.SharedInformerOption{
   392  				informers.WithNamespace(namespace),
   393  			}
   394  			if canFilter {
   395  				opts = append(opts, informers.WithTweakListOptions(func(options *metav1.ListOptions) {
   396  					options.LabelSelector = labels.SelectorFromSet(labels.Set{install.OLMManagedLabelKey: install.OLMManagedLabelValue}).String()
   397  				}))
   398  			}
   399  			return opts
   400  		}()...)
   401  		depInformer := k8sInformerFactory.Apps().V1().Deployments()
   402  		informersByNamespace[namespace].DeploymentInformer = depInformer
   403  		op.lister.AppsV1().RegisterDeploymentLister(namespace, depInformer.Lister())
   404  		depQueueInformer, err := queueinformer.NewQueueInformer(
   405  			ctx,
   406  			queueinformer.WithLogger(op.logger),
   407  			queueinformer.WithInformer(depInformer.Informer()),
   408  			queueinformer.WithSyncer(k8sSyncer),
   409  		)
   410  		if err != nil {
   411  			return nil, err
   412  		}
   413  		if err := op.RegisterQueueInformer(depQueueInformer); err != nil {
   414  			return nil, err
   415  		}
   416  
   417  		// Set up RBAC informers
   418  		roleInformer := k8sInformerFactory.Rbac().V1().Roles()
   419  		informersByNamespace[namespace].RoleInformer = roleInformer
   420  		op.lister.RbacV1().RegisterRoleLister(namespace, roleInformer.Lister())
   421  		roleQueueInformer, err := queueinformer.NewQueueInformer(
   422  			ctx,
   423  			queueinformer.WithLogger(op.logger),
   424  			queueinformer.WithInformer(roleInformer.Informer()),
   425  			queueinformer.WithSyncer(k8sSyncer),
   426  		)
   427  		if err != nil {
   428  			return nil, err
   429  		}
   430  		if err := op.RegisterQueueInformer(roleQueueInformer); err != nil {
   431  			return nil, err
   432  		}
   433  
   434  		roleBindingInformer := k8sInformerFactory.Rbac().V1().RoleBindings()
   435  		informersByNamespace[namespace].RoleBindingInformer = roleBindingInformer
   436  		op.lister.RbacV1().RegisterRoleBindingLister(namespace, roleBindingInformer.Lister())
   437  		roleBindingQueueInformer, err := queueinformer.NewQueueInformer(
   438  			ctx,
   439  			queueinformer.WithLogger(op.logger),
   440  			queueinformer.WithInformer(roleBindingInformer.Informer()),
   441  			queueinformer.WithSyncer(k8sSyncer),
   442  		)
   443  		if err != nil {
   444  			return nil, err
   445  		}
   446  		if err := op.RegisterQueueInformer(roleBindingQueueInformer); err != nil {
   447  			return nil, err
   448  		}
   449  
   450  		// Register Secret QueueInformer
   451  		secretInformer := informers.NewSharedInformerFactoryWithOptions(op.opClient.KubernetesInterface(), config.resyncPeriod(), informers.WithNamespace(namespace), informers.WithTweakListOptions(func(options *metav1.ListOptions) {
   452  			options.LabelSelector = labels.SelectorFromValidatedSet(map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}).String()
   453  		})).Core().V1().Secrets()
   454  		informersByNamespace[namespace].SecretInformer = secretInformer
   455  		op.lister.CoreV1().RegisterSecretLister(namespace, secretInformer.Lister())
   456  		secretQueueInformer, err := queueinformer.NewQueueInformer(
   457  			ctx,
   458  			queueinformer.WithLogger(op.logger),
   459  			queueinformer.WithInformer(secretInformer.Informer()),
   460  			queueinformer.WithSyncer(k8sSyncer),
   461  		)
   462  		if err != nil {
   463  			return nil, err
   464  		}
   465  		if err := op.RegisterQueueInformer(secretQueueInformer); err != nil {
   466  			return nil, err
   467  		}
   468  
   469  		// Register Service QueueInformer
   470  		serviceInformer := k8sInformerFactory.Core().V1().Services()
   471  		informersByNamespace[namespace].ServiceInformer = serviceInformer
   472  		op.lister.CoreV1().RegisterServiceLister(namespace, serviceInformer.Lister())
   473  		serviceQueueInformer, err := queueinformer.NewQueueInformer(
   474  			ctx,
   475  			queueinformer.WithLogger(op.logger),
   476  			queueinformer.WithInformer(serviceInformer.Informer()),
   477  			queueinformer.WithSyncer(k8sSyncer),
   478  		)
   479  		if err != nil {
   480  			return nil, err
   481  		}
   482  		if err := op.RegisterQueueInformer(serviceQueueInformer); err != nil {
   483  			return nil, err
   484  		}
   485  
   486  		// Register ServiceAccount QueueInformer
   487  		serviceAccountInformer := k8sInformerFactory.Core().V1().ServiceAccounts()
   488  		informersByNamespace[namespace].ServiceAccountInformer = serviceAccountInformer
   489  		op.lister.CoreV1().RegisterServiceAccountLister(metav1.NamespaceAll, serviceAccountInformer.Lister())
   490  		serviceAccountQueueInformer, err := queueinformer.NewQueueInformer(
   491  			ctx,
   492  			queueinformer.WithLogger(op.logger),
   493  			queueinformer.WithInformer(serviceAccountInformer.Informer()),
   494  			queueinformer.WithSyncer(k8sSyncer),
   495  		)
   496  		if err != nil {
   497  			return nil, err
   498  		}
   499  		if err := op.RegisterQueueInformer(serviceAccountQueueInformer); err != nil {
   500  			return nil, err
   501  		}
   502  	}
   503  
   504  	complete := map[schema.GroupVersionResource][]bool{}
   505  	completeLock := &sync.Mutex{}
   506  
   507  	labelObjects := func(gvr schema.GroupVersionResource, informer cache.SharedIndexInformer, sync func(done func() bool) queueinformer.LegacySyncHandler) error {
   508  		if canFilter {
   509  			return nil
   510  		}
   511  
   512  		// for each GVR, we may have more than one labelling controller active; each of which detects
   513  		// when it is done; we allocate a space in complete[gvr][idx] to hold that outcome and track it
   514  		var idx int
   515  		if _, exists := complete[gvr]; exists {
   516  			idx = len(complete[gvr])
   517  			complete[gvr] = append(complete[gvr], false)
   518  		} else {
   519  			idx = 0
   520  			complete[gvr] = []bool{false}
   521  		}
   522  		logger := op.logger.WithFields(logrus.Fields{"gvr": gvr.String(), "index": idx})
   523  		logger.Info("registering labeller")
   524  
   525  		queue := workqueue.NewTypedRateLimitingQueueWithConfig[any](workqueue.DefaultTypedControllerRateLimiter[any](), workqueue.TypedRateLimitingQueueConfig[any]{
   526  			Name: gvr.String(),
   527  		})
   528  		queueInformer, err := queueinformer.NewQueueInformer(
   529  			ctx,
   530  			queueinformer.WithQueue(queue),
   531  			queueinformer.WithLogger(op.logger),
   532  			queueinformer.WithInformer(informer),
   533  			queueinformer.WithSyncer(sync(func() bool {
   534  				// this function is called by the processor when it detects that it's work is done - so, for that
   535  				// particular labelling action on that particular GVR, all objects are in the correct state. when
   536  				// that action is done, we need to further know if that was the last action to be completed, as
   537  				// when every action we know about has been completed, we re-start the process to allow the future
   538  				// invocation of this process to filter informers (canFilter = true) and elide all this logic
   539  				completeLock.Lock()
   540  				logger.Info("labeller complete")
   541  				complete[gvr][idx] = true
   542  				allDone := true
   543  				for _, items := range complete {
   544  					for _, done := range items {
   545  						allDone = allDone && done
   546  					}
   547  				}
   548  				completeLock.Unlock()
   549  				return allDone
   550  			}).ToSyncer()),
   551  		)
   552  		if err != nil {
   553  			return err
   554  		}
   555  
   556  		if err := op.RegisterQueueInformer(queueInformer); err != nil {
   557  			return err
   558  		}
   559  
   560  		return nil
   561  	}
   562  
   563  	deploymentsgvk := appsv1.SchemeGroupVersion.WithResource("deployments")
   564  	if err := labelObjects(deploymentsgvk, informersByNamespace[metav1.NamespaceAll].DeploymentInformer.Informer(), labeller.ObjectLabeler[*appsv1.Deployment, *appsv1applyconfigurations.DeploymentApplyConfiguration](
   565  		ctx, op.logger, labeller.Filter(deploymentsgvk),
   566  		informersByNamespace[metav1.NamespaceAll].DeploymentInformer.Lister().List,
   567  		appsv1applyconfigurations.Deployment,
   568  		func(namespace string, ctx context.Context, cfg *appsv1applyconfigurations.DeploymentApplyConfiguration, opts metav1.ApplyOptions) (*appsv1.Deployment, error) {
   569  			return op.opClient.KubernetesInterface().AppsV1().Deployments(namespace).Apply(ctx, cfg, opts)
   570  		},
   571  	)); err != nil {
   572  		return nil, err
   573  	}
   574  
   575  	// Register QueueInformer for olmConfig
   576  	olmConfigInformer := externalversions.NewSharedInformerFactoryWithOptions(
   577  		op.client,
   578  		config.resyncPeriod(),
   579  	).Operators().V1().OLMConfigs()
   580  	informersByNamespace[metav1.NamespaceAll].OLMConfigInformer = olmConfigInformer
   581  	olmConfigQueueInformer, err := queueinformer.NewQueueInformer(
   582  		ctx,
   583  		queueinformer.WithInformer(olmConfigInformer.Informer()),
   584  		queueinformer.WithLogger(op.logger),
   585  		queueinformer.WithQueue(op.olmConfigQueue),
   586  		queueinformer.WithIndexer(olmConfigInformer.Informer().GetIndexer()),
   587  		queueinformer.WithSyncer(queueinformer.LegacySyncHandler(op.syncOLMConfig).ToSyncer()),
   588  	)
   589  	if err != nil {
   590  		return nil, err
   591  	}
   592  	if err := op.RegisterQueueInformer(olmConfigQueueInformer); err != nil {
   593  		return nil, err
   594  	}
   595  
   596  	k8sInformerFactory := informers.NewSharedInformerFactoryWithOptions(op.opClient.KubernetesInterface(), config.resyncPeriod(), func() []informers.SharedInformerOption {
   597  		if !canFilter {
   598  			return nil
   599  		}
   600  		return []informers.SharedInformerOption{informers.WithTweakListOptions(func(options *metav1.ListOptions) {
   601  			options.LabelSelector = labels.SelectorFromSet(labels.Set{install.OLMManagedLabelKey: install.OLMManagedLabelValue}).String()
   602  		})}
   603  	}()...)
   604  	clusterRoleInformer := k8sInformerFactory.Rbac().V1().ClusterRoles()
   605  	informersByNamespace[metav1.NamespaceAll].ClusterRoleInformer = clusterRoleInformer
   606  	op.lister.RbacV1().RegisterClusterRoleLister(clusterRoleInformer.Lister())
   607  	clusterRoleQueueInformer, err := queueinformer.NewQueueInformer(
   608  		ctx,
   609  		queueinformer.WithLogger(op.logger),
   610  		queueinformer.WithInformer(clusterRoleInformer.Informer()),
   611  		queueinformer.WithSyncer(k8sSyncer),
   612  	)
   613  	if err != nil {
   614  		return nil, err
   615  	}
   616  	if err := op.RegisterQueueInformer(clusterRoleQueueInformer); err != nil {
   617  		return nil, err
   618  	}
   619  
   620  	clusterrolesgvk := rbacv1.SchemeGroupVersion.WithResource("clusterroles")
   621  	if err := labelObjects(clusterrolesgvk, clusterRoleInformer.Informer(), labeller.ObjectLabeler[*rbacv1.ClusterRole, *rbacv1applyconfigurations.ClusterRoleApplyConfiguration](
   622  		ctx, op.logger, labeller.Filter(clusterrolesgvk),
   623  		clusterRoleInformer.Lister().List,
   624  		func(name, _ string) *rbacv1applyconfigurations.ClusterRoleApplyConfiguration {
   625  			return rbacv1applyconfigurations.ClusterRole(name)
   626  		},
   627  		func(_ string, ctx context.Context, cfg *rbacv1applyconfigurations.ClusterRoleApplyConfiguration, opts metav1.ApplyOptions) (*rbacv1.ClusterRole, error) {
   628  			return op.opClient.KubernetesInterface().RbacV1().ClusterRoles().Apply(ctx, cfg, opts)
   629  		},
   630  	)); err != nil {
   631  		return nil, err
   632  	}
   633  	if err := labelObjects(clusterrolesgvk, clusterRoleInformer.Informer(), labeller.ContentHashLabeler[*rbacv1.ClusterRole, *rbacv1applyconfigurations.ClusterRoleApplyConfiguration](
   634  		ctx, op.logger, labeller.ContentHashFilter,
   635  		func(clusterRole *rbacv1.ClusterRole) (string, error) {
   636  			return resolver.PolicyRuleHashLabelValue(clusterRole.Rules)
   637  		},
   638  		clusterRoleInformer.Lister().List,
   639  		func(name, _ string) *rbacv1applyconfigurations.ClusterRoleApplyConfiguration {
   640  			return rbacv1applyconfigurations.ClusterRole(name)
   641  		},
   642  		func(_ string, ctx context.Context, cfg *rbacv1applyconfigurations.ClusterRoleApplyConfiguration, opts metav1.ApplyOptions) (*rbacv1.ClusterRole, error) {
   643  			return op.opClient.KubernetesInterface().RbacV1().ClusterRoles().Apply(ctx, cfg, opts)
   644  		},
   645  	)); err != nil {
   646  		return nil, err
   647  	}
   648  
   649  	clusterRoleBindingInformer := k8sInformerFactory.Rbac().V1().ClusterRoleBindings()
   650  	informersByNamespace[metav1.NamespaceAll].ClusterRoleBindingInformer = clusterRoleBindingInformer
   651  	op.lister.RbacV1().RegisterClusterRoleBindingLister(clusterRoleBindingInformer.Lister())
   652  	clusterRoleBindingQueueInformer, err := queueinformer.NewQueueInformer(
   653  		ctx,
   654  		queueinformer.WithLogger(op.logger),
   655  		queueinformer.WithInformer(clusterRoleBindingInformer.Informer()),
   656  		queueinformer.WithSyncer(k8sSyncer),
   657  	)
   658  	if err != nil {
   659  		return nil, err
   660  	}
   661  	if err := op.RegisterQueueInformer(clusterRoleBindingQueueInformer); err != nil {
   662  		return nil, err
   663  	}
   664  
   665  	clusterrolebindingssgvk := rbacv1.SchemeGroupVersion.WithResource("clusterrolebindings")
   666  	if err := labelObjects(clusterrolebindingssgvk, clusterRoleBindingInformer.Informer(), labeller.ObjectLabeler[*rbacv1.ClusterRoleBinding, *rbacv1applyconfigurations.ClusterRoleBindingApplyConfiguration](
   667  		ctx, op.logger, labeller.Filter(clusterrolebindingssgvk),
   668  		clusterRoleBindingInformer.Lister().List,
   669  		func(name, _ string) *rbacv1applyconfigurations.ClusterRoleBindingApplyConfiguration {
   670  			return rbacv1applyconfigurations.ClusterRoleBinding(name)
   671  		},
   672  		func(_ string, ctx context.Context, cfg *rbacv1applyconfigurations.ClusterRoleBindingApplyConfiguration, opts metav1.ApplyOptions) (*rbacv1.ClusterRoleBinding, error) {
   673  			return op.opClient.KubernetesInterface().RbacV1().ClusterRoleBindings().Apply(ctx, cfg, opts)
   674  		},
   675  	)); err != nil {
   676  		return nil, err
   677  	}
   678  	if err := labelObjects(clusterrolebindingssgvk, clusterRoleBindingInformer.Informer(), labeller.ContentHashLabeler[*rbacv1.ClusterRoleBinding, *rbacv1applyconfigurations.ClusterRoleBindingApplyConfiguration](
   679  		ctx, op.logger, labeller.ContentHashFilter,
   680  		func(clusterRoleBinding *rbacv1.ClusterRoleBinding) (string, error) {
   681  			return resolver.RoleReferenceAndSubjectHashLabelValue(clusterRoleBinding.RoleRef, clusterRoleBinding.Subjects)
   682  		},
   683  		clusterRoleBindingInformer.Lister().List,
   684  		func(name, _ string) *rbacv1applyconfigurations.ClusterRoleBindingApplyConfiguration {
   685  			return rbacv1applyconfigurations.ClusterRoleBinding(name)
   686  		},
   687  		func(_ string, ctx context.Context, cfg *rbacv1applyconfigurations.ClusterRoleBindingApplyConfiguration, opts metav1.ApplyOptions) (*rbacv1.ClusterRoleBinding, error) {
   688  			return op.opClient.KubernetesInterface().RbacV1().ClusterRoleBindings().Apply(ctx, cfg, opts)
   689  		},
   690  	)); err != nil {
   691  		return nil, err
   692  	}
   693  
   694  	// register namespace queueinformer using a new informer factory - since namespaces won't have the labels
   695  	// that other k8s objects will
   696  	namespaceInformer := informers.NewSharedInformerFactory(op.opClient.KubernetesInterface(), config.resyncPeriod()).Core().V1().Namespaces()
   697  	informersByNamespace[metav1.NamespaceAll].NamespaceInformer = namespaceInformer
   698  	op.lister.CoreV1().RegisterNamespaceLister(namespaceInformer.Lister())
   699  	op.nsQueueSet = workqueue.NewTypedRateLimitingQueueWithConfig[any](
   700  		workqueue.DefaultTypedControllerRateLimiter[any](),
   701  		workqueue.TypedRateLimitingQueueConfig[any]{
   702  			Name: "resolver",
   703  		})
   704  	namespaceInformer.Informer().AddEventHandler(
   705  		&cache.ResourceEventHandlerFuncs{
   706  			DeleteFunc: op.namespaceAddedOrRemoved,
   707  			AddFunc:    op.namespaceAddedOrRemoved,
   708  		},
   709  	)
   710  	namespaceQueueInformer, err := queueinformer.NewQueueInformer(
   711  		ctx,
   712  		queueinformer.WithLogger(op.logger),
   713  		queueinformer.WithQueue(op.nsQueueSet),
   714  		queueinformer.WithInformer(namespaceInformer.Informer()),
   715  		queueinformer.WithSyncer(queueinformer.LegacySyncHandler(op.syncNamespace).ToSyncer()),
   716  	)
   717  	if err != nil {
   718  		return nil, err
   719  	}
   720  	if err := op.RegisterQueueInformer(namespaceQueueInformer); err != nil {
   721  		return nil, err
   722  	}
   723  
   724  	// Register APIService QueueInformer
   725  	apiServiceInformer := kagg.NewSharedInformerFactory(op.opClient.ApiregistrationV1Interface(), config.resyncPeriod()).Apiregistration().V1().APIServices()
   726  	informersByNamespace[metav1.NamespaceAll].APIServiceInformer = apiServiceInformer
   727  	op.lister.APIRegistrationV1().RegisterAPIServiceLister(apiServiceInformer.Lister())
   728  	apiServiceQueueInformer, err := queueinformer.NewQueueInformer(
   729  		ctx,
   730  		queueinformer.WithLogger(op.logger),
   731  		queueinformer.WithQueue(op.apiServiceQueue),
   732  		queueinformer.WithInformer(apiServiceInformer.Informer()),
   733  		queueinformer.WithSyncer(queueinformer.LegacySyncHandler(op.syncAPIService).ToSyncerWithDelete(op.handleDeletion)),
   734  	)
   735  	if err != nil {
   736  		return nil, err
   737  	}
   738  	if err := op.RegisterQueueInformer(apiServiceQueueInformer); err != nil {
   739  		return nil, err
   740  	}
   741  
   742  	// Register CustomResourceDefinition QueueInformer. Object metadata requests are used
   743  	// by this informer in order to reduce cached size.
   744  	gvr := apiextensionsv1.SchemeGroupVersion.WithResource("customresourcedefinitions")
   745  	crdInformer := metadatainformer.NewFilteredMetadataInformer(
   746  		config.metadataClient,
   747  		gvr,
   748  		metav1.NamespaceAll,
   749  		config.resyncPeriod(),
   750  		cache.Indexers{},
   751  		nil,
   752  	).Informer()
   753  	crdLister := metadatalister.New(crdInformer.GetIndexer(), gvr)
   754  	informersByNamespace[metav1.NamespaceAll].CRDInformer = crdInformer
   755  	informersByNamespace[metav1.NamespaceAll].CRDLister = crdLister
   756  	op.lister.APIExtensionsV1().RegisterCustomResourceDefinitionLister(crdLister)
   757  	crdQueueInformer, err := queueinformer.NewQueueInformer(
   758  		ctx,
   759  		queueinformer.WithLogger(op.logger),
   760  		queueinformer.WithInformer(crdInformer),
   761  		queueinformer.WithSyncer(k8sSyncer),
   762  	)
   763  	if err != nil {
   764  		return nil, err
   765  	}
   766  	if err := op.RegisterQueueInformer(crdQueueInformer); err != nil {
   767  		return nil, err
   768  	}
   769  
   770  	// setup proxy env var injection policies
   771  	discovery := config.operatorClient.KubernetesInterface().Discovery()
   772  	proxyAPIExists, err := proxy.IsAPIAvailable(discovery)
   773  	if err != nil {
   774  		op.logger.Errorf("error happened while probing for Proxy API support - %v", err)
   775  		return nil, err
   776  	}
   777  
   778  	proxyQuerierInUse := proxy.NoopQuerier()
   779  	if proxyAPIExists {
   780  		op.logger.Info("OpenShift Proxy API  available - setting up watch for Proxy type")
   781  
   782  		proxyInformer, proxySyncer, proxyQuerier, err := proxy.NewSyncer(op.logger, config.configClient, discovery)
   783  		if err != nil {
   784  			err = fmt.Errorf("failed to initialize syncer for Proxy type - %v", err)
   785  			return nil, err
   786  		}
   787  
   788  		op.logger.Info("OpenShift Proxy query will be used to fetch cluster proxy configuration")
   789  		proxyQuerierInUse = proxyQuerier
   790  
   791  		informer, err := queueinformer.NewQueueInformer(
   792  			ctx,
   793  			queueinformer.WithLogger(op.logger),
   794  			queueinformer.WithInformer(proxyInformer.Informer()),
   795  			queueinformer.WithSyncer(queueinformer.LegacySyncHandler(proxySyncer.SyncProxy).ToSyncerWithDelete(proxySyncer.HandleProxyDelete)),
   796  		)
   797  		if err != nil {
   798  			return nil, err
   799  		}
   800  		if err := op.RegisterQueueInformer(informer); err != nil {
   801  			return nil, err
   802  		}
   803  	}
   804  
   805  	overridesBuilderFunc := overrides.NewDeploymentInitializer(op.logger, proxyQuerierInUse, op.lister)
   806  	op.resolver = &install.StrategyResolver{
   807  		OverridesBuilderFunc: overridesBuilderFunc.GetDeploymentInitializer,
   808  	}
   809  	op.informersByNamespace = informersByNamespace
   810  
   811  	// initialize plugins
   812  	for _, makePlugIn := range operatorPlugInFactoryFuncs {
   813  		plugin, err := makePlugIn(ctx, config, op)
   814  		if err != nil {
   815  			return nil, fmt.Errorf("error creating plugin: %s", err)
   816  		}
   817  		op.plugins = append(op.plugins, plugin)
   818  	}
   819  
   820  	if len(operatorPlugInFactoryFuncs) > 0 {
   821  		go func() {
   822  			// block until operator is done
   823  			<-op.Done()
   824  
   825  			// shutdown plug-ins
   826  			for _, plugin := range op.plugins {
   827  				if err := plugin.Shutdown(); err != nil {
   828  					if op.logger != nil {
   829  						op.logger.Warnf("error shutting down plug-in: %s", err)
   830  					}
   831  				}
   832  			}
   833  		}()
   834  	}
   835  
   836  	return op, nil
   837  }
   838  
   839  func (a *Operator) now() *metav1.Time {
   840  	now := metav1.NewTime(a.clock.Now().UTC())
   841  	return &now
   842  }
   843  
   844  func (a *Operator) syncSubscription(obj interface{}) error {
   845  	sub, ok := obj.(*v1alpha1.Subscription)
   846  	if !ok {
   847  		a.logger.Debugf("wrong type: %#v\n", obj)
   848  		return fmt.Errorf("casting Subscription failed")
   849  	}
   850  
   851  	installedCSV := sub.Status.InstalledCSV
   852  	if installedCSV != "" {
   853  		a.logger.WithField("csv", installedCSV).Debug("subscription has changed, requeuing installed csv")
   854  		if err := a.csvQueueSet.Requeue(sub.GetNamespace(), installedCSV); err != nil {
   855  			a.logger.WithField("csv", installedCSV).Debug("failed to requeue installed csv")
   856  			return err
   857  		}
   858  	}
   859  
   860  	return nil
   861  }
   862  
   863  func (a *Operator) syncSubscriptionDeleted(obj interface{}) {
   864  	_, ok := obj.(*v1alpha1.Subscription)
   865  	if !ok {
   866  		a.logger.Debugf("casting Subscription failed, wrong type: %#v\n", obj)
   867  	}
   868  }
   869  
   870  func (a *Operator) syncAPIService(obj interface{}) (syncError error) {
   871  	apiService, ok := obj.(*apiregistrationv1.APIService)
   872  	if !ok {
   873  		a.logger.Debugf("wrong type: %#v", obj)
   874  		return fmt.Errorf("casting APIService failed")
   875  	}
   876  
   877  	logger := a.logger.WithFields(logrus.Fields{
   878  		"id":         queueinformer.NewLoopID(),
   879  		"apiService": apiService.GetName(),
   880  	})
   881  	logger.Debug("syncing APIService")
   882  
   883  	if name, ns, ok := ownerutil.GetOwnerByKindLabel(apiService, v1alpha1.ClusterServiceVersionKind); ok {
   884  		_, err := a.lister.CoreV1().NamespaceLister().Get(ns)
   885  		if apierrors.IsNotFound(err) {
   886  			logger.Debug("Deleting api service since owning namespace is not found")
   887  			syncError = a.opClient.DeleteAPIService(apiService.GetName(), &metav1.DeleteOptions{})
   888  			return
   889  		}
   890  
   891  		_, err = a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(ns).Get(name)
   892  		if apierrors.IsNotFound(err) {
   893  			logger.Debug("Deleting api service since owning CSV is not found")
   894  			syncError = a.opClient.DeleteAPIService(apiService.GetName(), &metav1.DeleteOptions{})
   895  			return
   896  		} else if err != nil {
   897  			syncError = err
   898  			return
   899  		} else {
   900  			if ownerutil.IsOwnedByKindLabel(apiService, v1alpha1.ClusterServiceVersionKind) {
   901  				logger.Debug("requeueing owner CSVs")
   902  				a.requeueOwnerCSVs(apiService)
   903  			}
   904  		}
   905  	}
   906  
   907  	return nil
   908  }
   909  
   910  func (a *Operator) GetCSVSetGenerator() csvutility.SetGenerator {
   911  	return a.csvSetGenerator
   912  }
   913  
   914  func (a *Operator) GetReplaceFinder() csvutility.ReplaceFinder {
   915  	return a.csvReplaceFinder
   916  }
   917  
   918  func (a *Operator) RegisterCSVWatchNotification(csvNotification csvutility.WatchNotification) {
   919  	if csvNotification == nil {
   920  		return
   921  	}
   922  
   923  	a.csvNotification = csvNotification
   924  }
   925  
   926  func (a *Operator) EnsureCSVMetric() error {
   927  	csvs, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().List(labels.Everything())
   928  	if err != nil {
   929  		return err
   930  	}
   931  	for _, csv := range csvs {
   932  		logger := a.logger.WithFields(logrus.Fields{
   933  			"name":      csv.GetName(),
   934  			"namespace": csv.GetNamespace(),
   935  			"self":      csv.GetSelfLink(),
   936  		})
   937  		logger.Debug("emitting metrics for existing CSV")
   938  		metrics.EmitCSVMetric(csv, csv)
   939  	}
   940  	return nil
   941  }
   942  
   943  func (a *Operator) syncObject(obj interface{}) (syncError error) {
   944  	// Assert as metav1.Object
   945  	metaObj, ok := obj.(metav1.Object)
   946  	if !ok {
   947  		syncError = errors.New("object sync: casting to metav1.Object failed")
   948  		a.logger.Warn(syncError.Error())
   949  		return
   950  	}
   951  	logger := a.logger.WithFields(logrus.Fields{
   952  		"name":      metaObj.GetName(),
   953  		"namespace": metaObj.GetNamespace(),
   954  		"self":      metaObj.GetSelfLink(),
   955  	})
   956  
   957  	// Objects that can't have ownerrefs (cluster -> namespace, cross-namespace)
   958  	// are handled by finalizer
   959  
   960  	// Requeue all owner CSVs
   961  	if ownerutil.IsOwnedByKind(metaObj, v1alpha1.ClusterServiceVersionKind) {
   962  		logger.Debug("requeueing owner csvs")
   963  		a.requeueOwnerCSVs(metaObj)
   964  	}
   965  
   966  	// Requeue CSVs with provided and required labels (for CRDs)
   967  	if labelSets, err := a.apiLabeler.LabelSetsFor(metaObj); err != nil {
   968  		logger.WithError(err).Warn("couldn't create label set")
   969  	} else if len(labelSets) > 0 {
   970  		logger.Debug("requeueing providing/requiring csvs")
   971  		a.requeueCSVsByLabelSet(logger, labelSets...)
   972  	}
   973  
   974  	// Requeue CSVs that have the reason of `CSVReasonComponentFailedNoRetry` in the case of an RBAC change
   975  	var errs []error
   976  	related, _ := scoped.IsObjectRBACRelated(metaObj)
   977  	if related {
   978  		csvList := a.csvSet(metaObj.GetNamespace(), v1alpha1.CSVPhaseFailed)
   979  		for _, csv := range csvList {
   980  			csv = csv.DeepCopy()
   981  			if csv.Status.Reason != v1alpha1.CSVReasonComponentFailedNoRetry {
   982  				continue
   983  			}
   984  			csv.SetPhase(v1alpha1.CSVPhasePending, v1alpha1.CSVReasonDetectedClusterChange, "Cluster resources changed state", a.now())
   985  			_, err := a.client.OperatorsV1alpha1().ClusterServiceVersions(csv.GetNamespace()).UpdateStatus(context.TODO(), csv, metav1.UpdateOptions{})
   986  			if err != nil {
   987  				errs = append(errs, err)
   988  				continue
   989  			}
   990  			if err := a.csvQueueSet.Requeue(csv.GetNamespace(), csv.GetName()); err != nil {
   991  				errs = append(errs, err)
   992  			}
   993  			logger.Debug("Requeuing CSV due to detected RBAC change")
   994  		}
   995  	}
   996  
   997  	syncError = utilerrors.NewAggregate(errs)
   998  	return nil
   999  }
  1000  
  1001  func (a *Operator) namespaceAddedOrRemoved(obj interface{}) {
  1002  	// Check to see if any operator groups are associated with this namespace
  1003  	namespace, ok := obj.(*corev1.Namespace)
  1004  	if !ok {
  1005  		return
  1006  	}
  1007  
  1008  	logger := a.logger.WithFields(logrus.Fields{
  1009  		"name": namespace.GetName(),
  1010  	})
  1011  
  1012  	operatorGroupList, err := a.lister.OperatorsV1().OperatorGroupLister().OperatorGroups(metav1.NamespaceAll).List(labels.Everything())
  1013  	if err != nil {
  1014  		logger.WithError(err).Warn("lister failed")
  1015  		return
  1016  	}
  1017  
  1018  	for _, group := range operatorGroupList {
  1019  		if NewNamespaceSet(group.Status.Namespaces).Contains(namespace.GetName()) {
  1020  			if err := a.ogQueueSet.Requeue(group.Namespace, group.Name); err != nil {
  1021  				logger.WithError(err).Warn("error requeuing operatorgroup")
  1022  			}
  1023  		}
  1024  	}
  1025  }
  1026  
  1027  func (a *Operator) syncNamespace(obj interface{}) error {
  1028  	// Check to see if any operator groups are associated with this namespace
  1029  	namespace, ok := obj.(*corev1.Namespace)
  1030  	if !ok {
  1031  		a.logger.Debugf("wrong type: %#v\n", obj)
  1032  		return fmt.Errorf("casting Namespace failed")
  1033  	}
  1034  
  1035  	logger := a.logger.WithFields(logrus.Fields{
  1036  		"name": namespace.GetName(),
  1037  	})
  1038  
  1039  	operatorGroupList, err := a.lister.OperatorsV1().OperatorGroupLister().List(labels.Everything())
  1040  	if err != nil {
  1041  		logger.WithError(err).Warn("lister failed")
  1042  		return err
  1043  	}
  1044  
  1045  	desiredGroupLabels := make(map[string]string)
  1046  	for _, group := range operatorGroupList {
  1047  		namespaceSet := NewNamespaceSet(group.Status.Namespaces)
  1048  
  1049  		// Apply the label if not an All Namespaces OperatorGroup.
  1050  		if namespaceSet.Contains(namespace.GetName()) && !namespaceSet.IsAllNamespaces() {
  1051  			k, v, err := group.OGLabelKeyAndValue()
  1052  			if err != nil {
  1053  				return err
  1054  			}
  1055  			desiredGroupLabels[k] = v
  1056  		}
  1057  	}
  1058  
  1059  	if changed := func() bool {
  1060  		for ke, ve := range namespace.Labels {
  1061  			if !operatorsv1.IsOperatorGroupLabel(ke) {
  1062  				continue
  1063  			}
  1064  			if vd, ok := desiredGroupLabels[ke]; !ok || vd != ve {
  1065  				return true
  1066  			}
  1067  		}
  1068  		for kd, vd := range desiredGroupLabels {
  1069  			if ve, ok := namespace.Labels[kd]; !ok || ve != vd {
  1070  				return true
  1071  			}
  1072  		}
  1073  		return false
  1074  	}(); !changed {
  1075  		return nil
  1076  	}
  1077  
  1078  	namespace = namespace.DeepCopy()
  1079  	for k := range namespace.Labels {
  1080  		if operatorsv1.IsOperatorGroupLabel(k) {
  1081  			delete(namespace.Labels, k)
  1082  		}
  1083  	}
  1084  	if namespace.Labels == nil && len(desiredGroupLabels) > 0 {
  1085  		namespace.Labels = make(map[string]string)
  1086  	}
  1087  	for k, v := range desiredGroupLabels {
  1088  		namespace.Labels[k] = v
  1089  	}
  1090  
  1091  	_, err = a.opClient.KubernetesInterface().CoreV1().Namespaces().Update(context.TODO(), namespace, metav1.UpdateOptions{})
  1092  
  1093  	return err
  1094  }
  1095  
  1096  func (a *Operator) handleClusterServiceVersionDeletion(obj interface{}) {
  1097  	clusterServiceVersion, ok := obj.(*v1alpha1.ClusterServiceVersion)
  1098  	if !ok {
  1099  		tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
  1100  		if !ok {
  1101  			utilruntime.HandleError(fmt.Errorf("couldn't get object from tombstone %#v", obj))
  1102  			return
  1103  		}
  1104  
  1105  		clusterServiceVersion, ok = tombstone.Obj.(*v1alpha1.ClusterServiceVersion)
  1106  		if !ok {
  1107  			utilruntime.HandleError(fmt.Errorf("tombstone contained object that is not a ClusterServiceVersion %#v", obj))
  1108  			return
  1109  		}
  1110  	}
  1111  
  1112  	if a.csvNotification != nil {
  1113  		a.csvNotification.OnDelete(clusterServiceVersion)
  1114  	}
  1115  
  1116  	logger := a.logger.WithFields(logrus.Fields{
  1117  		"id":        queueinformer.NewLoopID(),
  1118  		"csv":       clusterServiceVersion.GetName(),
  1119  		"namespace": clusterServiceVersion.GetNamespace(),
  1120  		"phase":     clusterServiceVersion.Status.Phase,
  1121  	})
  1122  
  1123  	logger.Debug("start deleting CSV")
  1124  	defer logger.Debug("end deleting CSV")
  1125  
  1126  	metrics.DeleteCSVMetric(clusterServiceVersion)
  1127  
  1128  	if clusterServiceVersion.IsCopied() {
  1129  		logger.Warning("deleted csv is copied. skipping additional cleanup steps") // should not happen?
  1130  		return
  1131  	}
  1132  
  1133  	defer func(csv v1alpha1.ClusterServiceVersion) {
  1134  		if clusterServiceVersion.IsCopied() {
  1135  			logger.Debug("deleted csv is copied. skipping operatorgroup requeue")
  1136  			return
  1137  		}
  1138  
  1139  		// Requeue all OperatorGroups in the namespace
  1140  		logger.Debug("requeueing operatorgroups in namespace")
  1141  		operatorGroups, err := a.lister.OperatorsV1().OperatorGroupLister().OperatorGroups(csv.GetNamespace()).List(labels.Everything())
  1142  		if err != nil {
  1143  			logger.WithError(err).Warnf("an error occurred while listing operatorgroups to requeue after csv deletion")
  1144  			return
  1145  		}
  1146  
  1147  		for _, operatorGroup := range operatorGroups {
  1148  			logger := logger.WithField("operatorgroup", operatorGroup.GetName())
  1149  			logger.Debug("requeueing")
  1150  			if err := a.ogQueueSet.Requeue(operatorGroup.GetNamespace(), operatorGroup.GetName()); err != nil {
  1151  				logger.WithError(err).Debug("error requeueing operatorgroup")
  1152  			}
  1153  		}
  1154  	}(*clusterServiceVersion)
  1155  
  1156  	targetNamespaces, ok := clusterServiceVersion.Annotations[operatorsv1.OperatorGroupTargetsAnnotationKey]
  1157  	if !ok {
  1158  		logger.Debug("missing target namespaces annotation on csv")
  1159  		return
  1160  	}
  1161  
  1162  	operatorNamespace, ok := clusterServiceVersion.Annotations[operatorsv1.OperatorGroupNamespaceAnnotationKey]
  1163  	if !ok {
  1164  		logger.Debug("missing operator namespace annotation on csv")
  1165  		return
  1166  	}
  1167  
  1168  	if _, ok = clusterServiceVersion.Annotations[operatorsv1.OperatorGroupAnnotationKey]; !ok {
  1169  		logger.Debug("missing operatorgroup name annotation on csv")
  1170  		return
  1171  	}
  1172  
  1173  	logger.Info("gcing children")
  1174  	namespaces := make([]string, 0)
  1175  	if targetNamespaces == "" {
  1176  		namespaceList, err := a.opClient.KubernetesInterface().CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{})
  1177  		if err != nil {
  1178  			logger.WithError(err).Warn("cannot list all namespaces to requeue child csvs for deletion")
  1179  			return
  1180  		}
  1181  		for _, namespace := range namespaceList.Items {
  1182  			namespaces = append(namespaces, namespace.GetName())
  1183  		}
  1184  	} else {
  1185  		namespaces = strings.Split(targetNamespaces, ",")
  1186  	}
  1187  	for _, namespace := range namespaces {
  1188  		if namespace != operatorNamespace {
  1189  			logger.WithField("targetNamespace", namespace).Debug("requeueing child csv for deletion")
  1190  			if err := a.copiedCSVGCQueueSet.Requeue(namespace, clusterServiceVersion.GetName()); err != nil {
  1191  				logger.WithError(err).Warn("unable to requeue")
  1192  			}
  1193  		}
  1194  	}
  1195  
  1196  	for _, desc := range clusterServiceVersion.Spec.APIServiceDefinitions.Owned {
  1197  		apiServiceName := fmt.Sprintf("%s.%s", desc.Version, desc.Group)
  1198  		fetched, err := a.lister.APIRegistrationV1().APIServiceLister().Get(apiServiceName)
  1199  		if apierrors.IsNotFound(err) {
  1200  			continue
  1201  		}
  1202  		if err != nil {
  1203  			logger.WithError(err).Warn("api service get failure")
  1204  			continue
  1205  		}
  1206  		apiServiceLabels := fetched.GetLabels()
  1207  		if clusterServiceVersion.GetName() == apiServiceLabels[ownerutil.OwnerKey] && clusterServiceVersion.GetNamespace() == apiServiceLabels[ownerutil.OwnerNamespaceKey] {
  1208  			logger.Infof("gcing api service %v", apiServiceName)
  1209  			err := a.opClient.DeleteAPIService(apiServiceName, &metav1.DeleteOptions{})
  1210  			if err != nil {
  1211  				logger.WithError(err).Warn("cannot delete orphaned api service")
  1212  			}
  1213  		}
  1214  	}
  1215  
  1216  	// Conversion webhooks are defined within a CRD.
  1217  	// In an effort to prevent customer dataloss, OLM does not delete CRDs associated with a CSV when it is deleted.
  1218  	// Deleting a CSV that introduced a conversion webhook removes the deployment that serviced the conversion webhook calls.
  1219  	// If a conversion webhook is defined and the service isn't available, all requests against the CR associated with the CRD will fail.
  1220  	// This ultimately breaks kubernetes garbage collection and prevents OLM from reinstalling the CSV as CR validation against the new CRD's
  1221  	// openapiv3 schema fails.
  1222  	// As such, when a CSV is deleted OLM will check if it is being replaced. If the CSV is not being replaced, OLM will remove the conversion
  1223  	// webhook from the CRD definition.
  1224  	csvs, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(clusterServiceVersion.GetNamespace()).List(labels.Everything())
  1225  	if err != nil {
  1226  		logger.Errorf("error listing csvs: %v\n", err)
  1227  	}
  1228  	for _, csv := range csvs {
  1229  		if csv.Spec.Replaces == clusterServiceVersion.GetName() {
  1230  			return
  1231  		}
  1232  	}
  1233  
  1234  	for _, desc := range clusterServiceVersion.Spec.WebhookDefinitions {
  1235  		if desc.Type != v1alpha1.ConversionWebhook || len(desc.ConversionCRDs) == 0 {
  1236  			continue
  1237  		}
  1238  
  1239  		for i, crdName := range desc.ConversionCRDs {
  1240  			crd, err := a.opClient.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), crdName, metav1.GetOptions{})
  1241  			if err != nil {
  1242  				logger.Errorf("error getting CRD %v which was defined in CSVs spec.WebhookDefinition[%d]: %v\n", crdName, i, err)
  1243  				continue
  1244  			}
  1245  
  1246  			copy := crd.DeepCopy()
  1247  			copy.Spec.Conversion.Strategy = apiextensionsv1.NoneConverter
  1248  			copy.Spec.Conversion.Webhook = nil
  1249  
  1250  			if _, err = a.opClient.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Update(context.TODO(), copy, metav1.UpdateOptions{}); err != nil {
  1251  				logger.Errorf("error updating conversion strategy for CRD %v: %v\n", crdName, err)
  1252  			}
  1253  		}
  1254  	}
  1255  }
  1256  
  1257  func (a *Operator) removeDanglingChildCSVs(csv *metav1.PartialObjectMetadata) error {
  1258  	logger := a.logger.WithFields(logrus.Fields{
  1259  		"id":          queueinformer.NewLoopID(),
  1260  		"csv":         csv.GetName(),
  1261  		"namespace":   csv.GetNamespace(),
  1262  		"labels":      csv.GetLabels(),
  1263  		"annotations": csv.GetAnnotations(),
  1264  	})
  1265  
  1266  	if !v1alpha1.IsCopied(csv) {
  1267  		logger.Warning("removeDanglingChild called on a parent. this is a no-op but should be avoided.")
  1268  		return nil
  1269  	}
  1270  
  1271  	operatorNamespace, ok := csv.Annotations[operatorsv1.OperatorGroupNamespaceAnnotationKey]
  1272  	if !ok {
  1273  		logger.Debug("missing operator namespace annotation on copied CSV")
  1274  		return a.deleteChild(csv, logger)
  1275  	}
  1276  
  1277  	logger = logger.WithField("parentNamespace", operatorNamespace)
  1278  	parent, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(operatorNamespace).Get(csv.GetName())
  1279  	if apierrors.IsNotFound(err) || apierrors.IsGone(err) || parent == nil {
  1280  		logger.Debug("deleting copied CSV since parent is missing")
  1281  		return a.deleteChild(csv, logger)
  1282  	}
  1283  
  1284  	if parent.Status.Phase == v1alpha1.CSVPhaseFailed && parent.Status.Reason == v1alpha1.CSVReasonInterOperatorGroupOwnerConflict {
  1285  		logger.Debug("deleting copied CSV since parent has intersecting operatorgroup conflict")
  1286  		return a.deleteChild(csv, logger)
  1287  	}
  1288  
  1289  	if annotations := parent.GetAnnotations(); annotations != nil {
  1290  		if !NewNamespaceSetFromString(annotations[operatorsv1.OperatorGroupTargetsAnnotationKey]).Contains(csv.GetNamespace()) {
  1291  			logger.WithField("parentTargets", annotations[operatorsv1.OperatorGroupTargetsAnnotationKey]).
  1292  				Debug("deleting copied CSV since parent no longer lists this as a target namespace")
  1293  			return a.deleteChild(csv, logger)
  1294  		}
  1295  	}
  1296  
  1297  	if parent.GetNamespace() == csv.GetNamespace() {
  1298  		logger.Debug("deleting copied CSV since it has incorrect parent annotations")
  1299  		return a.deleteChild(csv, logger)
  1300  	}
  1301  
  1302  	return nil
  1303  }
  1304  
  1305  func (a *Operator) deleteChild(csv *metav1.PartialObjectMetadata, logger *logrus.Entry) error {
  1306  	logger.Debug("gcing csv")
  1307  	return a.client.OperatorsV1alpha1().ClusterServiceVersions(csv.GetNamespace()).Delete(context.TODO(), csv.GetName(), metav1.DeleteOptions{})
  1308  }
  1309  
  1310  // Return values, err, ok; ok == true: continue Reconcile, ok == false: exit Reconcile
  1311  func (a *Operator) processFinalizer(csv *v1alpha1.ClusterServiceVersion, log *logrus.Entry) (error, bool) {
  1312  	myFinalizerName := "operators.coreos.com/csv-cleanup"
  1313  
  1314  	if csv.ObjectMeta.DeletionTimestamp.IsZero() {
  1315  		// CSV is not being deleted, add finalizer if not present
  1316  		if !controllerutil.ContainsFinalizer(csv, myFinalizerName) {
  1317  			controllerutil.AddFinalizer(csv, myFinalizerName)
  1318  			_, err := a.client.OperatorsV1alpha1().ClusterServiceVersions(csv.GetNamespace()).Update(a.ctx, csv, metav1.UpdateOptions{})
  1319  			if err != nil {
  1320  				log.WithError(err).Error("Adding finalizer")
  1321  				return err, false
  1322  			}
  1323  		}
  1324  		return nil, true
  1325  	}
  1326  
  1327  	if !controllerutil.ContainsFinalizer(csv, myFinalizerName) {
  1328  		// Finalizer has been removed; stop reconciliation as the CSV is being deleted
  1329  		return nil, false
  1330  	}
  1331  
  1332  	log.Info("started finalizer")
  1333  	defer log.Info("completed finalizer")
  1334  
  1335  	// CSV is being deleted and the finalizer still present; do any clean up
  1336  	ownerSelector := ownerutil.CSVOwnerSelector(csv)
  1337  	listOptions := metav1.ListOptions{
  1338  		LabelSelector: ownerSelector.String(),
  1339  	}
  1340  	deleteOptions := metav1.DeleteOptions{}
  1341  	// Look for resources owned by this CSV, and delete them.
  1342  	log.WithFields(logrus.Fields{"selector": ownerSelector}).Info("Cleaning up resources after CSV deletion")
  1343  	var errs []error
  1344  
  1345  	err := a.opClient.KubernetesInterface().RbacV1().ClusterRoleBindings().DeleteCollection(a.ctx, deleteOptions, listOptions)
  1346  	if client.IgnoreNotFound(err) != nil {
  1347  		log.WithError(err).Error("Deleting ClusterRoleBindings on CSV delete")
  1348  		errs = append(errs, err)
  1349  	}
  1350  
  1351  	err = a.opClient.KubernetesInterface().RbacV1().ClusterRoles().DeleteCollection(a.ctx, deleteOptions, listOptions)
  1352  	if client.IgnoreNotFound(err) != nil {
  1353  		log.WithError(err).Error("Deleting ClusterRoles on CSV delete")
  1354  		errs = append(errs, err)
  1355  	}
  1356  	err = a.opClient.KubernetesInterface().AdmissionregistrationV1().MutatingWebhookConfigurations().DeleteCollection(a.ctx, deleteOptions, listOptions)
  1357  	if client.IgnoreNotFound(err) != nil {
  1358  		log.WithError(err).Error("Deleting MutatingWebhookConfigurations on CSV delete")
  1359  		errs = append(errs, err)
  1360  	}
  1361  
  1362  	err = a.opClient.KubernetesInterface().AdmissionregistrationV1().ValidatingWebhookConfigurations().DeleteCollection(a.ctx, deleteOptions, listOptions)
  1363  	if client.IgnoreNotFound(err) != nil {
  1364  		log.WithError(err).Error("Deleting ValidatingWebhookConfigurations on CSV delete")
  1365  		errs = append(errs, err)
  1366  	}
  1367  
  1368  	// Make sure things are deleted
  1369  	crbList, err := a.lister.RbacV1().ClusterRoleBindingLister().List(ownerSelector)
  1370  	if err != nil {
  1371  		errs = append(errs, err)
  1372  	} else if len(crbList) != 0 {
  1373  		errs = append(errs, fmt.Errorf("waiting for ClusterRoleBindings to delete"))
  1374  	}
  1375  
  1376  	crList, err := a.lister.RbacV1().ClusterRoleLister().List(ownerSelector)
  1377  	if err != nil {
  1378  		errs = append(errs, err)
  1379  	} else if len(crList) != 0 {
  1380  		errs = append(errs, fmt.Errorf("waiting for ClusterRoles to delete"))
  1381  	}
  1382  
  1383  	// Return any errors
  1384  	if err := utilerrors.NewAggregate(errs); err != nil {
  1385  		return err, false
  1386  	}
  1387  
  1388  	// If no errors, remove our finalizer from the CSV and update
  1389  	controllerutil.RemoveFinalizer(csv, myFinalizerName)
  1390  	_, err = a.client.OperatorsV1alpha1().ClusterServiceVersions(csv.GetNamespace()).Update(a.ctx, csv, metav1.UpdateOptions{})
  1391  	if err != nil {
  1392  		log.WithError(err).Error("Removing finalizer")
  1393  		return err, false
  1394  	}
  1395  
  1396  	// Stop reconciliation as the csv is being deleted
  1397  	return nil, false
  1398  }
  1399  
  1400  // syncClusterServiceVersion is the method that gets called when we see a CSV event in the cluster
  1401  func (a *Operator) syncClusterServiceVersion(obj interface{}) (syncError error) {
  1402  	clusterServiceVersion, ok := obj.(*v1alpha1.ClusterServiceVersion)
  1403  	if !ok {
  1404  		a.logger.Debugf("wrong type: %#v", obj)
  1405  		return fmt.Errorf("casting ClusterServiceVersion failed")
  1406  	}
  1407  
  1408  	logger := a.logger.WithFields(logrus.Fields{
  1409  		"id":        queueinformer.NewLoopID(),
  1410  		"csv":       clusterServiceVersion.GetName(),
  1411  		"namespace": clusterServiceVersion.GetNamespace(),
  1412  		"phase":     clusterServiceVersion.Status.Phase,
  1413  	})
  1414  	logger.Debug("start syncing CSV")
  1415  	defer logger.Debug("end syncing CSV")
  1416  
  1417  	// get an up-to-date clusterServiceVersion from the cache
  1418  	clusterServiceVersion, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(clusterServiceVersion.GetNamespace()).Get(clusterServiceVersion.GetName())
  1419  	if apierrors.IsNotFound(err) {
  1420  		logger.Info("CSV has beeen deleted")
  1421  		return nil
  1422  	} else if err != nil {
  1423  		logger.Info("Error getting latest version of CSV")
  1424  		return err
  1425  	}
  1426  
  1427  	if err, ok := a.processFinalizer(clusterServiceVersion, logger); !ok {
  1428  		return err
  1429  	}
  1430  
  1431  	if a.csvNotification != nil {
  1432  		a.csvNotification.OnAddOrUpdate(clusterServiceVersion)
  1433  	}
  1434  
  1435  	if clusterServiceVersion.IsCopied() {
  1436  		logger.Warning("skipping copied csv transition") // should not happen?
  1437  		return
  1438  	}
  1439  
  1440  	outCSV, syncError := a.transitionCSVState(*clusterServiceVersion)
  1441  
  1442  	if outCSV == nil {
  1443  		return
  1444  	}
  1445  
  1446  	// status changed, update CSV
  1447  	if !(outCSV.Status.LastUpdateTime.Equal(clusterServiceVersion.Status.LastUpdateTime) &&
  1448  		outCSV.Status.Phase == clusterServiceVersion.Status.Phase &&
  1449  		outCSV.Status.Reason == clusterServiceVersion.Status.Reason &&
  1450  		outCSV.Status.Message == clusterServiceVersion.Status.Message) {
  1451  		// Update CSV with status of transition. Log errors if we can't write them to the status.
  1452  		_, err := a.client.OperatorsV1alpha1().ClusterServiceVersions(outCSV.GetNamespace()).UpdateStatus(context.TODO(), outCSV, metav1.UpdateOptions{})
  1453  		if err != nil {
  1454  			updateErr := errors.New("error updating ClusterServiceVersion status: " + err.Error())
  1455  			if syncError == nil {
  1456  				logger.Info(updateErr)
  1457  				syncError = updateErr
  1458  			} else {
  1459  				syncError = fmt.Errorf("error transitioning ClusterServiceVersion: %s and error updating CSV status: %s", syncError, updateErr)
  1460  			}
  1461  		} else {
  1462  			metrics.EmitCSVMetric(clusterServiceVersion, outCSV)
  1463  		}
  1464  	}
  1465  
  1466  	operatorGroup := a.operatorGroupFromAnnotations(logger, clusterServiceVersion)
  1467  	if operatorGroup == nil {
  1468  		logger.WithField("reason", "no operatorgroup found for active CSV").Debug("skipping potential RBAC creation in target namespaces")
  1469  		return
  1470  	}
  1471  
  1472  	if len(operatorGroup.Status.Namespaces) == 1 && operatorGroup.Status.Namespaces[0] == operatorGroup.GetNamespace() {
  1473  		logger.Debug("skipping copy for OwnNamespace operatorgroup")
  1474  		return
  1475  	}
  1476  	// Ensure operator has access to targetnamespaces with cluster RBAC
  1477  	// (roles/rolebindings are checked for each target namespace in syncCopyCSV)
  1478  	if err := a.ensureRBACInTargetNamespace(clusterServiceVersion, operatorGroup); err != nil {
  1479  		logger.WithError(err).Info("couldn't ensure RBAC in target namespaces")
  1480  		syncError = err
  1481  	}
  1482  
  1483  	if !outCSV.IsUncopiable() {
  1484  		if err := a.csvCopyQueueSet.Requeue(outCSV.GetNamespace(), outCSV.GetName()); err != nil {
  1485  			logger.WithError(err).Warn("unable to requeue")
  1486  		}
  1487  	}
  1488  
  1489  	logger.Debug("done syncing CSV")
  1490  	return
  1491  }
  1492  
  1493  func (a *Operator) allNamespaceOperatorGroups() ([]*operatorsv1.OperatorGroup, error) {
  1494  	operatorGroups, err := a.lister.OperatorsV1().OperatorGroupLister().List(labels.Everything())
  1495  	if err != nil {
  1496  		return nil, err
  1497  	}
  1498  
  1499  	result := []*operatorsv1.OperatorGroup{}
  1500  	for _, operatorGroup := range operatorGroups {
  1501  		if NewNamespaceSet(operatorGroup.Status.Namespaces).IsAllNamespaces() {
  1502  			result = append(result, operatorGroup.DeepCopy())
  1503  		}
  1504  	}
  1505  	return result, nil
  1506  }
  1507  
  1508  func (a *Operator) syncOLMConfig(obj interface{}) (syncError error) {
  1509  	a.logger.Debug("Processing olmConfig")
  1510  	olmConfig, ok := obj.(*operatorsv1.OLMConfig)
  1511  	if !ok {
  1512  		return fmt.Errorf("casting OLMConfig failed")
  1513  	}
  1514  
  1515  	// Generate an array of allNamespace OperatorGroups
  1516  	allNSOperatorGroups, err := a.allNamespaceOperatorGroups()
  1517  	if err != nil {
  1518  		return err
  1519  	}
  1520  
  1521  	nonCopiedCSVRequirement, err := labels.NewRequirement(v1alpha1.CopiedLabelKey, selection.DoesNotExist, []string{})
  1522  	if err != nil {
  1523  		return err
  1524  	}
  1525  
  1526  	csvIsRequeued := false
  1527  	for _, og := range allNSOperatorGroups {
  1528  		// Get all copied CSVs owned by this operatorGroup
  1529  		copiedCSVRequirement, err := labels.NewRequirement(v1alpha1.CopiedLabelKey, selection.Equals, []string{og.GetNamespace()})
  1530  		if err != nil {
  1531  			return err
  1532  		}
  1533  
  1534  		copiedCSVs, err := a.copiedCSVLister.List(labels.NewSelector().Add(*copiedCSVRequirement))
  1535  		if err != nil {
  1536  			return err
  1537  		}
  1538  
  1539  		// Create a map that points from CSV name to a map of namespaces it is copied to
  1540  		// for quick lookups.
  1541  		copiedCSVNamespaces := map[string]map[string]struct{}{}
  1542  		for _, copiedCSV := range copiedCSVs {
  1543  			if _, ok := copiedCSVNamespaces[copiedCSV.GetName()]; !ok {
  1544  				copiedCSVNamespaces[copiedCSV.GetName()] = map[string]struct{}{}
  1545  			}
  1546  			copiedCSVNamespaces[copiedCSV.GetName()][copiedCSV.GetNamespace()] = struct{}{}
  1547  		}
  1548  
  1549  		csvs, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(og.GetNamespace()).List(labels.NewSelector().Add(*nonCopiedCSVRequirement))
  1550  		if err != nil {
  1551  			return err
  1552  		}
  1553  
  1554  		namespaces, err := a.lister.CoreV1().NamespaceLister().List(labels.Everything())
  1555  		if err != nil {
  1556  			return err
  1557  		}
  1558  
  1559  		copiedCSVEvaluatorFunc := getCopiedCSVEvaluatorFunc(olmConfig.CopiedCSVsAreEnabled(), namespaces, a.protectedCopiedCSVNamespaces)
  1560  
  1561  		for _, csv := range csvs {
  1562  			// Ignore NS where actual CSV is installed
  1563  			if copiedCSVEvaluatorFunc(copiedCSVNamespaces[csv.GetName()]) {
  1564  				continue
  1565  			}
  1566  
  1567  			if err := a.csvQueueSet.Requeue(csv.GetNamespace(), csv.GetName()); err != nil {
  1568  				a.logger.WithError(err).Warn("unable to requeue")
  1569  			}
  1570  			csvIsRequeued = true
  1571  		}
  1572  	}
  1573  
  1574  	// Update the olmConfig status if it has changed.
  1575  	condition := getCopiedCSVsCondition(olmConfig.CopiedCSVsAreEnabled(), csvIsRequeued)
  1576  	if !isStatusConditionPresentAndAreTypeReasonMessageStatusEqual(olmConfig.Status.Conditions, condition) {
  1577  		meta.SetStatusCondition(&olmConfig.Status.Conditions, condition)
  1578  		if _, err := a.client.OperatorsV1().OLMConfigs().UpdateStatus(context.TODO(), olmConfig, metav1.UpdateOptions{}); err != nil {
  1579  			return err
  1580  		}
  1581  	}
  1582  
  1583  	return nil
  1584  }
  1585  
  1586  // getCopiedCSVEvaluatorFunc returns a function that evaluates if the a set of Copied CSVs exist in the expected namespaces.
  1587  func getCopiedCSVEvaluatorFunc(copiedCSVsEnabled bool, namespaces []*corev1.Namespace, protectedCopiedCSVNamespaces map[string]struct{}) func(map[string]struct{}) bool {
  1588  	if copiedCSVsEnabled {
  1589  		// Exclude the namespace hosting the original CSV
  1590  		expectedCopiedCSVCount := -1
  1591  		for _, ns := range namespaces {
  1592  			if ns.Status.Phase == corev1.NamespaceActive {
  1593  				expectedCopiedCSVCount++
  1594  			}
  1595  		}
  1596  		return func(m map[string]struct{}) bool {
  1597  			return expectedCopiedCSVCount == len(m)
  1598  		}
  1599  	}
  1600  
  1601  	// Check that Copied CSVs exist in protected namespaces.
  1602  	return func(m map[string]struct{}) bool {
  1603  		if len(protectedCopiedCSVNamespaces) != len(m) {
  1604  			return false
  1605  		}
  1606  
  1607  		for protectedNS := range protectedCopiedCSVNamespaces {
  1608  			if _, ok := m[protectedNS]; !ok {
  1609  				return false
  1610  			}
  1611  		}
  1612  
  1613  		return true
  1614  	}
  1615  }
  1616  
  1617  func isStatusConditionPresentAndAreTypeReasonMessageStatusEqual(conditions []metav1.Condition, condition metav1.Condition) bool {
  1618  	foundCondition := meta.FindStatusCondition(conditions, condition.Type)
  1619  	if foundCondition == nil {
  1620  		return false
  1621  	}
  1622  	return foundCondition.Type == condition.Type &&
  1623  		foundCondition.Reason == condition.Reason &&
  1624  		foundCondition.Message == condition.Message &&
  1625  		foundCondition.Status == condition.Status
  1626  }
  1627  
  1628  func getCopiedCSVsCondition(enabled, csvIsRequeued bool) metav1.Condition {
  1629  	condition := metav1.Condition{
  1630  		Type:               operatorsv1.DisabledCopiedCSVsConditionType,
  1631  		LastTransitionTime: metav1.Now(),
  1632  		Status:             metav1.ConditionFalse,
  1633  	}
  1634  	if enabled {
  1635  		condition.Reason = "CopiedCSVsEnabled"
  1636  		condition.Message = "Copied CSVs are enabled and present across the cluster"
  1637  		if csvIsRequeued {
  1638  			condition.Message = "Copied CSVs are enabled and at least one copied CSVs is missing"
  1639  		}
  1640  		return condition
  1641  	}
  1642  
  1643  	condition.Reason = "CopiedCSVsDisabled"
  1644  	if csvIsRequeued {
  1645  		condition.Message = "Copied CSVs are disabled and at least one unexpected copied CSV was found for an operator installed in AllNamespace mode"
  1646  		return condition
  1647  	}
  1648  
  1649  	condition.Status = metav1.ConditionTrue
  1650  	condition.Message = "Copied CSVs are disabled and no unexpected copied CSVs were found for operators installed in AllNamespace mode"
  1651  
  1652  	return condition
  1653  }
  1654  
  1655  func (a *Operator) syncCopyCSV(obj interface{}) (syncError error) {
  1656  	clusterServiceVersion, ok := obj.(*v1alpha1.ClusterServiceVersion)
  1657  	if !ok {
  1658  		a.logger.Debugf("wrong type: %#v", obj)
  1659  		return fmt.Errorf("casting ClusterServiceVersion failed")
  1660  	}
  1661  
  1662  	olmConfig, err := a.client.OperatorsV1().OLMConfigs().Get(context.TODO(), "cluster", metav1.GetOptions{})
  1663  	if err != nil && !apierrors.IsNotFound(err) {
  1664  		return err
  1665  	}
  1666  
  1667  	if err == nil {
  1668  		go a.olmConfigQueue.AddAfter(olmConfig, time.Second*5)
  1669  	}
  1670  
  1671  	logger := a.logger.WithFields(logrus.Fields{
  1672  		"id":        queueinformer.NewLoopID(),
  1673  		"csv":       clusterServiceVersion.GetName(),
  1674  		"namespace": clusterServiceVersion.GetNamespace(),
  1675  		"phase":     clusterServiceVersion.Status.Phase,
  1676  	})
  1677  
  1678  	logger.Debug("copying CSV")
  1679  
  1680  	operatorGroup := a.operatorGroupFromAnnotations(logger, clusterServiceVersion)
  1681  	if operatorGroup == nil {
  1682  		// since syncClusterServiceVersion is the only enqueuer, annotations should be present
  1683  		logger.WithField("reason", "no operatorgroup found for active CSV").Error("operatorgroup should have annotations")
  1684  		syncError = fmt.Errorf("operatorGroup for csv '%v' should have annotations", clusterServiceVersion.GetName())
  1685  		return
  1686  	}
  1687  
  1688  	logger.WithFields(logrus.Fields{
  1689  		"targetNamespaces": strings.Join(operatorGroup.Status.Namespaces, ","),
  1690  	}).Debug("copying csv to targets")
  1691  
  1692  	copiedCSVsAreEnabled, err := a.copiedCSVsAreEnabled()
  1693  	if err != nil {
  1694  		return err
  1695  	}
  1696  
  1697  	// Check if we need to do any copying / annotation for the operatorgroup
  1698  	namespaceSet := NewNamespaceSet(operatorGroup.Status.Namespaces)
  1699  	if copiedCSVsAreEnabled || !namespaceSet.IsAllNamespaces() {
  1700  		if err := a.ensureCSVsInNamespaces(clusterServiceVersion, operatorGroup, namespaceSet); err != nil {
  1701  			logger.WithError(err).Info("couldn't copy CSV to target namespaces")
  1702  			syncError = err
  1703  		}
  1704  
  1705  		// If the CSV was installed in AllNamespace mode, remove any "CSV Copying Disabled" events
  1706  		// in which the related object's name, namespace, and uid match the given CSV's.
  1707  		if namespaceSet.IsAllNamespaces() {
  1708  			if err := a.deleteCSVCopyingDisabledEvent(clusterServiceVersion); err != nil {
  1709  				return err
  1710  			}
  1711  		}
  1712  		return
  1713  	}
  1714  
  1715  	requirement, err := labels.NewRequirement(v1alpha1.CopiedLabelKey, selection.Equals, []string{clusterServiceVersion.Namespace})
  1716  	if err != nil {
  1717  		return err
  1718  	}
  1719  
  1720  	copiedCSVs, err := a.copiedCSVLister.List(labels.NewSelector().Add(*requirement))
  1721  	if err != nil {
  1722  		return err
  1723  	}
  1724  
  1725  	// Ensure that the Copied CSVs exist in the protected namespaces.
  1726  	protectedNamespaces := []string{}
  1727  	for ns := range a.protectedCopiedCSVNamespaces {
  1728  		if ns == clusterServiceVersion.GetNamespace() {
  1729  			continue
  1730  		}
  1731  		protectedNamespaces = append(protectedNamespaces, ns)
  1732  	}
  1733  
  1734  	if err := a.ensureCSVsInNamespaces(clusterServiceVersion, operatorGroup, NewNamespaceSet(protectedNamespaces)); err != nil {
  1735  		return err
  1736  	}
  1737  
  1738  	// Delete Copied CSVs in namespaces that are not protected.
  1739  	for _, copiedCSV := range copiedCSVs {
  1740  		if _, ok := a.protectedCopiedCSVNamespaces[copiedCSV.Namespace]; ok {
  1741  			continue
  1742  		}
  1743  		err := a.client.OperatorsV1alpha1().ClusterServiceVersions(copiedCSV.Namespace).Delete(context.TODO(), copiedCSV.Name, metav1.DeleteOptions{})
  1744  		if err != nil && !apierrors.IsNotFound(err) {
  1745  			return err
  1746  		}
  1747  	}
  1748  
  1749  	if err := a.createCSVCopyingDisabledEvent(clusterServiceVersion); err != nil {
  1750  		return err
  1751  	}
  1752  
  1753  	return
  1754  }
  1755  
  1756  // copiedCSVsAreEnabled determines if csv copying is enabled for OLM.
  1757  //
  1758  // This method will first attempt to get the "cluster" olmConfig resource,
  1759  // if any error other than "IsNotFound" is encountered, false and the error
  1760  // will be returned.
  1761  //
  1762  // If the "cluster" olmConfig resource is found, the value of
  1763  // olmConfig.spec.features.disableCopiedCSVs will be returned along with a
  1764  // nil error.
  1765  //
  1766  // If the "cluster" olmConfig resource is not found, true will be returned
  1767  // without an error.
  1768  func (a *Operator) copiedCSVsAreEnabled() (bool, error) {
  1769  	olmConfig, err := a.client.OperatorsV1().OLMConfigs().Get(context.TODO(), "cluster", metav1.GetOptions{})
  1770  	if err != nil {
  1771  		// Default to true if olmConfig singleton cannot be found
  1772  		if apierrors.IsNotFound(err) {
  1773  			return true, nil
  1774  		}
  1775  		// If there was an error that wasn't an IsNotFound, return the error
  1776  		return false, err
  1777  	}
  1778  
  1779  	// If there was no error, return value based on olmConfig singleton
  1780  	return olmConfig.CopiedCSVsAreEnabled(), nil
  1781  }
  1782  
  1783  func (a *Operator) getCopiedCSVDisabledEventsForCSV(csv *v1alpha1.ClusterServiceVersion) ([]corev1.Event, error) {
  1784  	result := []corev1.Event{}
  1785  	if csv == nil {
  1786  		return result, nil
  1787  	}
  1788  
  1789  	events, err := a.opClient.KubernetesInterface().CoreV1().Events(csv.GetNamespace()).List(context.TODO(), metav1.ListOptions{})
  1790  	if err != nil {
  1791  		return nil, err
  1792  	}
  1793  
  1794  	for _, event := range events.Items {
  1795  		if event.InvolvedObject.Namespace == csv.GetNamespace() &&
  1796  			event.InvolvedObject.Name == csv.GetName() &&
  1797  			event.InvolvedObject.UID == csv.GetUID() &&
  1798  			event.Reason == operatorsv1.DisabledCopiedCSVsConditionType {
  1799  			result = append(result, *event.DeepCopy())
  1800  		}
  1801  	}
  1802  
  1803  	return result, nil
  1804  }
  1805  
  1806  func (a *Operator) deleteCSVCopyingDisabledEvent(csv *v1alpha1.ClusterServiceVersion) error {
  1807  	events, err := a.getCopiedCSVDisabledEventsForCSV(csv)
  1808  	if err != nil {
  1809  		return err
  1810  	}
  1811  
  1812  	// Remove existing events.
  1813  	return a.deleteEvents(events)
  1814  }
  1815  
  1816  func (a *Operator) deleteEvents(events []corev1.Event) error {
  1817  	for _, event := range events {
  1818  		err := a.opClient.KubernetesInterface().EventsV1().Events(event.GetNamespace()).Delete(context.TODO(), event.GetName(), metav1.DeleteOptions{})
  1819  		if err != nil && !apierrors.IsNotFound(err) {
  1820  			return err
  1821  		}
  1822  	}
  1823  	return nil
  1824  }
  1825  
  1826  func (a *Operator) createCSVCopyingDisabledEvent(csv *v1alpha1.ClusterServiceVersion) error {
  1827  	events, err := a.getCopiedCSVDisabledEventsForCSV(csv)
  1828  	if err != nil {
  1829  		return err
  1830  	}
  1831  
  1832  	if len(events) == 1 {
  1833  		return nil
  1834  	}
  1835  
  1836  	// Remove existing events.
  1837  	if len(events) > 1 {
  1838  		if err := a.deleteEvents(events); err != nil {
  1839  			return err
  1840  		}
  1841  	}
  1842  
  1843  	a.recorder.Eventf(csv, corev1.EventTypeWarning, operatorsv1.DisabledCopiedCSVsConditionType, "CSV copying disabled for %s/%s", csv.GetNamespace(), csv.GetName())
  1844  
  1845  	return nil
  1846  }
  1847  
  1848  func (a *Operator) syncGcCsv(obj interface{}) (syncError error) {
  1849  	clusterServiceVersion, ok := obj.(*metav1.PartialObjectMetadata)
  1850  	if !ok {
  1851  		a.logger.Debugf("wrong type: %#v", obj)
  1852  		return fmt.Errorf("casting ClusterServiceVersion failed")
  1853  	}
  1854  	if v1alpha1.IsCopied(clusterServiceVersion) {
  1855  		syncError = a.removeDanglingChildCSVs(clusterServiceVersion)
  1856  		return
  1857  	}
  1858  	return
  1859  }
  1860  
  1861  // operatorGroupFromAnnotations returns the OperatorGroup for the CSV only if the CSV is active one in the group
  1862  func (a *Operator) operatorGroupFromAnnotations(logger *logrus.Entry, csv *v1alpha1.ClusterServiceVersion) *operatorsv1.OperatorGroup {
  1863  	annotations := csv.GetAnnotations()
  1864  
  1865  	// Not part of a group yet
  1866  	if annotations == nil {
  1867  		logger.Info("not part of any operatorgroup, no annotations")
  1868  		return nil
  1869  	}
  1870  
  1871  	// Not in the OperatorGroup namespace
  1872  	if annotations[operatorsv1.OperatorGroupNamespaceAnnotationKey] != csv.GetNamespace() {
  1873  		logger.Info("not in operatorgroup namespace")
  1874  		return nil
  1875  	}
  1876  
  1877  	operatorGroupName, ok := annotations[operatorsv1.OperatorGroupAnnotationKey]
  1878  
  1879  	// No OperatorGroup annotation
  1880  	if !ok {
  1881  		logger.Info("no olm.operatorGroup annotation")
  1882  		return nil
  1883  	}
  1884  
  1885  	logger = logger.WithField("operatorgroup", operatorGroupName)
  1886  
  1887  	operatorGroup, err := a.lister.OperatorsV1().OperatorGroupLister().OperatorGroups(csv.GetNamespace()).Get(operatorGroupName)
  1888  	// OperatorGroup not found
  1889  	if err != nil {
  1890  		logger.Info("operatorgroup not found")
  1891  		return nil
  1892  	}
  1893  
  1894  	targets, ok := annotations[operatorsv1.OperatorGroupTargetsAnnotationKey]
  1895  
  1896  	// No target annotation
  1897  	if !ok {
  1898  		logger.Info("no olm.targetNamespaces annotation")
  1899  		return nil
  1900  	}
  1901  
  1902  	// Target namespaces don't match
  1903  	if targets != operatorGroup.BuildTargetNamespaces() {
  1904  		logger.Info("olm.targetNamespaces annotation doesn't match operatorgroup status")
  1905  		return nil
  1906  	}
  1907  
  1908  	return operatorGroup.DeepCopy()
  1909  }
  1910  
  1911  func (a *Operator) operatorGroupForCSV(csv *v1alpha1.ClusterServiceVersion, logger *logrus.Entry) (*operatorsv1.OperatorGroup, error) {
  1912  	now := a.now()
  1913  
  1914  	// Attempt to associate an OperatorGroup with the CSV.
  1915  	operatorGroups, err := a.lister.OperatorsV1().OperatorGroupLister().OperatorGroups(csv.GetNamespace()).List(labels.Everything())
  1916  	if err != nil {
  1917  		logger.Errorf("error occurred while attempting to associate csv with operatorgroup")
  1918  		return nil, err
  1919  	}
  1920  	var operatorGroup *operatorsv1.OperatorGroup
  1921  
  1922  	switch len(operatorGroups) {
  1923  	case 0:
  1924  		err = fmt.Errorf("csv in namespace with no operatorgroups")
  1925  		logger.Warn(err)
  1926  		csv.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonNoOperatorGroup, err.Error(), now, a.recorder)
  1927  		return nil, err
  1928  	case 1:
  1929  		operatorGroup = operatorGroups[0]
  1930  		logger = logger.WithField("opgroup", operatorGroup.GetName())
  1931  		if a.operatorGroupAnnotationsDiffer(&csv.ObjectMeta, operatorGroup) {
  1932  			a.setOperatorGroupAnnotations(&csv.ObjectMeta, operatorGroup, true)
  1933  			if _, err := a.client.OperatorsV1alpha1().ClusterServiceVersions(csv.GetNamespace()).Update(context.TODO(), csv, metav1.UpdateOptions{}); err != nil {
  1934  				logger.WithError(err).Warn("error adding operatorgroup annotations")
  1935  				return nil, err
  1936  			}
  1937  			if targetNamespaceList, err := a.getOperatorGroupTargets(operatorGroup); err == nil && len(targetNamespaceList) == 0 {
  1938  				csv.SetPhaseWithEventIfChanged(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonNoTargetNamespaces, "no targetNamespaces are matched operatorgroups namespace selection", now, a.recorder)
  1939  			}
  1940  			logger.Debug("CSV not in operatorgroup, requeuing operator group")
  1941  			// this requeue helps when an operator group has not annotated a CSV due to a permissions error
  1942  			// but the permissions issue has now been resolved
  1943  			if err := a.ogQueueSet.Requeue(operatorGroup.GetNamespace(), operatorGroup.GetName()); err != nil {
  1944  				return nil, err
  1945  			}
  1946  			return nil, nil
  1947  		}
  1948  		logger.Debug("csv in operatorgroup")
  1949  		return operatorGroup.DeepCopy(), nil
  1950  	default:
  1951  		err = fmt.Errorf("csv created in namespace with multiple operatorgroups, can't pick one automatically")
  1952  		logger.WithError(err).Warn("csv failed to become an operatorgroup member")
  1953  		if csv.Status.Reason != v1alpha1.CSVReasonTooManyOperatorGroups {
  1954  			csv.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonTooManyOperatorGroups, err.Error(), now, a.recorder)
  1955  		}
  1956  		return nil, err
  1957  	}
  1958  }
  1959  
  1960  // transitionCSVState moves the CSV status state machine along based on the current value and the current cluster state.
  1961  // SyncError should be returned when an additional reconcile of the CSV might fix the issue.
  1962  func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v1alpha1.ClusterServiceVersion, syncError error) {
  1963  	logger := a.logger.WithFields(logrus.Fields{
  1964  		"id":        queueinformer.NewLoopID(),
  1965  		"csv":       in.GetName(),
  1966  		"namespace": in.GetNamespace(),
  1967  		"phase":     in.Status.Phase,
  1968  	})
  1969  
  1970  	if in.Status.Reason == v1alpha1.CSVReasonComponentFailedNoRetry {
  1971  		// will change phase out of failed in the event of an intentional requeue
  1972  		logger.Debugf("skipping sync for CSV in failed-no-retry state")
  1973  		return
  1974  	}
  1975  
  1976  	out = in.DeepCopy()
  1977  	now := a.now()
  1978  
  1979  	operatorSurface, err := apiSurfaceOfCSV(out)
  1980  	if err != nil {
  1981  		// If the resolver is unable to retrieve the operator info from the CSV the CSV requires changes, a syncError should not be returned.
  1982  		logger.WithError(err).Warn("Unable to retrieve operator information from CSV")
  1983  		return
  1984  	}
  1985  
  1986  	// Ensure required and provided API labels
  1987  	if labelSets, err := a.apiLabeler.LabelSetsFor(operatorSurface); err != nil {
  1988  		logger.WithError(err).Warn("couldn't create label set")
  1989  	} else if len(labelSets) > 0 {
  1990  		updated, err := a.ensureLabels(out, labelSets...)
  1991  		if err != nil {
  1992  			logger.WithError(err).Warn("issue ensuring csv api labels")
  1993  			syncError = err
  1994  			return
  1995  		}
  1996  		// Update the underlying value of out to preserve changes
  1997  		*out = *updated
  1998  	}
  1999  
  2000  	// Verify CSV operatorgroup (and update annotations if needed)
  2001  	operatorGroup, err := a.operatorGroupForCSV(out, logger)
  2002  	if operatorGroup == nil {
  2003  		// when err is nil, we still want to exit, but we don't want to re-add the csv ratelimited to the queue
  2004  		syncError = err
  2005  		logger.WithError(err).Info("operatorgroup incorrect")
  2006  		return
  2007  	}
  2008  
  2009  	modeSet, err := v1alpha1.NewInstallModeSet(out.Spec.InstallModes)
  2010  	if err != nil {
  2011  		logger.WithError(err).Warn("csv has invalid installmodes")
  2012  		out.SetPhaseWithEventIfChanged(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonInvalidInstallModes, err.Error(), now, a.recorder)
  2013  		return
  2014  	}
  2015  
  2016  	// Check if the CSV supports its operatorgroup's selected namespaces
  2017  	targets, ok := out.GetAnnotations()[operatorsv1.OperatorGroupTargetsAnnotationKey]
  2018  	if ok {
  2019  		namespaces := strings.Split(targets, ",")
  2020  
  2021  		if err := modeSet.Supports(out.GetNamespace(), namespaces); err != nil {
  2022  			logger.WithField("reason", err.Error()).Info("installmodeset does not support operatorgroups namespace selection")
  2023  			out.SetPhaseWithEventIfChanged(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonUnsupportedOperatorGroup, err.Error(), now, a.recorder)
  2024  			return
  2025  		}
  2026  	} else {
  2027  		logger.Info("csv missing olm.targetNamespaces annotation")
  2028  		out.SetPhaseWithEventIfChanged(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonNoTargetNamespaces, "csv missing olm.targetNamespaces annotation", now, a.recorder)
  2029  		return
  2030  	}
  2031  
  2032  	// Check for intersecting provided APIs in intersecting OperatorGroups
  2033  	allGroups, err := a.lister.OperatorsV1().OperatorGroupLister().List(labels.Everything())
  2034  	if err != nil {
  2035  		logger.WithError(err).Warn("failed to list operatorgroups")
  2036  		return
  2037  	}
  2038  	otherGroups := make([]operatorsv1.OperatorGroup, 0, len(allGroups))
  2039  	for _, g := range allGroups {
  2040  		if g.GetName() != operatorGroup.GetName() || g.GetNamespace() != operatorGroup.GetNamespace() {
  2041  			otherGroups = append(otherGroups, *g)
  2042  		}
  2043  	}
  2044  
  2045  	groupSurface := NewOperatorGroup(operatorGroup)
  2046  	otherGroupSurfaces := NewOperatorGroupSurfaces(otherGroups...)
  2047  	providedAPIs := operatorSurface.ProvidedAPIs.StripPlural()
  2048  
  2049  	switch result := a.apiReconciler.Reconcile(providedAPIs, groupSurface, otherGroupSurfaces...); {
  2050  	case operatorGroup.Spec.StaticProvidedAPIs && (result == AddAPIs || result == RemoveAPIs):
  2051  		// Transition the CSV to FAILED with status reason "CannotModifyStaticOperatorGroupProvidedAPIs"
  2052  		if out.Status.Reason != v1alpha1.CSVReasonInterOperatorGroupOwnerConflict {
  2053  			logger.WithField("apis", providedAPIs).Warn("cannot modify provided apis of static provided api operatorgroup")
  2054  			out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonCannotModifyStaticOperatorGroupProvidedAPIs, "static provided api operatorgroup cannot be modified by these apis", now, a.recorder)
  2055  			a.cleanupCSVDeployments(logger, out)
  2056  		}
  2057  		return
  2058  	case result == APIConflict:
  2059  		// Transition the CSV to FAILED with status reason "InterOperatorGroupOwnerConflict"
  2060  		if out.Status.Reason != v1alpha1.CSVReasonInterOperatorGroupOwnerConflict {
  2061  			logger.WithField("apis", providedAPIs).Warn("intersecting operatorgroups provide the same apis")
  2062  			out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonInterOperatorGroupOwnerConflict, "intersecting operatorgroups provide the same apis", now, a.recorder)
  2063  			a.cleanupCSVDeployments(logger, out)
  2064  		}
  2065  		return
  2066  	case result == AddAPIs:
  2067  		// Add the CSV's provided APIs to its OperatorGroup's annotation
  2068  		logger.WithField("apis", providedAPIs).Debug("adding csv provided apis to operatorgroup")
  2069  		union := groupSurface.ProvidedAPIs().Union(providedAPIs)
  2070  		unionedAnnotations := operatorGroup.GetAnnotations()
  2071  		if unionedAnnotations == nil {
  2072  			unionedAnnotations = make(map[string]string)
  2073  		}
  2074  		if unionedAnnotations[operatorsv1.OperatorGroupProvidedAPIsAnnotationKey] == union.String() {
  2075  			// resolver may think apis need adding with invalid input, so continue when there's no work
  2076  			// to be done so that the CSV can progress far enough to get requirements checked
  2077  			a.logger.Debug("operator group annotations up to date, continuing")
  2078  			break
  2079  		}
  2080  		unionedAnnotations[operatorsv1.OperatorGroupProvidedAPIsAnnotationKey] = union.String()
  2081  		operatorGroup.SetAnnotations(unionedAnnotations)
  2082  		if _, err := a.client.OperatorsV1().OperatorGroups(operatorGroup.GetNamespace()).Update(context.TODO(), operatorGroup, metav1.UpdateOptions{}); err != nil && !apierrors.IsNotFound(err) {
  2083  			syncError = fmt.Errorf("could not update operatorgroups %s annotation: %v", operatorsv1.OperatorGroupProvidedAPIsAnnotationKey, err)
  2084  		}
  2085  		if err := a.csvQueueSet.Requeue(out.GetNamespace(), out.GetName()); err != nil {
  2086  			a.logger.WithError(err).Warn("unable to requeue")
  2087  		}
  2088  		return
  2089  	case result == RemoveAPIs:
  2090  		// Remove the CSV's provided APIs from its OperatorGroup's annotation
  2091  		logger.WithField("apis", providedAPIs).Debug("removing csv provided apis from operatorgroup")
  2092  		difference := groupSurface.ProvidedAPIs().Difference(providedAPIs)
  2093  		if diffedAnnotations := operatorGroup.GetAnnotations(); diffedAnnotations != nil {
  2094  			diffedAnnotations[operatorsv1.OperatorGroupProvidedAPIsAnnotationKey] = difference.String()
  2095  			operatorGroup.SetAnnotations(diffedAnnotations)
  2096  			if _, err := a.client.OperatorsV1().OperatorGroups(operatorGroup.GetNamespace()).Update(context.TODO(), operatorGroup, metav1.UpdateOptions{}); err != nil && !apierrors.IsNotFound(err) {
  2097  				syncError = fmt.Errorf("could not update operatorgroups %s annotation: %v", operatorsv1.OperatorGroupProvidedAPIsAnnotationKey, err)
  2098  			}
  2099  		}
  2100  		if err := a.csvQueueSet.Requeue(out.GetNamespace(), out.GetName()); err != nil {
  2101  			a.logger.WithError(err).Warn("unable to requeue")
  2102  		}
  2103  		return
  2104  	default:
  2105  		logger.WithField("apis", providedAPIs).Debug("no intersecting operatorgroups provide the same apis")
  2106  	}
  2107  
  2108  	switch out.Status.Phase {
  2109  	case v1alpha1.CSVPhaseNone:
  2110  		logger.Info("scheduling ClusterServiceVersion for requirement verification")
  2111  		out.SetPhaseWithEvent(v1alpha1.CSVPhasePending, v1alpha1.CSVReasonRequirementsUnknown, "requirements not yet checked", now, a.recorder)
  2112  	case v1alpha1.CSVPhasePending:
  2113  		// Check previous version's Upgradeable condition
  2114  		replacedCSV := a.isReplacing(out)
  2115  		if replacedCSV != nil {
  2116  			operatorUpgradeable, condErr := a.isOperatorUpgradeable(replacedCSV)
  2117  			if !operatorUpgradeable {
  2118  				out.SetPhaseWithEventIfChanged(v1alpha1.CSVPhasePending, v1alpha1.CSVReasonOperatorConditionNotUpgradeable, fmt.Sprintf("operator is not upgradeable: %s", condErr), now, a.recorder)
  2119  				return
  2120  			}
  2121  		}
  2122  		met, statuses, err := a.requirementAndPermissionStatus(out)
  2123  		if err != nil {
  2124  			// TODO: account for Bad Rule as well
  2125  			logger.Info("invalid install strategy")
  2126  			out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonInvalidStrategy, fmt.Sprintf("install strategy invalid: %s", err.Error()), now, a.recorder)
  2127  			return
  2128  		}
  2129  		out.SetRequirementStatus(statuses)
  2130  
  2131  		// Check if we need to requeue the previous
  2132  		if prev := a.isReplacing(out); prev != nil {
  2133  			if prev.Status.Phase == v1alpha1.CSVPhaseSucceeded {
  2134  				if err := a.csvQueueSet.Requeue(prev.GetNamespace(), prev.GetName()); err != nil {
  2135  					a.logger.WithError(err).Warn("error requeueing previous")
  2136  				}
  2137  			}
  2138  		}
  2139  
  2140  		if !met {
  2141  			logger.Info("requirements were not met")
  2142  			out.SetPhaseWithEventIfChanged(v1alpha1.CSVPhasePending, v1alpha1.CSVReasonRequirementsNotMet, "one or more requirements couldn't be found", now, a.recorder)
  2143  			syncError = ErrRequirementsNotMet
  2144  			return
  2145  		}
  2146  
  2147  		// Create a map to track unique names
  2148  		webhookNames := map[string]struct{}{}
  2149  		// Check if Webhooks have valid rules and unique names
  2150  		// TODO: Move this to validating library
  2151  		for _, desc := range out.Spec.WebhookDefinitions {
  2152  			_, present := webhookNames[desc.GenerateName]
  2153  			if present {
  2154  				logger.WithError(fmt.Errorf("repeated WebhookDescription name %s", desc.GenerateName)).Warn("CSV is invalid")
  2155  				out.SetPhaseWithEventIfChanged(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonInvalidWebhookDescription, "CSV contains repeated WebhookDescription name", now, a.recorder)
  2156  				return
  2157  			}
  2158  			webhookNames[desc.GenerateName] = struct{}{}
  2159  			if err = install.ValidWebhookRules(desc.Rules); err != nil {
  2160  				logger.WithError(err).Warnf("WebhookDescription %s includes invalid rules", desc.GenerateName)
  2161  				out.SetPhaseWithEventIfChanged(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonInvalidWebhookDescription, err.Error(), now, a.recorder)
  2162  				return
  2163  			}
  2164  		}
  2165  
  2166  		// Check for CRD ownership conflicts
  2167  		if syncError = a.crdOwnerConflicts(out, a.csvSet(out.GetNamespace(), v1alpha1.CSVPhaseAny)); syncError != nil {
  2168  			if syncError == ErrCRDOwnerConflict {
  2169  				out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonOwnerConflict, syncError.Error(), now, a.recorder)
  2170  			}
  2171  			return
  2172  		}
  2173  
  2174  		// Check for APIServices ownership conflicts
  2175  		if syncError = a.apiServiceOwnerConflicts(out); syncError != nil {
  2176  			if syncError == ErrAPIServiceOwnerConflict {
  2177  				out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonOwnerConflict, syncError.Error(), now, a.recorder)
  2178  			}
  2179  			return
  2180  		}
  2181  
  2182  		// Check if we're not ready to install part of the replacement chain yet
  2183  		if prev := a.isReplacing(out); prev != nil {
  2184  			if prev.Status.Phase != v1alpha1.CSVPhaseReplacing {
  2185  				logger.WithError(fmt.Errorf("CSV being replaced is in phase %s instead of %s", prev.Status.Phase, v1alpha1.CSVPhaseReplacing)).Warn("Unable to replace previous CSV")
  2186  				return
  2187  			}
  2188  		}
  2189  
  2190  		logger.Info("scheduling ClusterServiceVersion for install")
  2191  		out.SetPhaseWithEvent(v1alpha1.CSVPhaseInstallReady, v1alpha1.CSVReasonRequirementsMet, "all requirements found, attempting install", now, a.recorder)
  2192  	case v1alpha1.CSVPhaseInstallReady:
  2193  		installer, strategy := a.parseStrategiesAndUpdateStatus(out)
  2194  		if strategy == nil {
  2195  			return
  2196  		}
  2197  
  2198  		if syncError = installer.Install(strategy); syncError != nil {
  2199  			if install.IsErrorUnrecoverable(syncError) {
  2200  				logger.Infof("Setting CSV reason to failed without retry: %v", syncError)
  2201  				out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonComponentFailedNoRetry, fmt.Sprintf("install strategy failed: %s", syncError), now, a.recorder)
  2202  				return
  2203  			}
  2204  			out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonComponentFailed, fmt.Sprintf("install strategy failed: %s", syncError), now, a.recorder)
  2205  			return
  2206  		}
  2207  
  2208  		if installer.CertsRotated() {
  2209  			now := metav1.Now()
  2210  			rotateTime := metav1.NewTime(installer.CertsRotateAt())
  2211  			out.Status.CertsLastUpdated = &now
  2212  			out.Status.CertsRotateAt = &rotateTime
  2213  		}
  2214  
  2215  		out.SetPhaseWithEvent(v1alpha1.CSVPhaseInstalling, v1alpha1.CSVReasonInstallSuccessful, "waiting for install components to report healthy", now, a.recorder)
  2216  		err := a.csvQueueSet.Requeue(out.GetNamespace(), out.GetName())
  2217  		if err != nil {
  2218  			a.logger.Warn(err.Error())
  2219  		}
  2220  		return
  2221  
  2222  	case v1alpha1.CSVPhaseInstalling:
  2223  		installer, strategy := a.parseStrategiesAndUpdateStatus(out)
  2224  		if strategy == nil {
  2225  			return
  2226  		}
  2227  
  2228  		strategy, err := a.updateDeploymentSpecsWithAPIServiceData(out, strategy)
  2229  		if err != nil {
  2230  			logger.WithError(err).Debug("Unable to calculate expected deployment")
  2231  			out.SetPhaseWithEvent(v1alpha1.CSVPhasePending, v1alpha1.CSVReasonNeedsReinstall, "calculated deployment install is bad", now, a.recorder)
  2232  			return
  2233  		}
  2234  		if installErr := a.updateInstallStatus(out, installer, strategy, v1alpha1.CSVPhaseInstalling, v1alpha1.CSVReasonWaiting); installErr != nil {
  2235  			// Re-sync if kube-apiserver was unavailable
  2236  			if apierrors.IsServiceUnavailable(installErr) {
  2237  				logger.WithError(installErr).Info("could not update install status")
  2238  				syncError = installErr
  2239  				return
  2240  			}
  2241  			// Set phase to failed if it's been a long time since the last transition (5 minutes)
  2242  			if out.Status.LastTransitionTime != nil && a.now().Sub(out.Status.LastTransitionTime.Time) >= 5*time.Minute {
  2243  				logger.Warn("install timed out")
  2244  				out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonInstallCheckFailed, "install timeout", now, a.recorder)
  2245  				return
  2246  			}
  2247  		}
  2248  		logger.WithField("strategy", out.Spec.InstallStrategy.StrategyName).Infof("install strategy successful")
  2249  
  2250  	case v1alpha1.CSVPhaseSucceeded:
  2251  		// Check if the current CSV is being replaced, return with replacing status if so
  2252  		if err := a.checkReplacementsAndUpdateStatus(out); err != nil {
  2253  			logger.WithError(err).Info("replacement check")
  2254  			return
  2255  		}
  2256  
  2257  		installer, strategy := a.parseStrategiesAndUpdateStatus(out)
  2258  		if strategy == nil {
  2259  			return
  2260  		}
  2261  
  2262  		// Check if any generated resources are missing
  2263  		if err := a.checkAPIServiceResources(out, certs.PEMSHA256); err != nil {
  2264  			logger.WithError(err).Debug("API Resources are unavailable")
  2265  			out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonAPIServiceResourceIssue, err.Error(), now, a.recorder)
  2266  			return
  2267  		}
  2268  
  2269  		// Check if it's time to refresh owned APIService certs
  2270  		if shouldRotate, err := installer.ShouldRotateCerts(strategy); err != nil {
  2271  			logger.WithError(err).Info("cert validity check")
  2272  			return
  2273  		} else if shouldRotate {
  2274  			logger.Debug("CSV owns resources that require a cert refresh")
  2275  			out.SetPhaseWithEvent(v1alpha1.CSVPhasePending, v1alpha1.CSVReasonNeedsCertRotation, "CSV owns resources that require a cert refresh", now, a.recorder)
  2276  			return
  2277  		}
  2278  
  2279  		// Ensure requirements are still present
  2280  		met, statuses, err := a.requirementAndPermissionStatus(out)
  2281  		if err != nil {
  2282  			logger.Info("invalid install strategy")
  2283  			out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonInvalidStrategy, fmt.Sprintf("install strategy invalid: %s", err.Error()), now, a.recorder)
  2284  			return
  2285  		} else if !met {
  2286  			logger.Debug("CSV Requirements are no longer met")
  2287  			out.SetRequirementStatus(statuses)
  2288  			out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonRequirementsNotMet, "requirements no longer met", now, a.recorder)
  2289  			return
  2290  		}
  2291  
  2292  		// Check install status
  2293  		strategy, err = a.updateDeploymentSpecsWithAPIServiceData(out, strategy)
  2294  		if err != nil {
  2295  			logger.WithError(err).Debug("Unable to calculate expected deployment")
  2296  			out.SetPhaseWithEvent(v1alpha1.CSVPhasePending, v1alpha1.CSVReasonNeedsReinstall, "calculated deployment install is bad", now, a.recorder)
  2297  			return
  2298  		}
  2299  		if installErr := a.updateInstallStatus(out, installer, strategy, v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonComponentUnhealthy); installErr != nil {
  2300  			// Re-sync if kube-apiserver was unavailable
  2301  			if apierrors.IsServiceUnavailable(installErr) {
  2302  				logger.WithError(installErr).Info("could not update install status")
  2303  				syncError = installErr
  2304  				return
  2305  			}
  2306  			logger.WithField("strategy", out.Spec.InstallStrategy.StrategyName).Warnf("unhealthy component: %s", installErr)
  2307  			return
  2308  		}
  2309  
  2310  		// Ensure cluster roles exist for using provided apis
  2311  		if err := a.ensureClusterRolesForCSV(out); err != nil {
  2312  			logger.WithError(err).Info("couldn't ensure clusterroles for provided api types")
  2313  			syncError = err
  2314  			return
  2315  		}
  2316  
  2317  	case v1alpha1.CSVPhaseFailed:
  2318  		// Transition to the replacing phase if FailForward is enabled and a CSV exists that replaces the operator.
  2319  		if operatorGroup.UpgradeStrategy() == operatorsv1.UpgradeStrategyUnsafeFailForward {
  2320  			if replacement := a.isBeingReplaced(out, a.csvSet(out.GetNamespace(), v1alpha1.CSVPhaseAny)); replacement != nil {
  2321  				msg := fmt.Sprintf("Fail Forward is enabled, allowing %s csv to be replaced by csv: %s", out.Status.Phase, replacement.GetName())
  2322  				out.SetPhaseWithEvent(v1alpha1.CSVPhaseReplacing, v1alpha1.CSVReasonBeingReplaced, msg, a.now(), a.recorder)
  2323  				metrics.CSVUpgradeCount.Inc()
  2324  				return
  2325  			}
  2326  		}
  2327  		installer, strategy := a.parseStrategiesAndUpdateStatus(out)
  2328  		if strategy == nil {
  2329  			return
  2330  		}
  2331  
  2332  		// Check if failed due to unsupported InstallModes
  2333  		if out.Status.Reason == v1alpha1.CSVReasonNoTargetNamespaces ||
  2334  			out.Status.Reason == v1alpha1.CSVReasonNoOperatorGroup ||
  2335  			out.Status.Reason == v1alpha1.CSVReasonTooManyOperatorGroups ||
  2336  			out.Status.Reason == v1alpha1.CSVReasonUnsupportedOperatorGroup {
  2337  			logger.Info("InstallModes now support target namespaces. Transitioning to Pending...")
  2338  			// Check occurred before switch, safe to transition to pending
  2339  			out.SetPhaseWithEvent(v1alpha1.CSVPhasePending, v1alpha1.CSVReasonRequirementsUnknown, "InstallModes now support target namespaces", now, a.recorder)
  2340  			return
  2341  		}
  2342  
  2343  		// Check if failed due to conflicting OperatorGroups
  2344  		if out.Status.Reason == v1alpha1.CSVReasonInterOperatorGroupOwnerConflict {
  2345  			logger.Info("OperatorGroup no longer intersecting with conflicting owner. Transitioning to Pending...")
  2346  			// Check occurred before switch, safe to transition to pending
  2347  			out.SetPhaseWithEvent(v1alpha1.CSVPhasePending, v1alpha1.CSVReasonRequirementsUnknown, "OperatorGroup no longer intersecting with conflicting owner", now, a.recorder)
  2348  			return
  2349  		}
  2350  
  2351  		// Check if failed due to an attempt to modify a static OperatorGroup
  2352  		if out.Status.Reason == v1alpha1.CSVReasonCannotModifyStaticOperatorGroupProvidedAPIs {
  2353  			logger.Info("static OperatorGroup and intersecting groups now support providedAPIs...")
  2354  			// Check occurred before switch, safe to transition to pending
  2355  			out.SetPhaseWithEvent(v1alpha1.CSVPhasePending, v1alpha1.CSVReasonRequirementsUnknown, "static OperatorGroup and intersecting groups now support providedAPIs", now, a.recorder)
  2356  			return
  2357  		}
  2358  
  2359  		// Check if requirements exist
  2360  		met, statuses, err := a.requirementAndPermissionStatus(out)
  2361  		if err != nil && out.Status.Reason != v1alpha1.CSVReasonInvalidStrategy {
  2362  			logger.Warn("invalid install strategy")
  2363  			out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonInvalidStrategy, fmt.Sprintf("install strategy invalid: %s", err.Error()), now, a.recorder)
  2364  			return
  2365  		} else if !met {
  2366  			logger.Debug("CSV Requirements are not met")
  2367  			out.SetRequirementStatus(statuses)
  2368  			out.SetPhaseWithEvent(v1alpha1.CSVPhasePending, v1alpha1.CSVReasonRequirementsNotMet, "requirements not met", now, a.recorder)
  2369  			return
  2370  		}
  2371  
  2372  		// Check if any generated resources are missing and that OLM can action on them
  2373  		if err := a.checkAPIServiceResources(out, certs.PEMSHA256); err != nil {
  2374  			if a.apiServiceResourceErrorActionable(err) {
  2375  				logger.WithError(err).Debug("API Resources are unavailable")
  2376  				// Check if API services are adoptable. If not, keep CSV as Failed state
  2377  				out.SetPhaseWithEvent(v1alpha1.CSVPhasePending, v1alpha1.CSVReasonAPIServiceResourcesNeedReinstall, err.Error(), now, a.recorder)
  2378  			}
  2379  			return
  2380  		}
  2381  
  2382  		// Check if it's time to refresh owned APIService certs
  2383  		if shouldRotate, err := installer.ShouldRotateCerts(strategy); err != nil {
  2384  			logger.WithError(err).Info("cert validity check")
  2385  			return
  2386  		} else if shouldRotate {
  2387  			logger.Debug("CSV owns resources that require a cert refresh")
  2388  			out.SetPhaseWithEvent(v1alpha1.CSVPhasePending, v1alpha1.CSVReasonNeedsCertRotation, "owned APIServices need cert refresh", now, a.recorder)
  2389  			return
  2390  		}
  2391  
  2392  		// Check install status
  2393  		strategy, err = a.updateDeploymentSpecsWithAPIServiceData(out, strategy)
  2394  		if err != nil {
  2395  			logger.WithError(err).Debug("Unable to calculate expected deployment")
  2396  			out.SetPhaseWithEvent(v1alpha1.CSVPhasePending, v1alpha1.CSVReasonNeedsReinstall, "calculated deployment install is bad", now, a.recorder)
  2397  			return
  2398  		}
  2399  		if installErr := a.updateInstallStatus(out, installer, strategy, v1alpha1.CSVPhasePending, v1alpha1.CSVReasonNeedsReinstall); installErr != nil {
  2400  			// Re-sync if kube-apiserver was unavailable
  2401  			if apierrors.IsServiceUnavailable(installErr) {
  2402  				logger.WithError(installErr).Info("could not update install status")
  2403  				syncError = installErr
  2404  				return
  2405  			}
  2406  			logger.WithField("strategy", out.Spec.InstallStrategy.StrategyName).Warnf("needs reinstall: %s", installErr)
  2407  		}
  2408  
  2409  	case v1alpha1.CSVPhaseReplacing:
  2410  		// determine CSVs that are safe to delete by finding a replacement chain to a CSV that's running
  2411  		// since we don't know what order we'll process replacements, we have to guard against breaking that chain
  2412  
  2413  		// if this isn't the earliest csv in a replacement chain, skip gc.
  2414  		// marking an intermediate for deletion will break the replacement chain
  2415  		if prev := a.isReplacing(out); prev != nil {
  2416  			logger.Debugf("being replaced, but is not a leaf. skipping gc")
  2417  			return
  2418  		}
  2419  
  2420  		// If there is a succeeded replacement, mark this for deletion
  2421  		next := a.isBeingReplaced(out, a.csvSet(out.GetNamespace(), v1alpha1.CSVPhaseAny))
  2422  		// Get the newest CSV in the replacement chain if fail forward upgrades are enabled.
  2423  		if operatorGroup.UpgradeStrategy() == operatorsv1.UpgradeStrategyUnsafeFailForward {
  2424  			csvs, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(next.GetNamespace()).List(labels.Everything())
  2425  			if err != nil {
  2426  				syncError = err
  2427  				return
  2428  			}
  2429  
  2430  			lastCSVInChain, err := resolver.WalkReplacementChain(next, resolver.ReplacementMapping(csvs), resolver.WithUniqueCSVs())
  2431  			if err != nil {
  2432  				syncError = err
  2433  				return
  2434  			}
  2435  
  2436  			if lastCSVInChain == nil {
  2437  				syncError = fmt.Errorf("fail forward upgrades enabled, unable to identify last CSV in replacement chain")
  2438  				return
  2439  			}
  2440  
  2441  			next = lastCSVInChain
  2442  		}
  2443  		if next != nil {
  2444  			if next.Status.Phase == v1alpha1.CSVPhaseSucceeded {
  2445  				out.SetPhaseWithEvent(v1alpha1.CSVPhaseDeleting, v1alpha1.CSVReasonReplaced, "has been replaced by a newer ClusterServiceVersion that has successfully installed.", now, a.recorder)
  2446  			} else {
  2447  				// If there's a replacement, but it's not yet succeeded, requeue both (this is an active replacement)
  2448  				if err := a.csvQueueSet.Requeue(next.GetNamespace(), next.GetName()); err != nil {
  2449  					a.logger.Warn(err.Error())
  2450  				}
  2451  				if err := a.csvQueueSet.Requeue(out.GetNamespace(), out.GetName()); err != nil {
  2452  					a.logger.Warn(err.Error())
  2453  				}
  2454  			}
  2455  		} else {
  2456  			syncError = fmt.Errorf("marked as replacement, but no replacement CSV found in cluster")
  2457  		}
  2458  	case v1alpha1.CSVPhaseDeleting:
  2459  		syncError = a.client.OperatorsV1alpha1().ClusterServiceVersions(out.GetNamespace()).Delete(context.TODO(), out.GetName(), metav1.DeleteOptions{})
  2460  		if syncError != nil {
  2461  			logger.Debugf("unable to get delete csv marked for deletion: %s", syncError.Error())
  2462  		}
  2463  	}
  2464  
  2465  	return
  2466  }
  2467  
  2468  // csvSet gathers all CSVs in the given namespace into a map keyed by CSV name; if metav1.NamespaceAll gets the set across all namespaces
  2469  func (a *Operator) csvSet(namespace string, phase v1alpha1.ClusterServiceVersionPhase) map[string]*v1alpha1.ClusterServiceVersion {
  2470  	return a.csvSetGenerator.WithNamespace(namespace, phase)
  2471  }
  2472  
  2473  // checkReplacementsAndUpdateStatus returns an error if we can find a newer CSV and sets the status if so
  2474  func (a *Operator) checkReplacementsAndUpdateStatus(csv *v1alpha1.ClusterServiceVersion) error {
  2475  	if csv.Status.Phase == v1alpha1.CSVPhaseReplacing || csv.Status.Phase == v1alpha1.CSVPhaseDeleting {
  2476  		return nil
  2477  	}
  2478  	if replacement := a.isBeingReplaced(csv, a.csvSet(csv.GetNamespace(), v1alpha1.CSVPhaseAny)); replacement != nil {
  2479  		a.logger.Infof("newer csv replacing %s, no-op", csv.GetName())
  2480  		msg := fmt.Sprintf("being replaced by csv: %s", replacement.GetName())
  2481  		csv.SetPhaseWithEvent(v1alpha1.CSVPhaseReplacing, v1alpha1.CSVReasonBeingReplaced, msg, a.now(), a.recorder)
  2482  		metrics.CSVUpgradeCount.Inc()
  2483  
  2484  		return fmt.Errorf("replacing")
  2485  	}
  2486  	return nil
  2487  }
  2488  
  2489  func (a *Operator) updateInstallStatus(csv *v1alpha1.ClusterServiceVersion, installer install.StrategyInstaller, strategy install.Strategy, requeuePhase v1alpha1.ClusterServiceVersionPhase, requeueConditionReason v1alpha1.ConditionReason) error {
  2490  	strategyInstalled, strategyErr := installer.CheckInstalled(strategy)
  2491  	now := a.now()
  2492  
  2493  	if strategyErr != nil {
  2494  		a.logger.WithError(strategyErr).Debug("operator not installed")
  2495  	}
  2496  
  2497  	apiServicesInstalled, apiServiceErr := a.areAPIServicesAvailable(csv)
  2498  	webhooksInstalled, webhookErr := a.areWebhooksAvailable(csv)
  2499  
  2500  	if strategyInstalled && apiServicesInstalled && webhooksInstalled {
  2501  		// if there's no error, we're successfully running
  2502  		csv.SetPhaseWithEventIfChanged(v1alpha1.CSVPhaseSucceeded, v1alpha1.CSVReasonInstallSuccessful, "install strategy completed with no errors", now, a.recorder)
  2503  		return nil
  2504  	}
  2505  
  2506  	if err := findFirstError(apierrors.IsServiceUnavailable, strategyErr, apiServiceErr, webhookErr); err != nil {
  2507  		return err
  2508  	}
  2509  
  2510  	// installcheck determined we can't progress (e.g. deployment failed to come up in time)
  2511  	if install.IsErrorUnrecoverable(strategyErr) {
  2512  		csv.SetPhaseWithEventIfChanged(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonInstallCheckFailed, fmt.Sprintf("install failed: %s", strategyErr), now, a.recorder)
  2513  		return strategyErr
  2514  	}
  2515  
  2516  	if apiServiceErr != nil {
  2517  		csv.SetPhaseWithEventIfChanged(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonAPIServiceInstallFailed, fmt.Sprintf("APIService install failed: %s", apiServiceErr), now, a.recorder)
  2518  		return apiServiceErr
  2519  	}
  2520  
  2521  	if !apiServicesInstalled {
  2522  		msg := "apiServices not installed"
  2523  		csv.SetPhaseWithEventIfChanged(requeuePhase, requeueConditionReason, msg, now, a.recorder)
  2524  		if err := a.csvQueueSet.Requeue(csv.GetNamespace(), csv.GetName()); err != nil {
  2525  			a.logger.Warn(err.Error())
  2526  		}
  2527  
  2528  		return errors.New(msg)
  2529  	}
  2530  
  2531  	if webhookErr != nil {
  2532  		csv.SetPhaseWithEventIfChanged(v1alpha1.CSVPhaseInstallReady, requeueConditionReason, fmt.Sprintf("Webhook install failed: %s", webhookErr), now, a.recorder)
  2533  		return webhookErr
  2534  	}
  2535  
  2536  	if !webhooksInstalled {
  2537  		msg := "webhooks not installed"
  2538  		csv.SetPhaseWithEventIfChanged(requeuePhase, requeueConditionReason, msg, now, a.recorder)
  2539  		if err := a.csvQueueSet.Requeue(csv.GetNamespace(), csv.GetName()); err != nil {
  2540  			a.logger.Warn(err.Error())
  2541  		}
  2542  
  2543  		return errors.New(msg)
  2544  	}
  2545  
  2546  	if strategyErr != nil {
  2547  		reasonForError := install.ReasonForError(strategyErr)
  2548  		if reasonForError == install.StrategyErrDeploymentUpdated || reasonForError == install.StrategyErrReasonAnnotationsMissing {
  2549  			csv.SetPhaseWithEventIfChanged(v1alpha1.CSVPhaseInstallReady, requeueConditionReason, fmt.Sprintf("installing: %s", strategyErr), now, a.recorder)
  2550  		} else {
  2551  			csv.SetPhaseWithEventIfChanged(requeuePhase, requeueConditionReason, fmt.Sprintf("installing: %s", strategyErr), now, a.recorder)
  2552  		}
  2553  		if err := a.csvQueueSet.Requeue(csv.GetNamespace(), csv.GetName()); err != nil {
  2554  			a.logger.Warn(err.Error())
  2555  		}
  2556  
  2557  		return strategyErr
  2558  	}
  2559  
  2560  	return nil
  2561  }
  2562  
  2563  func findFirstError(f func(error) bool, errs ...error) error {
  2564  	for _, err := range errs {
  2565  		if f(err) {
  2566  			return err
  2567  		}
  2568  	}
  2569  	return nil
  2570  }
  2571  
  2572  // parseStrategiesAndUpdateStatus returns a StrategyInstaller and a Strategy for a CSV if it can, else it sets a status on the CSV and returns
  2573  func (a *Operator) parseStrategiesAndUpdateStatus(csv *v1alpha1.ClusterServiceVersion) (install.StrategyInstaller, install.Strategy) {
  2574  	strategy, err := a.resolver.UnmarshalStrategy(csv.Spec.InstallStrategy)
  2575  	if err != nil {
  2576  		csv.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonInvalidStrategy, fmt.Sprintf("install strategy invalid: %s", err), a.now(), a.recorder)
  2577  		return nil, nil
  2578  	}
  2579  
  2580  	previousCSV := a.isReplacing(csv)
  2581  	var previousStrategy install.Strategy
  2582  	if previousCSV != nil {
  2583  		err = a.csvQueueSet.Requeue(previousCSV.Namespace, previousCSV.Name)
  2584  		if err != nil {
  2585  			a.logger.Warn(err.Error())
  2586  		}
  2587  
  2588  		previousStrategy, err = a.resolver.UnmarshalStrategy(previousCSV.Spec.InstallStrategy)
  2589  		if err != nil {
  2590  			previousStrategy = nil
  2591  		}
  2592  	}
  2593  
  2594  	// If an admin has specified a service account to the operator group
  2595  	// associated with the namespace then we should use a scoped client that is
  2596  	// bound to the service account.
  2597  	querierFunc := a.serviceAccountQuerier.NamespaceQuerier(csv.GetNamespace())
  2598  	attenuate, err := a.clientAttenuator.AttenuateToServiceAccount(querierFunc)
  2599  	if err != nil {
  2600  		a.logger.Errorf("failed to get a client for operator deployment - %v", err)
  2601  		return nil, nil
  2602  	}
  2603  	kubeclient, err := a.clientFactory.WithConfigTransformer(attenuate).NewOperatorClient()
  2604  	if err != nil {
  2605  		a.logger.Errorf("failed to get an operator client for operator deployment - %v", err)
  2606  		return nil, nil
  2607  	}
  2608  
  2609  	strName := strategy.GetStrategyName()
  2610  	installer := a.resolver.InstallerForStrategy(strName, kubeclient, a.lister, csv, csv.GetAnnotations(), csv.GetAllAPIServiceDescriptions(), csv.Spec.WebhookDefinitions, previousStrategy)
  2611  	return installer, strategy
  2612  }
  2613  
  2614  func (a *Operator) crdOwnerConflicts(in *v1alpha1.ClusterServiceVersion, csvsInNamespace map[string]*v1alpha1.ClusterServiceVersion) error {
  2615  	csvsInChain := a.getReplacementChain(in, csvsInNamespace)
  2616  	// find csvs in the namespace that are not part of the replacement chain
  2617  	for name, csv := range csvsInNamespace {
  2618  		if _, ok := csvsInChain[name]; ok {
  2619  			continue
  2620  		}
  2621  		for _, crd := range in.Spec.CustomResourceDefinitions.Owned {
  2622  			if name != in.GetName() && csv.OwnsCRD(crd.Name) {
  2623  				return ErrCRDOwnerConflict
  2624  			}
  2625  		}
  2626  	}
  2627  
  2628  	return nil
  2629  }
  2630  
  2631  func (a *Operator) getReplacementChain(in *v1alpha1.ClusterServiceVersion, csvsInNamespace map[string]*v1alpha1.ClusterServiceVersion) map[string]struct{} {
  2632  	current := in.GetName()
  2633  	csvsInChain := map[string]struct{}{
  2634  		current: {},
  2635  	}
  2636  
  2637  	replacement := func(csvName string) *string {
  2638  		for _, csv := range csvsInNamespace {
  2639  			if csv.Spec.Replaces == csvName {
  2640  				name := csv.GetName()
  2641  				return &name
  2642  			}
  2643  		}
  2644  		return nil
  2645  	}
  2646  
  2647  	replaces := func(replaces string) *string {
  2648  		for _, csv := range csvsInNamespace {
  2649  			name := csv.GetName()
  2650  			if name == replaces {
  2651  				rep := csv.Spec.Replaces
  2652  				return &rep
  2653  			}
  2654  		}
  2655  		return nil
  2656  	}
  2657  
  2658  	next := replacement(current)
  2659  	for next != nil {
  2660  		if _, ok := csvsInChain[*next]; ok {
  2661  			break // cycle
  2662  		}
  2663  		csvsInChain[*next] = struct{}{}
  2664  		current = *next
  2665  		next = replacement(current)
  2666  	}
  2667  
  2668  	current = in.Spec.Replaces
  2669  	prev := replaces(current)
  2670  	if prev != nil {
  2671  		csvsInChain[current] = struct{}{}
  2672  	}
  2673  	for prev != nil && *prev != "" {
  2674  		if _, ok := csvsInChain[*prev]; ok {
  2675  			break // cycle
  2676  		}
  2677  		current = *prev
  2678  		csvsInChain[current] = struct{}{}
  2679  		prev = replaces(current)
  2680  	}
  2681  	return csvsInChain
  2682  }
  2683  
  2684  func (a *Operator) apiServiceOwnerConflicts(csv *v1alpha1.ClusterServiceVersion) error {
  2685  	for _, desc := range csv.GetOwnedAPIServiceDescriptions() {
  2686  		// Check if the APIService exists
  2687  		apiService, err := a.lister.APIRegistrationV1().APIServiceLister().Get(desc.GetName())
  2688  		if err != nil && !apierrors.IsNotFound(err) && !apierrors.IsGone(err) {
  2689  			return err
  2690  		}
  2691  
  2692  		if apiService == nil {
  2693  			continue
  2694  		}
  2695  
  2696  		adoptable, err := install.IsAPIServiceAdoptable(a.lister, csv, apiService)
  2697  		if err != nil {
  2698  			a.logger.WithFields(logrus.Fields{"obj": "apiService", "labels": apiService.GetLabels()}).Errorf("adoption check failed - %v", err)
  2699  		}
  2700  
  2701  		if !adoptable {
  2702  			return ErrAPIServiceOwnerConflict
  2703  		}
  2704  	}
  2705  
  2706  	return nil
  2707  }
  2708  
  2709  func (a *Operator) isBeingReplaced(in *v1alpha1.ClusterServiceVersion, csvsInNamespace map[string]*v1alpha1.ClusterServiceVersion) (replacedBy *v1alpha1.ClusterServiceVersion) {
  2710  	return a.csvReplaceFinder.IsBeingReplaced(in, csvsInNamespace)
  2711  }
  2712  
  2713  func (a *Operator) isReplacing(in *v1alpha1.ClusterServiceVersion) *v1alpha1.ClusterServiceVersion {
  2714  	return a.csvReplaceFinder.IsReplacing(in)
  2715  }
  2716  
  2717  func (a *Operator) handleDeletion(obj interface{}) {
  2718  	metaObj, ok := obj.(metav1.Object)
  2719  	if !ok {
  2720  		tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
  2721  		if !ok {
  2722  			utilruntime.HandleError(fmt.Errorf("couldn't get object from tombstone %#v", obj))
  2723  			return
  2724  		}
  2725  
  2726  		metaObj, ok = tombstone.Obj.(metav1.Object)
  2727  		if !ok {
  2728  			utilruntime.HandleError(fmt.Errorf("tombstone contained object that is not a metav1.Object %#v", obj))
  2729  			return
  2730  		}
  2731  	}
  2732  	logger := a.logger.WithFields(logrus.Fields{
  2733  		"name":      metaObj.GetName(),
  2734  		"namespace": metaObj.GetNamespace(),
  2735  		"self":      metaObj.GetSelfLink(),
  2736  	})
  2737  	logger.Debug("handling resource deletion")
  2738  
  2739  	logger.Debug("requeueing owner csvs due to deletion")
  2740  	a.requeueOwnerCSVs(metaObj)
  2741  
  2742  	// Requeue CSVs with provided and required labels (for CRDs)
  2743  	if labelSets, err := a.apiLabeler.LabelSetsFor(metaObj); err != nil {
  2744  		logger.WithError(err).Warn("couldn't create label set")
  2745  	} else if len(labelSets) > 0 {
  2746  		logger.Debug("requeueing providing/requiring csvs due to deletion")
  2747  		a.requeueCSVsByLabelSet(logger, labelSets...)
  2748  	}
  2749  }
  2750  
  2751  func (a *Operator) requeueCSVsByLabelSet(logger *logrus.Entry, labelSets ...labels.Set) {
  2752  	keys, err := index.LabelIndexKeys(a.csvIndexers, labelSets...)
  2753  	if err != nil {
  2754  		logger.WithError(err).Debug("issue getting csvs by label index")
  2755  		return
  2756  	}
  2757  
  2758  	for _, key := range keys {
  2759  		if err := a.csvQueueSet.RequeueByKey(key); err != nil {
  2760  			logger.WithError(err).Debug("cannot requeue requiring/providing csv")
  2761  		} else {
  2762  			logger.WithField("key", key).Debug("csv successfully requeued on crd change")
  2763  		}
  2764  	}
  2765  }
  2766  
  2767  func (a *Operator) requeueOwnerCSVs(ownee metav1.Object) {
  2768  	logger := a.logger.WithFields(logrus.Fields{
  2769  		"ownee":     ownee.GetName(),
  2770  		"selflink":  ownee.GetSelfLink(),
  2771  		"namespace": ownee.GetNamespace(),
  2772  	})
  2773  
  2774  	// Attempt to requeue CSV owners in the same namespace as the object
  2775  	owners := ownerutil.GetOwnersByKind(ownee, v1alpha1.ClusterServiceVersionKind)
  2776  	if len(owners) > 0 && ownee.GetNamespace() != metav1.NamespaceAll {
  2777  		for _, ownerCSV := range owners {
  2778  			_, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(ownee.GetNamespace()).Get(ownerCSV.Name)
  2779  			if apierrors.IsNotFound(err) {
  2780  				logger.Debugf("skipping requeue since CSV %v is not in cache", ownerCSV.Name)
  2781  				continue
  2782  			}
  2783  			// Since cross-namespace CSVs can't exist we're guaranteed the owner will be in the same namespace
  2784  			err = a.csvQueueSet.Requeue(ownee.GetNamespace(), ownerCSV.Name)
  2785  			if err != nil {
  2786  				logger.Warn(err.Error())
  2787  			}
  2788  		}
  2789  		return
  2790  	}
  2791  
  2792  	// Requeue owners based on labels
  2793  	if name, ns, ok := ownerutil.GetOwnerByKindLabel(ownee, v1alpha1.ClusterServiceVersionKind); ok {
  2794  		_, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(ns).Get(name)
  2795  		if apierrors.IsNotFound(err) {
  2796  			logger.Debugf("skipping requeue since CSV %v is not in cache", name)
  2797  			return
  2798  		}
  2799  
  2800  		err = a.csvQueueSet.Requeue(ns, name)
  2801  		if err != nil {
  2802  			logger.Warn(err.Error())
  2803  		}
  2804  	}
  2805  }
  2806  
  2807  func (a *Operator) cleanupCSVDeployments(logger *logrus.Entry, csv *v1alpha1.ClusterServiceVersion) {
  2808  	// Extract the InstallStrategy for the deployment
  2809  	strategy, err := a.resolver.UnmarshalStrategy(csv.Spec.InstallStrategy)
  2810  	if err != nil {
  2811  		logger.Warn("could not parse install strategy while cleaning up CSV deployment")
  2812  		return
  2813  	}
  2814  
  2815  	// Assume the strategy is for a deployment
  2816  	strategyDetailsDeployment, ok := strategy.(*v1alpha1.StrategyDetailsDeployment)
  2817  	if !ok {
  2818  		logger.Warnf("could not cast install strategy as type %T", strategyDetailsDeployment)
  2819  		return
  2820  	}
  2821  
  2822  	// Delete deployments
  2823  	for _, spec := range strategyDetailsDeployment.DeploymentSpecs {
  2824  		logger := logger.WithField("deployment", spec.Name)
  2825  		logger.Debug("cleaning up CSV deployment")
  2826  		if err := a.opClient.DeleteDeployment(csv.GetNamespace(), spec.Name, &metav1.DeleteOptions{}); err != nil {
  2827  			logger.WithField("err", err).Warn("error cleaning up CSV deployment")
  2828  		}
  2829  	}
  2830  }
  2831  
  2832  // ensureLabels merges a label set with a CSV's labels and attempts to update the CSV if the merged set differs from the CSV's original labels.
  2833  func (a *Operator) ensureLabels(in *v1alpha1.ClusterServiceVersion, labelSets ...labels.Set) (*v1alpha1.ClusterServiceVersion, error) {
  2834  	csvLabelSet := labels.Set(in.GetLabels())
  2835  	merged := csvLabelSet
  2836  	for _, labelSet := range labelSets {
  2837  		merged = labels.Merge(merged, labelSet)
  2838  	}
  2839  	if labels.Equals(csvLabelSet, merged) {
  2840  		return in, nil
  2841  	}
  2842  
  2843  	logger := a.logger.WithFields(logrus.Fields{"labels": merged, "csv": in.GetName(), "ns": in.GetNamespace()})
  2844  	logger.Info("updated labels")
  2845  
  2846  	out := in.DeepCopy()
  2847  	out.SetLabels(merged)
  2848  	out, err := a.client.OperatorsV1alpha1().ClusterServiceVersions(out.GetNamespace()).Update(context.TODO(), out, metav1.UpdateOptions{})
  2849  	return out, err
  2850  }