github.com/operator-framework/operator-lifecycle-manager@v0.30.0/test/e2e/operator_groups_e2e_test.go (about)

     1  package e2e
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/blang/semver/v4"
    11  	"github.com/google/go-cmp/cmp"
    12  	. "github.com/onsi/ginkgo/v2"
    13  	. "github.com/onsi/gomega"
    14  	"github.com/stretchr/testify/assert"
    15  	"github.com/stretchr/testify/require"
    16  	authorizationv1 "k8s.io/api/authorization/v1"
    17  	corev1 "k8s.io/api/core/v1"
    18  	rbacv1 "k8s.io/api/rbac/v1"
    19  	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    20  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    21  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    22  	"k8s.io/apimachinery/pkg/labels"
    23  	"k8s.io/apimachinery/pkg/util/wait"
    24  	"k8s.io/client-go/informers"
    25  	"k8s.io/client-go/tools/cache"
    26  	"k8s.io/client-go/util/retry"
    27  
    28  	v1 "github.com/operator-framework/api/pkg/operators/v1"
    29  	"github.com/operator-framework/api/pkg/operators/v1alpha1"
    30  	"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned"
    31  	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
    32  	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry"
    33  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
    34  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil"
    35  	"github.com/operator-framework/operator-lifecycle-manager/test/e2e/ctx"
    36  )
    37  
    38  var _ = Describe("Operator Group", func() {
    39  	var (
    40  		c                  operatorclient.ClientInterface
    41  		crc                versioned.Interface
    42  		generatedNamespace corev1.Namespace
    43  	)
    44  
    45  	BeforeEach(func() {
    46  		c = ctx.Ctx().KubeClient()
    47  		crc = ctx.Ctx().OperatorClient()
    48  
    49  		generatedNamespace = SetupGeneratedTestNamespace(genName("operator-group-e2e-"))
    50  
    51  	})
    52  
    53  	AfterEach(func() {
    54  		TearDown(generatedNamespace.GetName())
    55  	})
    56  
    57  	It("e2e functionality", func() {
    58  
    59  		By(`Create namespace with specific label`)
    60  		By(`Create CRD`)
    61  		By(`Create CSV in operator namespace`)
    62  		By(`Create operator group that watches namespace and uses specific label`)
    63  		By(`Verify operator group status contains correct status`)
    64  		By(`Verify csv in target namespace exists, has copied status, has annotations`)
    65  		By(`Verify deployments have correct namespace annotation`)
    66  		By(`(Verify that the operator can operate in the target namespace)`)
    67  		By(`Update CSV to support no InstallModes`)
    68  		By(`Verify the CSV transitions to FAILED`)
    69  		By(`Verify the copied CSV transitions to FAILED`)
    70  		By(`Delete CSV`)
    71  		By(`Verify copied CVS is deleted`)
    72  
    73  		log := func(s string) {
    74  			GinkgoT().Logf("%s: %s", time.Now().Format("15:04:05.9999"), s)
    75  		}
    76  
    77  		csvName := genName("another-csv-") // must be lowercase for DNS-1123 validation
    78  
    79  		opGroupNamespace := genName(generatedNamespace.GetName() + "-")
    80  		matchingLabel := map[string]string{"inGroup": opGroupNamespace}
    81  		otherNamespaceName := genName(opGroupNamespace + "-")
    82  		bothNamespaceNames := opGroupNamespace + "," + otherNamespaceName
    83  
    84  		_, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
    85  			ObjectMeta: metav1.ObjectMeta{
    86  				Name:   opGroupNamespace,
    87  				Labels: matchingLabel,
    88  			},
    89  		}, metav1.CreateOptions{})
    90  		require.NoError(GinkgoT(), err)
    91  		defer func() {
    92  			err = c.KubernetesInterface().CoreV1().Namespaces().Delete(context.TODO(), opGroupNamespace, metav1.DeleteOptions{})
    93  			require.NoError(GinkgoT(), err)
    94  		}()
    95  
    96  		otherNamespace := corev1.Namespace{
    97  			ObjectMeta: metav1.ObjectMeta{
    98  				Name:   otherNamespaceName,
    99  				Labels: matchingLabel,
   100  			},
   101  		}
   102  		createdOtherNamespace, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), &otherNamespace, metav1.CreateOptions{})
   103  		require.NoError(GinkgoT(), err)
   104  		defer func() {
   105  			err = c.KubernetesInterface().CoreV1().Namespaces().Delete(context.TODO(), otherNamespaceName, metav1.DeleteOptions{})
   106  			require.NoError(GinkgoT(), err)
   107  		}()
   108  
   109  		log("Creating CRD")
   110  		mainCRDPlural := genName("opgroup")
   111  		mainCRD := newCRD(mainCRDPlural)
   112  		cleanupCRD, err := createCRD(c, mainCRD)
   113  		require.NoError(GinkgoT(), err)
   114  		defer cleanupCRD()
   115  
   116  		log("Creating operator group")
   117  		operatorGroup := v1.OperatorGroup{
   118  			ObjectMeta: metav1.ObjectMeta{
   119  				Name:      genName("e2e-operator-group-"),
   120  				Namespace: opGroupNamespace,
   121  			},
   122  			Spec: v1.OperatorGroupSpec{
   123  				Selector: &metav1.LabelSelector{
   124  					MatchLabels: matchingLabel,
   125  				},
   126  			},
   127  		}
   128  		_, err = crc.OperatorsV1().OperatorGroups(opGroupNamespace).Create(context.TODO(), &operatorGroup, metav1.CreateOptions{})
   129  		require.NoError(GinkgoT(), err)
   130  
   131  		By(`fetched namespaces might be in any order`)
   132  		namespaces := map[string]bool{}
   133  		namespaces[opGroupNamespace] = true
   134  		namespaces[createdOtherNamespace.GetName()] = true
   135  
   136  		log("Waiting on operator group to have correct status")
   137  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
   138  			fetched, fetchErr := crc.OperatorsV1().OperatorGroups(opGroupNamespace).Get(context.TODO(), operatorGroup.Name, metav1.GetOptions{})
   139  			if fetchErr != nil {
   140  				log(fmt.Sprintf("error getting operatorgroup %s/%s: %v", opGroupNamespace, operatorGroup.Name, err))
   141  				return false, nil
   142  			}
   143  			if len(namespaces) != len(fetched.Status.Namespaces) {
   144  				log(fmt.Sprintf("element length mismatch: %v vs %v", namespaces, fetched.Status.Namespaces))
   145  				return false, nil
   146  			}
   147  			for _, v := range fetched.Status.Namespaces {
   148  				if !namespaces[v] {
   149  					log(fmt.Sprintf("element values mismatch: %v vs %v", namespaces, fetched.Status.Namespaces))
   150  					return false, nil
   151  				}
   152  			}
   153  			return true, nil
   154  		})
   155  		require.NoError(GinkgoT(), err)
   156  
   157  		log("Creating CSV")
   158  
   159  		By(`Generate permissions`)
   160  		serviceAccountName := genName("nginx-sa")
   161  		permissions := []v1alpha1.StrategyDeploymentPermissions{
   162  			{
   163  				ServiceAccountName: serviceAccountName,
   164  				Rules: []rbacv1.PolicyRule{
   165  					{
   166  						Verbs:     []string{rbacv1.VerbAll},
   167  						APIGroups: []string{mainCRD.Spec.Group},
   168  						Resources: []string{mainCRDPlural},
   169  					},
   170  				},
   171  			},
   172  		}
   173  
   174  		By(`Create a new NamedInstallStrategy`)
   175  		deploymentName := genName("operator-deployment")
   176  		namedStrategy := newNginxInstallStrategy(deploymentName, permissions, nil)
   177  
   178  		aCSV := newCSV(csvName, opGroupNamespace, "", semver.MustParse("0.0.0"), []apiextensionsv1.CustomResourceDefinition{mainCRD}, nil, &namedStrategy)
   179  		createdCSV, err := crc.OperatorsV1alpha1().ClusterServiceVersions(opGroupNamespace).Create(context.TODO(), &aCSV, metav1.CreateOptions{})
   180  		require.NoError(GinkgoT(), err)
   181  
   182  		serviceAccount := &corev1.ServiceAccount{
   183  			ObjectMeta: metav1.ObjectMeta{
   184  				Namespace: opGroupNamespace,
   185  				Name:      serviceAccountName,
   186  			},
   187  		}
   188  		ownerutil.AddNonBlockingOwner(serviceAccount, createdCSV)
   189  		err = ownerutil.AddOwnerLabels(serviceAccount, createdCSV)
   190  		require.NoError(GinkgoT(), err)
   191  
   192  		role := &rbacv1.Role{
   193  			ObjectMeta: metav1.ObjectMeta{
   194  				Namespace: opGroupNamespace,
   195  				Name:      serviceAccountName + "-role",
   196  			},
   197  			Rules: permissions[0].Rules,
   198  		}
   199  		ownerutil.AddNonBlockingOwner(role, createdCSV)
   200  		err = ownerutil.AddOwnerLabels(role, createdCSV)
   201  		require.NoError(GinkgoT(), err)
   202  
   203  		roleBinding := &rbacv1.RoleBinding{
   204  			ObjectMeta: metav1.ObjectMeta{
   205  				Namespace: opGroupNamespace,
   206  				Name:      serviceAccountName + "-rb",
   207  			},
   208  			Subjects: []rbacv1.Subject{
   209  				{
   210  					Kind:      "ServiceAccount",
   211  					Name:      serviceAccountName,
   212  					Namespace: opGroupNamespace,
   213  				},
   214  			},
   215  			RoleRef: rbacv1.RoleRef{
   216  				Kind: "Role",
   217  				Name: role.GetName(),
   218  			},
   219  		}
   220  		ownerutil.AddNonBlockingOwner(roleBinding, createdCSV)
   221  		err = ownerutil.AddOwnerLabels(roleBinding, createdCSV)
   222  		require.NoError(GinkgoT(), err)
   223  
   224  		_, err = c.CreateServiceAccount(serviceAccount)
   225  		require.NoError(GinkgoT(), err)
   226  		_, err = c.CreateRole(role)
   227  		require.NoError(GinkgoT(), err)
   228  		_, err = c.CreateRoleBinding(roleBinding)
   229  		require.NoError(GinkgoT(), err)
   230  
   231  		log("wait for CSV to succeed")
   232  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
   233  			fetched, err := crc.OperatorsV1alpha1().ClusterServiceVersions(opGroupNamespace).Get(context.TODO(), createdCSV.GetName(), metav1.GetOptions{})
   234  			if err != nil {
   235  				return false, err
   236  			}
   237  			log(fmt.Sprintf("%s (%s): %s", fetched.Status.Phase, fetched.Status.Reason, fetched.Status.Message))
   238  			return csvSucceededChecker(fetched), nil
   239  		})
   240  		require.NoError(GinkgoT(), err)
   241  
   242  		log("Waiting for operator namespace csv to have annotations")
   243  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
   244  			fetchedCSV, fetchErr := crc.OperatorsV1alpha1().ClusterServiceVersions(opGroupNamespace).Get(context.TODO(), csvName, metav1.GetOptions{})
   245  			if fetchErr != nil {
   246  				if apierrors.IsNotFound(fetchErr) {
   247  					return false, nil
   248  				}
   249  				log(fmt.Sprintf("Error (in %v): %v", generatedNamespace.GetName(), fetchErr.Error()))
   250  				return false, fetchErr
   251  			}
   252  			if checkOperatorGroupAnnotations(fetchedCSV, &operatorGroup, true, bothNamespaceNames) == nil {
   253  				return true, nil
   254  			}
   255  			return false, nil
   256  		})
   257  		require.NoError(GinkgoT(), err)
   258  
   259  		log("Waiting for target namespace csv to have annotations (but not target namespaces)")
   260  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
   261  			fetchedCSV, fetchErr := crc.OperatorsV1alpha1().ClusterServiceVersions(otherNamespaceName).Get(context.TODO(), csvName, metav1.GetOptions{})
   262  			if fetchErr != nil {
   263  				if apierrors.IsNotFound(fetchErr) {
   264  					return false, nil
   265  				}
   266  				log(fmt.Sprintf("Error (in %v): %v", otherNamespaceName, fetchErr.Error()))
   267  				return false, fetchErr
   268  			}
   269  			if checkOperatorGroupAnnotations(fetchedCSV, &operatorGroup, false, "") == nil {
   270  				return true, nil
   271  			}
   272  
   273  			return false, nil
   274  		})
   275  
   276  		log("Checking status on csv in target namespace")
   277  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
   278  			fetchedCSV, fetchErr := crc.OperatorsV1alpha1().ClusterServiceVersions(otherNamespaceName).Get(context.TODO(), csvName, metav1.GetOptions{})
   279  			if fetchErr != nil {
   280  				if apierrors.IsNotFound(fetchErr) {
   281  					return false, nil
   282  				}
   283  				GinkgoT().Logf("Error (in %v): %v", otherNamespaceName, fetchErr.Error())
   284  				return false, fetchErr
   285  			}
   286  			if fetchedCSV.Status.Reason == v1alpha1.CSVReasonCopied {
   287  				return true, nil
   288  			}
   289  			return false, nil
   290  		})
   291  		require.NoError(GinkgoT(), err)
   292  
   293  		log("Waiting on deployment to have correct annotations")
   294  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
   295  			createdDeployment, err := c.GetDeployment(opGroupNamespace, deploymentName)
   296  			if err != nil {
   297  				if apierrors.IsNotFound(err) {
   298  					return false, nil
   299  				}
   300  				return false, err
   301  			}
   302  			if checkOperatorGroupAnnotations(&createdDeployment.Spec.Template, &operatorGroup, true, bothNamespaceNames) == nil {
   303  				return true, nil
   304  			}
   305  			return false, nil
   306  		})
   307  		require.NoError(GinkgoT(), err)
   308  
   309  		By(`check rbac in target namespace`)
   310  		informerFactory := informers.NewSharedInformerFactory(c.KubernetesInterface(), 1*time.Second)
   311  		roleInformer := informerFactory.Rbac().V1().Roles()
   312  		roleBindingInformer := informerFactory.Rbac().V1().RoleBindings()
   313  		clusterRoleInformer := informerFactory.Rbac().V1().ClusterRoles()
   314  		clusterRoleBindingInformer := informerFactory.Rbac().V1().ClusterRoleBindings()
   315  
   316  		By(`kick off informers`)
   317  		stopCh := make(chan struct{})
   318  		defer func() {
   319  			stopCh <- struct{}{}
   320  		}()
   321  
   322  		for _, informer := range []cache.SharedIndexInformer{roleInformer.Informer(), roleBindingInformer.Informer(), clusterRoleInformer.Informer(), clusterRoleBindingInformer.Informer()} {
   323  			go func() {
   324  				defer GinkgoRecover()
   325  				informer.Run(stopCh)
   326  			}()
   327  
   328  			synced := func() (bool, error) {
   329  				return informer.HasSynced(), nil
   330  			}
   331  
   332  			By(`wait until the informer has synced to continue`)
   333  			err := wait.PollUntil(500*time.Millisecond, synced, stopCh)
   334  			require.NoError(GinkgoT(), err)
   335  		}
   336  
   337  		ruleChecker := install.NewCSVRuleChecker(roleInformer.Lister(), roleBindingInformer.Lister(), clusterRoleInformer.Lister(), clusterRoleBindingInformer.Lister(), &aCSV)
   338  
   339  		log("Waiting for operator to have rbac in target namespace")
   340  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
   341  			for _, perm := range permissions {
   342  				sa, err := c.GetServiceAccount(opGroupNamespace, perm.ServiceAccountName)
   343  				require.NoError(GinkgoT(), err)
   344  				for _, rule := range perm.Rules {
   345  					satisfied, err := ruleChecker.RuleSatisfied(sa, otherNamespaceName, rule)
   346  					if err != nil {
   347  						GinkgoT().Log(err.Error())
   348  						return false, nil
   349  					}
   350  					if !satisfied {
   351  						return false, nil
   352  					}
   353  				}
   354  			}
   355  			return true, nil
   356  		})
   357  
   358  		By(`validate provided API clusterroles for the operatorgroup`)
   359  		existingClusterRoleList, err := c.KubernetesInterface().RbacV1().ClusterRoles().List(context.TODO(), metav1.ListOptions{
   360  			LabelSelector: labels.SelectorFromSet(ownerutil.OwnerLabel(&operatorGroup, "OperatorGroup")).String(),
   361  		})
   362  		require.NoError(GinkgoT(), err)
   363  		require.Len(GinkgoT(), existingClusterRoleList.Items, 3)
   364  
   365  		for _, role := range existingClusterRoleList.Items {
   366  			if strings.HasSuffix(role.Name, "admin") {
   367  				adminPolicyRules := []rbacv1.PolicyRule{
   368  					{Verbs: []string{"*"}, APIGroups: []string{mainCRD.Spec.Group}, Resources: []string{mainCRDPlural}},
   369  				}
   370  				if assert.Equal(GinkgoT(), adminPolicyRules, role.Rules) == false {
   371  					fmt.Println(cmp.Diff(adminPolicyRules, role.Rules))
   372  					GinkgoT().Fail()
   373  				}
   374  
   375  			} else if strings.HasSuffix(role.Name, "edit") {
   376  				editPolicyRules := []rbacv1.PolicyRule{
   377  					{Verbs: []string{"create", "update", "patch", "delete"}, APIGroups: []string{mainCRD.Spec.Group}, Resources: []string{mainCRDPlural}},
   378  				}
   379  				if assert.Equal(GinkgoT(), editPolicyRules, role.Rules) == false {
   380  					fmt.Println(cmp.Diff(editPolicyRules, role.Rules))
   381  					GinkgoT().Fail()
   382  				}
   383  			} else if strings.HasSuffix(role.Name, "view") {
   384  				viewPolicyRules := []rbacv1.PolicyRule{
   385  					{Verbs: []string{"get"}, APIGroups: []string{"apiextensions.k8s.io"}, Resources: []string{"customresourcedefinitions"}, ResourceNames: []string{mainCRD.Name}},
   386  					{Verbs: []string{"get", "list", "watch"}, APIGroups: []string{mainCRD.Spec.Group}, Resources: []string{mainCRDPlural}},
   387  				}
   388  				if assert.Equal(GinkgoT(), viewPolicyRules, role.Rules) == false {
   389  					fmt.Println(cmp.Diff(viewPolicyRules, role.Rules))
   390  					GinkgoT().Fail()
   391  				}
   392  			}
   393  		}
   394  
   395  		By(`Unsupport all InstallModes`)
   396  		log("unsupporting all csv installmodes")
   397  		fetchedCSV, err := crc.OperatorsV1alpha1().ClusterServiceVersions(opGroupNamespace).Get(context.TODO(), csvName, metav1.GetOptions{})
   398  		require.NoError(GinkgoT(), err, "could not fetch csv")
   399  		fetchedCSV.Spec.InstallModes = []v1alpha1.InstallMode{}
   400  		_, err = crc.OperatorsV1alpha1().ClusterServiceVersions(fetchedCSV.GetNamespace()).Update(context.TODO(), fetchedCSV, metav1.UpdateOptions{})
   401  		require.NoError(GinkgoT(), err, "could not update csv installmodes")
   402  
   403  		By(`Ensure CSV fails`)
   404  		_, err = fetchCSV(crc, opGroupNamespace, csvName, csvFailedChecker)
   405  		require.NoError(GinkgoT(), err, "csv did not transition to failed as expected")
   406  
   407  		By(`ensure deletion cleans up copied CSV`)
   408  		log("deleting parent csv")
   409  		err = crc.OperatorsV1alpha1().ClusterServiceVersions(opGroupNamespace).Delete(context.TODO(), csvName, metav1.DeleteOptions{})
   410  		require.NoError(GinkgoT(), err)
   411  
   412  		log("waiting for orphaned csv to be deleted")
   413  		err = waitForDelete(func() error {
   414  			_, err = crc.OperatorsV1alpha1().ClusterServiceVersions(otherNamespaceName).Get(context.TODO(), csvName, metav1.GetOptions{})
   415  			return err
   416  		})
   417  		require.NoError(GinkgoT(), err)
   418  
   419  		err = crc.OperatorsV1().OperatorGroups(opGroupNamespace).Delete(context.TODO(), operatorGroup.Name, metav1.DeleteOptions{})
   420  		require.NoError(GinkgoT(), err)
   421  		GinkgoT().Log("Waiting for OperatorGroup RBAC to be garbage collected")
   422  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
   423  			_, err := c.KubernetesInterface().RbacV1().ClusterRoles().Get(context.TODO(), operatorGroup.Name+"-admin", metav1.GetOptions{})
   424  			if err == nil {
   425  				return false, nil
   426  			}
   427  			return true, err
   428  		})
   429  		require.True(GinkgoT(), apierrors.IsNotFound(err))
   430  
   431  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
   432  			_, err := c.KubernetesInterface().RbacV1().ClusterRoles().Get(context.TODO(), operatorGroup.Name+"-edit", metav1.GetOptions{})
   433  			if err == nil {
   434  				return false, nil
   435  			}
   436  			return true, err
   437  		})
   438  		require.True(GinkgoT(), apierrors.IsNotFound(err))
   439  
   440  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
   441  			_, err := c.KubernetesInterface().RbacV1().ClusterRoles().Get(context.TODO(), operatorGroup.Name+"-view", metav1.GetOptions{})
   442  			if err == nil {
   443  				return false, nil
   444  			}
   445  			return true, err
   446  		})
   447  		require.True(GinkgoT(), apierrors.IsNotFound(err))
   448  	})
   449  	It("role aggregation", func() {
   450  
   451  		By(`kubectl -n a8v4sw  auth can-i create alp999.cluster.com --as system:serviceaccount:a8v4sw:padmin-xqdfz`)
   452  
   453  		By(`Generate namespaceA`)
   454  		By(`Generate operatorGroupA - OwnNamespace`)
   455  		By(`Generate csvA in namespaceA with all installmodes supported`)
   456  		By(`Create crd so csv succeeds`)
   457  		By(`Ensure clusterroles created and aggregated for access provided APIs`)
   458  
   459  		nsA := genName("a")
   460  		GinkgoT().Logf("generating namespaceA: %s", nsA)
   461  		c := newKubeClient()
   462  		for _, ns := range []string{nsA} {
   463  			namespace := &corev1.Namespace{
   464  				ObjectMeta: metav1.ObjectMeta{
   465  					Name: ns,
   466  				},
   467  			}
   468  			_, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), namespace, metav1.CreateOptions{})
   469  			require.NoError(GinkgoT(), err)
   470  			defer func(name string) {
   471  				require.NoError(GinkgoT(), c.KubernetesInterface().CoreV1().Namespaces().Delete(context.TODO(), name, metav1.DeleteOptions{}))
   472  			}(ns)
   473  		}
   474  
   475  		groupAName := genName("a")
   476  		GinkgoT().Logf("Generate operatorGroupA - OwnNamespace: %s", groupAName)
   477  		groupA := newOperatorGroup(nsA, groupAName, nil, nil, []string{nsA}, false)
   478  		_, err := crc.OperatorsV1().OperatorGroups(nsA).Create(context.TODO(), groupA, metav1.CreateOptions{})
   479  		require.NoError(GinkgoT(), err)
   480  		defer func() {
   481  			require.NoError(GinkgoT(), crc.OperatorsV1().OperatorGroups(nsA).Delete(context.TODO(), groupA.GetName(), metav1.DeleteOptions{}))
   482  		}()
   483  
   484  		crdAName := genName("a")
   485  		strategyName := genName("dep-")
   486  		csvAName := "nginx-a"
   487  		GinkgoT().Logf("Generate csv (%s/%s) with crd %s and with all installmodes supported: %s", nsA, csvAName, crdAName, strategyName)
   488  		crd := newCRD(crdAName)
   489  		namedStrategy := newNginxInstallStrategy(strategyName, nil, nil)
   490  		csvA := newCSV(csvAName, nsA, "", semver.MustParse("0.1.0"), []apiextensionsv1.CustomResourceDefinition{crd}, nil, &namedStrategy)
   491  		_, err = crc.OperatorsV1alpha1().ClusterServiceVersions(nsA).Create(context.TODO(), &csvA, metav1.CreateOptions{})
   492  		require.NoError(GinkgoT(), err)
   493  		defer func() {
   494  			require.NoError(GinkgoT(), crc.OperatorsV1alpha1().ClusterServiceVersions(nsA).Delete(context.TODO(), csvA.GetName(), metav1.DeleteOptions{}))
   495  		}()
   496  
   497  		GinkgoT().Logf("Create crd %s so csv %s/%s succeeds", crdAName, nsA, csvAName)
   498  		cleanupCRD, err := createCRD(c, crd)
   499  		require.NoError(GinkgoT(), err)
   500  		defer cleanupCRD()
   501  
   502  		_, err = fetchCSV(crc, nsA, csvA.GetName(), csvSucceededChecker)
   503  		require.NoError(GinkgoT(), err)
   504  
   505  		depName := genName("hat-server")
   506  		GinkgoT().Logf("Create csv %s/%s for an apiserver", nsA, depName)
   507  		mockGroup := fmt.Sprintf("hats.%s.redhat.com", genName(""))
   508  		version := "v1alpha1"
   509  		mockGroupVersion := strings.Join([]string{mockGroup, version}, "/")
   510  		mockKinds := []string{"fez", "fedora"}
   511  		mockNames := []string{"fezs", "fedoras"}
   512  		depSpec := newMockExtServerDeployment(depName, []mockGroupVersionKind{{depName, mockGroupVersion, mockKinds, 5443}})
   513  		strategy := v1alpha1.StrategyDetailsDeployment{
   514  			DeploymentSpecs: []v1alpha1.StrategyDeploymentSpec{
   515  				{
   516  					Name: depName,
   517  					Spec: depSpec,
   518  				},
   519  			},
   520  		}
   521  
   522  		owned := make([]v1alpha1.APIServiceDescription, len(mockKinds))
   523  		for i, kind := range mockKinds {
   524  			owned[i] = v1alpha1.APIServiceDescription{
   525  				Name:           mockNames[i],
   526  				Group:          mockGroup,
   527  				Version:        version,
   528  				Kind:           kind,
   529  				DeploymentName: depName,
   530  				ContainerPort:  int32(5443),
   531  				DisplayName:    kind,
   532  				Description:    fmt.Sprintf("A %s", kind),
   533  			}
   534  		}
   535  
   536  		csvB := v1alpha1.ClusterServiceVersion{
   537  			Spec: v1alpha1.ClusterServiceVersionSpec{
   538  				MinKubeVersion: "0.0.0",
   539  				InstallModes: []v1alpha1.InstallMode{
   540  					{
   541  						Type:      v1alpha1.InstallModeTypeOwnNamespace,
   542  						Supported: true,
   543  					},
   544  					{
   545  						Type:      v1alpha1.InstallModeTypeSingleNamespace,
   546  						Supported: true,
   547  					},
   548  					{
   549  						Type:      v1alpha1.InstallModeTypeMultiNamespace,
   550  						Supported: true,
   551  					},
   552  					{
   553  						Type:      v1alpha1.InstallModeTypeAllNamespaces,
   554  						Supported: true,
   555  					},
   556  				},
   557  				InstallStrategy: v1alpha1.NamedInstallStrategy{
   558  					StrategyName: v1alpha1.InstallStrategyNameDeployment,
   559  					StrategySpec: strategy,
   560  				},
   561  				APIServiceDefinitions: v1alpha1.APIServiceDefinitions{
   562  					Owned: owned,
   563  				},
   564  			},
   565  		}
   566  		csvB.SetName(depName)
   567  
   568  		GinkgoT().Logf("Create the APIService CSV %s/%s", nsA, depName)
   569  		cleanupCSV, err := createCSV(c, crc, csvB, nsA, false, true)
   570  		require.NoError(GinkgoT(), err)
   571  		defer cleanupCSV()
   572  
   573  		GinkgoT().Logf("Fetch the APIService CSV %s/%s", nsA, depName)
   574  		_, err = fetchCSV(crc, nsA, csvB.GetName(), csvSucceededChecker)
   575  		require.NoError(GinkgoT(), err)
   576  
   577  		GinkgoT().Logf("Ensure clusterroles created and aggregated for access provided APIs")
   578  		padmin, cleanupPadmin := createProjectAdmin(GinkgoT(), c, nsA)
   579  		defer cleanupPadmin()
   580  
   581  		GinkgoT().Logf("Check CRD access aggregated")
   582  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
   583  			res, err := c.KubernetesInterface().AuthorizationV1().SubjectAccessReviews().Create(context.TODO(), &authorizationv1.SubjectAccessReview{
   584  				Spec: authorizationv1.SubjectAccessReviewSpec{
   585  					User: padmin,
   586  					ResourceAttributes: &authorizationv1.ResourceAttributes{
   587  						Namespace: nsA,
   588  						Group:     crd.Spec.Group,
   589  						Version:   crd.Spec.Versions[0].Name,
   590  						Resource:  crd.Spec.Names.Plural,
   591  						Verb:      "create",
   592  					},
   593  				},
   594  			}, metav1.CreateOptions{})
   595  			if err != nil {
   596  				return false, err
   597  			}
   598  			if res == nil {
   599  				return false, nil
   600  			}
   601  			GinkgoT().Logf("checking padmin for permission: %#v", res)
   602  			return res.Status.Allowed, nil
   603  		})
   604  		require.NoError(GinkgoT(), err)
   605  
   606  		GinkgoT().Logf("Check apiserver access aggregated")
   607  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
   608  			res, err := c.KubernetesInterface().AuthorizationV1().SubjectAccessReviews().Create(context.TODO(), &authorizationv1.SubjectAccessReview{
   609  				Spec: authorizationv1.SubjectAccessReviewSpec{
   610  					User: padmin,
   611  					ResourceAttributes: &authorizationv1.ResourceAttributes{
   612  						Namespace: nsA,
   613  						Group:     mockGroup,
   614  						Version:   version,
   615  						Resource:  mockNames[1],
   616  						Verb:      "create",
   617  					},
   618  				},
   619  			}, metav1.CreateOptions{})
   620  			if err != nil {
   621  				return false, err
   622  			}
   623  			if res == nil {
   624  				return false, nil
   625  			}
   626  			GinkgoT().Logf("checking padmin for permission: %#v", res)
   627  			return res.Status.Allowed, nil
   628  		})
   629  		require.NoError(GinkgoT(), err)
   630  	})
   631  	It("install mode support", func() {
   632  
   633  		By(`Generate namespaceA`)
   634  		By(`Generate namespaceB`)
   635  		By(`Create operatorGroupA in namespaceA that selects namespaceA`)
   636  		By(`Generate csvA with an unfulfilled required CRD and no supported InstallModes in namespaceA`)
   637  		By(`Ensure csvA transitions to Failed with reason "UnsupportedOperatorGroup"`)
   638  		By(`Update csvA to have OwnNamespace supported=true`)
   639  		By(`Ensure csvA transitions to Succeeded`)
   640  		By(`Update operatorGroupA's target namespaces to select namespaceB`)
   641  		By(`Ensure csvA transitions to Failed with reason "UnsupportedOperatorGroup"`)
   642  		By(`Update csvA to have SingleNamespace supported=true`)
   643  		By(`Ensure csvA transitions to Pending`)
   644  		By(`Update operatorGroupA's target namespaces to select namespaceA and namespaceB`)
   645  		By(`Ensure csvA transitions to Failed with reason "UnsupportedOperatorGroup"`)
   646  		By(`Update csvA to have MultiNamespace supported=true`)
   647  		By(`Ensure csvA transitions to Pending`)
   648  		By(`Update operatorGroupA to select all namespaces`)
   649  		By(`Ensure csvA transitions to Failed with reason "UnsupportedOperatorGroup"`)
   650  		By(`Update csvA to have AllNamespaces supported=true`)
   651  		By(`Ensure csvA transitions to Pending`)
   652  
   653  		By(`Generate namespaceA and namespaceB`)
   654  		nsA := genName("a")
   655  		nsB := genName("b")
   656  
   657  		c := newKubeClient()
   658  		for _, ns := range []string{nsA, nsB} {
   659  			namespace := &corev1.Namespace{
   660  				ObjectMeta: metav1.ObjectMeta{
   661  					Name: ns,
   662  				},
   663  			}
   664  			_, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), namespace, metav1.CreateOptions{})
   665  			require.NoError(GinkgoT(), err)
   666  			defer func(name string) {
   667  				require.NoError(GinkgoT(), c.KubernetesInterface().CoreV1().Namespaces().Delete(context.TODO(), name, metav1.DeleteOptions{}))
   668  			}(ns)
   669  		}
   670  
   671  		By(`Generate operatorGroupA`)
   672  		groupA := newOperatorGroup(nsA, genName("a"), nil, nil, []string{nsA}, false)
   673  		_, err := crc.OperatorsV1().OperatorGroups(nsA).Create(context.TODO(), groupA, metav1.CreateOptions{})
   674  		require.NoError(GinkgoT(), err)
   675  		defer func() {
   676  			require.NoError(GinkgoT(), crc.OperatorsV1().OperatorGroups(nsA).Delete(context.TODO(), groupA.GetName(), metav1.DeleteOptions{}))
   677  		}()
   678  
   679  		By(`Generate csvA in namespaceA with no supported InstallModes`)
   680  		crd := newCRD(genName("b"))
   681  		namedStrategy := newNginxInstallStrategy(genName("dep-"), nil, nil)
   682  		csv := newCSV("nginx-a", nsA, "", semver.MustParse("0.1.0"), nil, []apiextensionsv1.CustomResourceDefinition{crd}, &namedStrategy)
   683  		csvA := &csv
   684  		csvA.Spec.InstallModes = []v1alpha1.InstallMode{
   685  			{
   686  				Type:      v1alpha1.InstallModeTypeOwnNamespace,
   687  				Supported: false,
   688  			},
   689  			{
   690  				Type:      v1alpha1.InstallModeTypeSingleNamespace,
   691  				Supported: false,
   692  			},
   693  			{
   694  				Type:      v1alpha1.InstallModeTypeMultiNamespace,
   695  				Supported: false,
   696  			},
   697  			{
   698  				Type:      v1alpha1.InstallModeTypeAllNamespaces,
   699  				Supported: false,
   700  			},
   701  		}
   702  		csvA, err = crc.OperatorsV1alpha1().ClusterServiceVersions(nsA).Create(context.TODO(), csvA, metav1.CreateOptions{})
   703  		require.NoError(GinkgoT(), err)
   704  		defer func() {
   705  			require.NoError(GinkgoT(), crc.OperatorsV1alpha1().ClusterServiceVersions(nsA).Delete(context.TODO(), csvA.GetName(), metav1.DeleteOptions{}))
   706  		}()
   707  
   708  		By(`Ensure csvA transitions to Failed with reason "UnsupportedOperatorGroup"`)
   709  		failedWithUnsupportedOperatorGroup := func(csv *v1alpha1.ClusterServiceVersion) bool {
   710  			return csvFailedChecker(csv) && csv.Status.Reason == v1alpha1.CSVReasonUnsupportedOperatorGroup
   711  		}
   712  		csvA, err = fetchCSV(crc, nsA, csvA.GetName(), failedWithUnsupportedOperatorGroup)
   713  		require.NoError(GinkgoT(), err)
   714  
   715  		By(`Update csvA to have OwnNamespace supported=true`)
   716  		csvA.Spec.InstallModes = []v1alpha1.InstallMode{
   717  			{
   718  				Type:      v1alpha1.InstallModeTypeOwnNamespace,
   719  				Supported: true,
   720  			},
   721  			{
   722  				Type:      v1alpha1.InstallModeTypeSingleNamespace,
   723  				Supported: false,
   724  			},
   725  			{
   726  				Type:      v1alpha1.InstallModeTypeMultiNamespace,
   727  				Supported: false,
   728  			},
   729  			{
   730  				Type:      v1alpha1.InstallModeTypeAllNamespaces,
   731  				Supported: false,
   732  			},
   733  		}
   734  		_, err = crc.OperatorsV1alpha1().ClusterServiceVersions(nsA).Update(context.TODO(), csvA, metav1.UpdateOptions{})
   735  		require.NoError(GinkgoT(), err)
   736  
   737  		By(`Create crd so csv succeeds`)
   738  		cleanupCRD, err := createCRD(c, crd)
   739  		require.NoError(GinkgoT(), err)
   740  		defer cleanupCRD()
   741  
   742  		By(`Ensure csvA transitions to Succeeded`)
   743  		csvA, err = fetchCSV(crc, nsA, csvA.GetName(), csvSucceededChecker)
   744  		require.NoError(GinkgoT(), err)
   745  
   746  		By(`Update operatorGroupA's target namespaces to select namespaceB`)
   747  		groupA, err = crc.OperatorsV1().OperatorGroups(nsA).Get(context.TODO(), groupA.GetName(), metav1.GetOptions{})
   748  		require.NoError(GinkgoT(), err)
   749  		groupA.Spec.TargetNamespaces = []string{nsB}
   750  		_, err = crc.OperatorsV1().OperatorGroups(nsA).Update(context.TODO(), groupA, metav1.UpdateOptions{})
   751  		require.NoError(GinkgoT(), err)
   752  
   753  		By(`Ensure csvA transitions to Failed with reason "UnsupportedOperatorGroup"`)
   754  		csvA, err = fetchCSV(crc, nsA, csvA.GetName(), failedWithUnsupportedOperatorGroup)
   755  		require.NoError(GinkgoT(), err)
   756  
   757  		By(`Update csvA to have SingleNamespace supported=true`)
   758  		csvA.Spec.InstallModes = []v1alpha1.InstallMode{
   759  			{
   760  				Type:      v1alpha1.InstallModeTypeOwnNamespace,
   761  				Supported: true,
   762  			},
   763  			{
   764  				Type:      v1alpha1.InstallModeTypeSingleNamespace,
   765  				Supported: true,
   766  			},
   767  			{
   768  				Type:      v1alpha1.InstallModeTypeMultiNamespace,
   769  				Supported: false,
   770  			},
   771  			{
   772  				Type:      v1alpha1.InstallModeTypeAllNamespaces,
   773  				Supported: false,
   774  			},
   775  		}
   776  		_, err = crc.OperatorsV1alpha1().ClusterServiceVersions(nsA).Update(context.TODO(), csvA, metav1.UpdateOptions{})
   777  		require.NoError(GinkgoT(), err)
   778  
   779  		By(`Ensure csvA transitions to Succeeded`)
   780  		csvA, err = fetchCSV(crc, nsA, csvA.GetName(), csvSucceededChecker)
   781  		require.NoError(GinkgoT(), err)
   782  
   783  		By(`Update operatorGroupA's target namespaces to select namespaceA and namespaceB`)
   784  		groupA, err = crc.OperatorsV1().OperatorGroups(nsA).Get(context.TODO(), groupA.GetName(), metav1.GetOptions{})
   785  		require.NoError(GinkgoT(), err)
   786  		groupA.Spec.TargetNamespaces = []string{nsA, nsB}
   787  		_, err = crc.OperatorsV1().OperatorGroups(nsA).Update(context.TODO(), groupA, metav1.UpdateOptions{})
   788  		require.NoError(GinkgoT(), err)
   789  
   790  		By(`Ensure csvA transitions to Failed with reason "UnsupportedOperatorGroup"`)
   791  		csvA, err = fetchCSV(crc, nsA, csvA.GetName(), failedWithUnsupportedOperatorGroup)
   792  		require.NoError(GinkgoT(), err)
   793  
   794  		By(`Update csvA to have MultiNamespace supported=true`)
   795  		csvA.Spec.InstallModes = []v1alpha1.InstallMode{
   796  			{
   797  				Type:      v1alpha1.InstallModeTypeOwnNamespace,
   798  				Supported: true,
   799  			},
   800  			{
   801  				Type:      v1alpha1.InstallModeTypeSingleNamespace,
   802  				Supported: true,
   803  			},
   804  			{
   805  				Type:      v1alpha1.InstallModeTypeMultiNamespace,
   806  				Supported: true,
   807  			},
   808  			{
   809  				Type:      v1alpha1.InstallModeTypeAllNamespaces,
   810  				Supported: false,
   811  			},
   812  		}
   813  		_, err = crc.OperatorsV1alpha1().ClusterServiceVersions(nsA).Update(context.TODO(), csvA, metav1.UpdateOptions{})
   814  		require.NoError(GinkgoT(), err)
   815  
   816  		By(`Ensure csvA transitions to Succeeded`)
   817  		csvA, err = fetchCSV(crc, nsA, csvA.GetName(), csvSucceededChecker)
   818  		require.NoError(GinkgoT(), err)
   819  
   820  		By(`Update operatorGroupA's target namespaces to select all namespaces`)
   821  		groupA, err = crc.OperatorsV1().OperatorGroups(nsA).Get(context.TODO(), groupA.GetName(), metav1.GetOptions{})
   822  		require.NoError(GinkgoT(), err)
   823  		groupA.Spec.TargetNamespaces = []string{}
   824  		_, err = crc.OperatorsV1().OperatorGroups(nsA).Update(context.TODO(), groupA, metav1.UpdateOptions{})
   825  		require.NoError(GinkgoT(), err)
   826  
   827  		By(`Ensure csvA transitions to Failed with reason "UnsupportedOperatorGroup"`)
   828  		csvA, err = fetchCSV(crc, nsA, csvA.GetName(), failedWithUnsupportedOperatorGroup)
   829  		require.NoError(GinkgoT(), err)
   830  
   831  		By(`Update csvA to have AllNamespaces supported=true`)
   832  		csvA.Spec.InstallModes = []v1alpha1.InstallMode{
   833  			{
   834  				Type:      v1alpha1.InstallModeTypeOwnNamespace,
   835  				Supported: true,
   836  			},
   837  			{
   838  				Type:      v1alpha1.InstallModeTypeSingleNamespace,
   839  				Supported: true,
   840  			},
   841  			{
   842  				Type:      v1alpha1.InstallModeTypeMultiNamespace,
   843  				Supported: true,
   844  			},
   845  			{
   846  				Type:      v1alpha1.InstallModeTypeAllNamespaces,
   847  				Supported: true,
   848  			},
   849  		}
   850  		_, err = crc.OperatorsV1alpha1().ClusterServiceVersions(nsA).Update(context.TODO(), csvA, metav1.UpdateOptions{})
   851  		require.NoError(GinkgoT(), err)
   852  
   853  		By(`Ensure csvA transitions to Pending`)
   854  		csvA, err = fetchCSV(crc, nsA, csvA.GetName(), csvSucceededChecker)
   855  		require.NoError(GinkgoT(), err)
   856  	})
   857  	It("[FLAKE] intersection", func() {
   858  
   859  		By(`Generate namespaceA`)
   860  		By(`Generate namespaceB`)
   861  		By(`Generate namespaceC`)
   862  		By(`Generate namespaceD`)
   863  		By(`Generate namespaceE`)
   864  		By(`Generate operatorGroupD in namespaceD that selects namespace D and E`)
   865  		By(`Generate csvD in namespaceD`)
   866  		By(`Wait for csvD to be successful`)
   867  		By(`Wait for csvD to have a CSV with copied status in namespace E`)
   868  		By(`Wait for operatorGroupD to have providedAPI annotation with crdD's Kind.version.group`)
   869  		By(`Generate operatorGroupA in namespaceA that selects AllNamespaces`)
   870  		By(`Generate csvD in namespaceA`)
   871  		By(`Wait for csvD to fail with status "InterOperatorGroupOwnerConflict"`)
   872  		By(`Ensure operatorGroupA's providedAPIs are empty`)
   873  		By(`Ensure csvD in namespaceD is still successful`)
   874  		By(`Generate csvA in namespaceA that owns crdA`)
   875  		By(`Wait for csvA to be successful`)
   876  		By(`Ensure clusterroles created and aggregated for accessing provided APIs`)
   877  		By(`Wait for operatorGroupA to have providedAPI annotation with crdA's Kind.version.group in its providedAPIs annotation`)
   878  		By(`Wait for csvA to have a CSV with copied status in namespace D`)
   879  		By(`Ensure csvA retains the operatorgroup annotations for operatorgroupA`)
   880  		By(`Wait for csvA to have a CSV with copied status in namespace C`)
   881  		By(`Generate operatorGroupB in namespaceB that selects namespace C`)
   882  		By(`Generate csvB in namespaceB that owns crdA`)
   883  		By(`Wait for csvB to fail with status "InterOperatorGroupOwnerConflict"`)
   884  		By(`Delete csvA`)
   885  		By(`Wait for crdA's Kind.version.group to be removed from operatorGroupA's providedAPIs annotation`)
   886  		By(`Ensure csvA's deployments are deleted`)
   887  		By(`Wait for csvB to be successful`)
   888  		By(`Wait for operatorGroupB to have providedAPI annotation with crdB's Kind.version.group`)
   889  		By(`Wait for csvB to have a CSV with a copied status in namespace C`)
   890  
   891  		By(`Create a catalog for csvA, csvB, and csvD`)
   892  		pkgA := genName("a-")
   893  		pkgB := genName("b-")
   894  		pkgD := genName("d-")
   895  		pkgAStable := pkgA + "-stable"
   896  		pkgBStable := pkgB + "-stable"
   897  		pkgDStable := pkgD + "-stable"
   898  		stableChannel := "stable"
   899  		strategyA := newNginxInstallStrategy(pkgAStable, nil, nil)
   900  		strategyB := newNginxInstallStrategy(pkgBStable, nil, nil)
   901  		strategyD := newNginxInstallStrategy(pkgDStable, nil, nil)
   902  		crdA := newCRD(genName(pkgA))
   903  		crdB := newCRD(genName(pkgB))
   904  		crdD := newCRD(genName(pkgD))
   905  		kvgA := fmt.Sprintf("%s.%s.%s", crdA.Spec.Names.Kind, crdA.Spec.Versions[0].Name, crdA.Spec.Group)
   906  		kvgB := fmt.Sprintf("%s.%s.%s", crdB.Spec.Names.Kind, crdB.Spec.Versions[0].Name, crdB.Spec.Group)
   907  		kvgD := fmt.Sprintf("%s.%s.%s", crdD.Spec.Names.Kind, crdD.Spec.Versions[0].Name, crdD.Spec.Group)
   908  		csvA := newCSV(pkgAStable, generatedNamespace.GetName(), "", semver.MustParse("0.1.0"), []apiextensionsv1.CustomResourceDefinition{crdA}, nil, &strategyA)
   909  		csvB := newCSV(pkgBStable, generatedNamespace.GetName(), "", semver.MustParse("0.1.0"), []apiextensionsv1.CustomResourceDefinition{crdA, crdB}, nil, &strategyB)
   910  		csvD := newCSV(pkgDStable, generatedNamespace.GetName(), "", semver.MustParse("0.1.0"), []apiextensionsv1.CustomResourceDefinition{crdD}, nil, &strategyD)
   911  
   912  		By(`Create namespaces`)
   913  		nsA, nsB, nsC, nsD, nsE := genName("a-"), genName("b-"), genName("c-"), genName("d-"), genName("e-")
   914  		for _, ns := range []string{nsA, nsB, nsC, nsD, nsE} {
   915  			namespace := &corev1.Namespace{
   916  				ObjectMeta: metav1.ObjectMeta{
   917  					Name: ns,
   918  				},
   919  			}
   920  			_, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), namespace, metav1.CreateOptions{})
   921  			require.NoError(GinkgoT(), err)
   922  			defer func(name string) {
   923  				require.NoError(GinkgoT(), c.KubernetesInterface().CoreV1().Namespaces().Delete(context.TODO(), name, metav1.DeleteOptions{}))
   924  			}(ns)
   925  		}
   926  
   927  		By(`Create the initial catalogsources`)
   928  		manifests := []registry.PackageManifest{
   929  			{
   930  				PackageName: pkgA,
   931  				Channels: []registry.PackageChannel{
   932  					{Name: stableChannel, CurrentCSVName: pkgAStable},
   933  				},
   934  				DefaultChannelName: stableChannel,
   935  			},
   936  			{
   937  				PackageName: pkgB,
   938  				Channels: []registry.PackageChannel{
   939  					{Name: stableChannel, CurrentCSVName: pkgBStable},
   940  				},
   941  				DefaultChannelName: stableChannel,
   942  			},
   943  			{
   944  				PackageName: pkgD,
   945  				Channels: []registry.PackageChannel{
   946  					{Name: stableChannel, CurrentCSVName: pkgDStable},
   947  				},
   948  				DefaultChannelName: stableChannel,
   949  			},
   950  		}
   951  
   952  		catalog := genName("catalog-")
   953  		_, cleanupCatalogSource := createInternalCatalogSource(c, crc, catalog, nsA, manifests, []apiextensionsv1.CustomResourceDefinition{crdA, crdD, crdB}, []v1alpha1.ClusterServiceVersion{csvA, csvB, csvD})
   954  		defer cleanupCatalogSource()
   955  		_, err := fetchCatalogSourceOnStatus(crc, catalog, nsA, catalogSourceRegistryPodSynced())
   956  		require.NoError(GinkgoT(), err)
   957  		_, cleanupCatalogSource = createInternalCatalogSource(c, crc, catalog, nsB, manifests, []apiextensionsv1.CustomResourceDefinition{crdA, crdD, crdB}, []v1alpha1.ClusterServiceVersion{csvA, csvB, csvD})
   958  		defer cleanupCatalogSource()
   959  		_, err = fetchCatalogSourceOnStatus(crc, catalog, nsB, catalogSourceRegistryPodSynced())
   960  		require.NoError(GinkgoT(), err)
   961  		_, cleanupCatalogSource = createInternalCatalogSource(c, crc, catalog, nsD, manifests, []apiextensionsv1.CustomResourceDefinition{crdA, crdD, crdB}, []v1alpha1.ClusterServiceVersion{csvA, csvB, csvD})
   962  		defer cleanupCatalogSource()
   963  		_, err = fetchCatalogSourceOnStatus(crc, catalog, nsD, catalogSourceRegistryPodSynced())
   964  		require.NoError(GinkgoT(), err)
   965  
   966  		By(`Create operatorgroups`)
   967  		groupA := newOperatorGroup(nsA, genName("a-"), nil, nil, nil, false)
   968  		groupB := newOperatorGroup(nsB, genName("b-"), nil, nil, []string{nsC}, false)
   969  		groupD := newOperatorGroup(nsD, genName("d-"), nil, nil, []string{nsD, nsE}, false)
   970  		for _, group := range []*v1.OperatorGroup{groupA, groupB, groupD} {
   971  			_, err := crc.OperatorsV1().OperatorGroups(group.GetNamespace()).Create(context.TODO(), group, metav1.CreateOptions{})
   972  			require.NoError(GinkgoT(), err)
   973  			defer func(namespace, name string) {
   974  				require.NoError(GinkgoT(), crc.OperatorsV1().OperatorGroups(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{}))
   975  			}(group.GetNamespace(), group.GetName())
   976  		}
   977  
   978  		By(`Create subscription for csvD in namespaceD`)
   979  		subDName := genName("d-")
   980  		cleanupSubD := createSubscriptionForCatalog(crc, nsD, subDName, catalog, pkgD, stableChannel, pkgDStable, v1alpha1.ApprovalAutomatic)
   981  		defer cleanupSubD()
   982  		subD, err := fetchSubscription(crc, nsD, subDName, subscriptionHasInstallPlanChecker())
   983  		require.NoError(GinkgoT(), err)
   984  		require.NotNil(GinkgoT(), subD)
   985  
   986  		By(`Await csvD's success`)
   987  		_, err = fetchCSV(crc, nsD, csvD.GetName(), csvSucceededChecker)
   988  		require.NoError(GinkgoT(), err)
   989  
   990  		By(`Await csvD's copy in namespaceE`)
   991  		_, err = fetchCSV(crc, nsE, csvD.GetName(), csvCopiedChecker)
   992  		require.NoError(GinkgoT(), err)
   993  
   994  		By(`Await annotation on groupD`)
   995  		q := func() (metav1.ObjectMeta, error) {
   996  			g, err := crc.OperatorsV1().OperatorGroups(nsD).Get(context.TODO(), groupD.GetName(), metav1.GetOptions{})
   997  			return g.ObjectMeta, err
   998  		}
   999  		require.NoError(GinkgoT(), awaitAnnotations(GinkgoT(), q, map[string]string{v1.OperatorGroupProvidedAPIsAnnotationKey: kvgD}))
  1000  
  1001  		By(`Create subscription for csvD2 in namespaceA`)
  1002  		subD2Name := genName("d2-")
  1003  		cleanupSubD2 := createSubscriptionForCatalog(crc, nsA, subD2Name, catalog, pkgD, stableChannel, pkgDStable, v1alpha1.ApprovalAutomatic)
  1004  		defer cleanupSubD2()
  1005  		subD2, err := fetchSubscription(crc, nsA, subD2Name, subscriptionHasInstallPlanChecker())
  1006  		require.NoError(GinkgoT(), err)
  1007  		require.NotNil(GinkgoT(), subD2)
  1008  
  1009  		By(`Await csvD2's failure`)
  1010  		csvD2, err := fetchCSV(crc, nsA, csvD.GetName(), csvFailedChecker)
  1011  		require.NoError(GinkgoT(), err)
  1012  		require.Equal(GinkgoT(), v1alpha1.CSVReasonInterOperatorGroupOwnerConflict, csvD2.Status.Reason)
  1013  
  1014  		By(`Ensure groupA's annotations are blank`)
  1015  		q = func() (metav1.ObjectMeta, error) {
  1016  			g, err := crc.OperatorsV1().OperatorGroups(nsA).Get(context.TODO(), groupA.GetName(), metav1.GetOptions{})
  1017  			return g.ObjectMeta, err
  1018  		}
  1019  		require.NoError(GinkgoT(), awaitAnnotations(GinkgoT(), q, map[string]string{}))
  1020  
  1021  		By(`Ensure csvD is still successful`)
  1022  		_, err = fetchCSV(crc, nsD, csvD.GetName(), csvSucceededChecker)
  1023  		require.NoError(GinkgoT(), err)
  1024  
  1025  		By(`Create subscription for csvA in namespaceA`)
  1026  		subAName := genName("a-")
  1027  		cleanupSubA := createSubscriptionForCatalog(crc, nsA, subAName, catalog, pkgA, stableChannel, pkgAStable, v1alpha1.ApprovalAutomatic)
  1028  		defer cleanupSubA()
  1029  		subA, err := fetchSubscription(crc, nsA, subAName, subscriptionHasInstallPlanChecker())
  1030  		require.NoError(GinkgoT(), err)
  1031  		require.NotNil(GinkgoT(), subA)
  1032  
  1033  		By(`Await csvA's success`)
  1034  		_, err = fetchCSV(crc, nsA, csvA.GetName(), csvSucceededChecker)
  1035  		require.NoError(GinkgoT(), err)
  1036  
  1037  		By(`Ensure clusterroles created and aggregated for access provided APIs`)
  1038  		padmin, cleanupPadmin := createProjectAdmin(GinkgoT(), c, nsA)
  1039  		defer cleanupPadmin()
  1040  
  1041  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
  1042  			res, err := c.KubernetesInterface().AuthorizationV1().SubjectAccessReviews().Create(context.TODO(), &authorizationv1.SubjectAccessReview{
  1043  				Spec: authorizationv1.SubjectAccessReviewSpec{
  1044  					User: padmin,
  1045  					ResourceAttributes: &authorizationv1.ResourceAttributes{
  1046  						Namespace: nsA,
  1047  						Group:     crdA.Spec.Group,
  1048  						Version:   crdA.Spec.Versions[0].Name,
  1049  						Resource:  crdA.Spec.Names.Plural,
  1050  						Verb:      "create",
  1051  					},
  1052  				},
  1053  			}, metav1.CreateOptions{})
  1054  			if err != nil {
  1055  				return false, err
  1056  			}
  1057  			if res == nil {
  1058  				return false, nil
  1059  			}
  1060  			GinkgoT().Log("checking padmin for permission")
  1061  			return res.Status.Allowed, nil
  1062  		})
  1063  		require.NoError(GinkgoT(), err)
  1064  
  1065  		By(`Await annotation on groupA`)
  1066  		q = func() (metav1.ObjectMeta, error) {
  1067  			g, err := crc.OperatorsV1().OperatorGroups(nsA).Get(context.TODO(), groupA.GetName(), metav1.GetOptions{})
  1068  			return g.ObjectMeta, err
  1069  		}
  1070  		require.NoError(GinkgoT(), awaitAnnotations(GinkgoT(), q, map[string]string{v1.OperatorGroupProvidedAPIsAnnotationKey: kvgA}))
  1071  
  1072  		By(`Wait for csvA to have a CSV with copied status in namespace D`)
  1073  		csvAinNsD, err := fetchCSV(crc, nsD, csvA.GetName(), csvCopiedChecker)
  1074  		require.NoError(GinkgoT(), err)
  1075  
  1076  		By(`trigger a resync of operatorgropuD`)
  1077  		fetchedGroupD, err := crc.OperatorsV1().OperatorGroups(nsD).Get(context.TODO(), groupD.GetName(), metav1.GetOptions{})
  1078  		require.NoError(GinkgoT(), err)
  1079  
  1080  		fetchedGroupD.Annotations["bump"] = "update"
  1081  		_, err = crc.OperatorsV1().OperatorGroups(nsD).Update(context.TODO(), fetchedGroupD, metav1.UpdateOptions{})
  1082  		require.NoError(GinkgoT(), err)
  1083  
  1084  		By(`Ensure csvA retains the operatorgroup annotations for operatorgroupA`)
  1085  		csvAinNsD, err = fetchCSV(crc, nsD, csvA.GetName(), csvCopiedChecker)
  1086  		require.NoError(GinkgoT(), err)
  1087  
  1088  		require.Equal(GinkgoT(), groupA.GetName(), csvAinNsD.Annotations[v1.OperatorGroupAnnotationKey])
  1089  		require.Equal(GinkgoT(), nsA, csvAinNsD.Annotations[v1.OperatorGroupNamespaceAnnotationKey])
  1090  		require.Equal(GinkgoT(), nsA, csvAinNsD.Labels[v1alpha1.CopiedLabelKey])
  1091  
  1092  		By(`Await csvA's copy in namespaceC`)
  1093  		_, err = fetchCSV(crc, nsC, csvA.GetName(), csvCopiedChecker)
  1094  		require.NoError(GinkgoT(), err)
  1095  
  1096  		By(`Create subscription for csvB in namespaceB`)
  1097  		subBName := genName("b-")
  1098  		cleanupSubB := createSubscriptionForCatalog(crc, nsB, subBName, catalog, pkgB, stableChannel, pkgBStable, v1alpha1.ApprovalAutomatic)
  1099  		defer cleanupSubB()
  1100  		subB, err := fetchSubscription(crc, nsB, subBName, subscriptionHasInstallPlanChecker())
  1101  		require.NoError(GinkgoT(), err)
  1102  		require.NotNil(GinkgoT(), subB)
  1103  
  1104  		By(`Await csvB's failure`)
  1105  		fetchedB, err := fetchCSV(crc, nsB, csvB.GetName(), csvFailedChecker)
  1106  		require.NoError(GinkgoT(), err)
  1107  		require.Equal(GinkgoT(), v1alpha1.CSVReasonInterOperatorGroupOwnerConflict, fetchedB.Status.Reason)
  1108  
  1109  		By(`Ensure no annotation on groupB`)
  1110  		q = func() (metav1.ObjectMeta, error) {
  1111  			g, err := crc.OperatorsV1().OperatorGroups(nsB).Get(context.TODO(), groupB.GetName(), metav1.GetOptions{})
  1112  			return g.ObjectMeta, err
  1113  		}
  1114  		require.NoError(GinkgoT(), awaitAnnotations(GinkgoT(), q, map[string]string{}))
  1115  
  1116  		By(`Delete csvA`)
  1117  		require.NoError(GinkgoT(), crc.OperatorsV1alpha1().ClusterServiceVersions(nsA).Delete(context.TODO(), csvA.GetName(), metav1.DeleteOptions{}))
  1118  
  1119  		By(`Ensure annotations are removed from groupA`)
  1120  		q = func() (metav1.ObjectMeta, error) {
  1121  			g, err := crc.OperatorsV1().OperatorGroups(nsA).Get(context.TODO(), groupA.GetName(), metav1.GetOptions{})
  1122  			return g.ObjectMeta, err
  1123  		}
  1124  		require.NoError(GinkgoT(), awaitAnnotations(GinkgoT(), q, map[string]string{v1.OperatorGroupProvidedAPIsAnnotationKey: ""}))
  1125  
  1126  		By(`Ensure csvA's deployment is deleted`)
  1127  		require.NoError(GinkgoT(), waitForDeploymentToDelete(generatedNamespace.GetName(), pkgAStable, c))
  1128  
  1129  		By(`Await csvB's success`)
  1130  		_, err = fetchCSV(crc, nsB, csvB.GetName(), csvSucceededChecker)
  1131  		require.NoError(GinkgoT(), err)
  1132  
  1133  		By(`Await csvB's copy in namespace C`)
  1134  		_, err = fetchCSV(crc, nsC, csvB.GetName(), csvCopiedChecker)
  1135  		require.NoError(GinkgoT(), err)
  1136  
  1137  		By(`Ensure annotations exist on group B`)
  1138  		q = func() (metav1.ObjectMeta, error) {
  1139  			g, err := crc.OperatorsV1().OperatorGroups(nsB).Get(context.TODO(), groupB.GetName(), metav1.GetOptions{})
  1140  			return g.ObjectMeta, err
  1141  		}
  1142  		require.NoError(GinkgoT(), awaitAnnotations(GinkgoT(), q, map[string]string{v1.OperatorGroupProvidedAPIsAnnotationKey: strings.Join([]string{kvgA, kvgB}, ",")}))
  1143  	})
  1144  	It("static provider", func() {
  1145  
  1146  		By(`Generate namespaceA`)
  1147  		By(`Generate namespaceB`)
  1148  		By(`Generate namespaceC`)
  1149  		By(`Generate namespaceD`)
  1150  		By(`Create static operatorGroupA in namespaceA that targets namespaceD with providedAPIs annotation containing KindA.version.group`)
  1151  		By(`Create operatorGroupB in namespaceB that targets all namespaces`)
  1152  		By(`Create operatorGroupC in namespaceC that targets namespaceC`)
  1153  		By(`Create csvA in namespaceB that provides KindA.version.group`)
  1154  		By(`Wait for csvA in namespaceB to fail`)
  1155  		By(`Ensure no providedAPI annotations on operatorGroupB`)
  1156  		By(`Ensure providedAPI annotations are unchanged on operatorGroupA`)
  1157  		By(`Create csvA in namespaceC`)
  1158  		By(`Wait for csvA in namespaceC to succeed`)
  1159  		By(`Ensure KindA.version.group providedAPI annotation on operatorGroupC`)
  1160  		By(`Create csvB in namespaceB that provides KindB.version.group`)
  1161  		By(`Wait for csvB to succeed`)
  1162  		By(`Wait for csvB to be copied to namespaceA, namespaceC, and namespaceD`)
  1163  		By(`Wait for KindB.version.group to exist in operatorGroupB's providedAPIs annotation`)
  1164  		By(`Add namespaceD to operatorGroupC's targetNamespaces`)
  1165  		By(`Wait for csvA in namespaceC to FAIL with status "InterOperatorGroupOwnerConflict"`)
  1166  		By(`Wait for KindA.version.group providedAPI annotation to be removed from operatorGroupC's providedAPIs annotation`)
  1167  		By(`Ensure KindA.version.group providedAPI annotation on operatorGroupA`)
  1168  
  1169  		By(`Create a catalog for csvA, csvB`)
  1170  		pkgA := genName("a-")
  1171  		pkgB := genName("b-")
  1172  		pkgAStable := pkgA + "-stable"
  1173  		pkgBStable := pkgB + "-stable"
  1174  		stableChannel := "stable"
  1175  		strategyA := newNginxInstallStrategy(pkgAStable, nil, nil)
  1176  		strategyB := newNginxInstallStrategy(pkgBStable, nil, nil)
  1177  		crdA := newCRD(genName(pkgA))
  1178  		crdB := newCRD(genName(pkgB))
  1179  		kvgA := fmt.Sprintf("%s.%s.%s", crdA.Spec.Names.Kind, crdA.Spec.Versions[0].Name, crdA.Spec.Group)
  1180  		kvgB := fmt.Sprintf("%s.%s.%s", crdB.Spec.Names.Kind, crdB.Spec.Versions[0].Name, crdB.Spec.Group)
  1181  		csvA := newCSV(pkgAStable, generatedNamespace.GetName(), "", semver.MustParse("0.1.0"), []apiextensionsv1.CustomResourceDefinition{crdA}, nil, &strategyA)
  1182  		csvB := newCSV(pkgBStable, generatedNamespace.GetName(), "", semver.MustParse("0.1.0"), []apiextensionsv1.CustomResourceDefinition{crdB}, nil, &strategyB)
  1183  
  1184  		By(`Create namespaces`)
  1185  		nsA, nsB, nsC, nsD := genName("a-"), genName("b-"), genName("c-"), genName("d-")
  1186  
  1187  		for _, ns := range []string{nsA, nsB, nsC, nsD} {
  1188  			namespace := &corev1.Namespace{
  1189  				ObjectMeta: metav1.ObjectMeta{
  1190  					Name: ns,
  1191  				},
  1192  			}
  1193  			_, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), namespace, metav1.CreateOptions{})
  1194  			require.NoError(GinkgoT(), err)
  1195  			defer func(name string) {
  1196  				require.NoError(GinkgoT(), c.KubernetesInterface().CoreV1().Namespaces().Delete(context.TODO(), name, metav1.DeleteOptions{}))
  1197  			}(ns)
  1198  		}
  1199  
  1200  		By(`Create the initial catalogsources`)
  1201  		manifests := []registry.PackageManifest{
  1202  			{
  1203  				PackageName: pkgA,
  1204  				Channels: []registry.PackageChannel{
  1205  					{Name: stableChannel, CurrentCSVName: pkgAStable},
  1206  				},
  1207  				DefaultChannelName: stableChannel,
  1208  			},
  1209  			{
  1210  				PackageName: pkgB,
  1211  				Channels: []registry.PackageChannel{
  1212  					{Name: stableChannel, CurrentCSVName: pkgBStable},
  1213  				},
  1214  				DefaultChannelName: stableChannel,
  1215  			},
  1216  		}
  1217  
  1218  		By(`Create catalog in namespaceB and namespaceC`)
  1219  		catalog := genName("catalog-")
  1220  		_, cleanupCatalogSource := createInternalCatalogSource(c, crc, catalog, nsB, manifests, []apiextensionsv1.CustomResourceDefinition{crdA, crdB}, []v1alpha1.ClusterServiceVersion{csvA, csvB})
  1221  		defer cleanupCatalogSource()
  1222  		_, err := fetchCatalogSourceOnStatus(crc, catalog, nsB, catalogSourceRegistryPodSynced())
  1223  		require.NoError(GinkgoT(), err)
  1224  		_, cleanupCatalogSource = createInternalCatalogSource(c, crc, catalog, nsC, manifests, []apiextensionsv1.CustomResourceDefinition{crdA, crdB}, []v1alpha1.ClusterServiceVersion{csvA, csvB})
  1225  		defer cleanupCatalogSource()
  1226  		_, err = fetchCatalogSourceOnStatus(crc, catalog, nsC, catalogSourceRegistryPodSynced())
  1227  		require.NoError(GinkgoT(), err)
  1228  
  1229  		By(`Create OperatorGroups`)
  1230  		groupA := newOperatorGroup(nsA, genName("a-"), map[string]string{v1.OperatorGroupProvidedAPIsAnnotationKey: kvgA}, nil, []string{nsD}, true)
  1231  		groupB := newOperatorGroup(nsB, genName("b-"), nil, nil, nil, false)
  1232  		groupC := newOperatorGroup(nsC, genName("d-"), nil, nil, []string{nsC}, false)
  1233  		for _, group := range []*v1.OperatorGroup{groupA, groupB, groupC} {
  1234  			_, err := crc.OperatorsV1().OperatorGroups(group.GetNamespace()).Create(context.TODO(), group, metav1.CreateOptions{})
  1235  			require.NoError(GinkgoT(), err)
  1236  			defer func(namespace, name string) {
  1237  				require.NoError(GinkgoT(), crc.OperatorsV1().OperatorGroups(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{}))
  1238  			}(group.GetNamespace(), group.GetName())
  1239  		}
  1240  
  1241  		By(`Create subscription for csvA in namespaceB`)
  1242  		subAName := genName("a-")
  1243  		cleanupSubA := createSubscriptionForCatalog(crc, nsB, subAName, catalog, pkgA, stableChannel, pkgAStable, v1alpha1.ApprovalAutomatic)
  1244  		defer cleanupSubA()
  1245  		subA, err := fetchSubscription(crc, nsB, subAName, subscriptionHasInstallPlanChecker())
  1246  		require.NoError(GinkgoT(), err)
  1247  		require.NotNil(GinkgoT(), subA)
  1248  
  1249  		By(`Await csvA's failure`)
  1250  		fetchedCSVA, err := fetchCSV(crc, nsB, csvA.GetName(), csvFailedChecker)
  1251  		require.NoError(GinkgoT(), err)
  1252  		require.Equal(GinkgoT(), v1alpha1.CSVReasonInterOperatorGroupOwnerConflict, fetchedCSVA.Status.Reason)
  1253  
  1254  		By(`Ensure operatorGroupB doesn't have providedAPI annotation`)
  1255  		q := func() (metav1.ObjectMeta, error) {
  1256  			g, err := crc.OperatorsV1().OperatorGroups(nsB).Get(context.TODO(), groupB.GetName(), metav1.GetOptions{})
  1257  			return g.ObjectMeta, err
  1258  		}
  1259  		require.NoError(GinkgoT(), awaitAnnotations(GinkgoT(), q, map[string]string{}))
  1260  
  1261  		By(`Ensure operatorGroupA still has KindA.version.group in its providedAPIs annotation`)
  1262  		q = func() (metav1.ObjectMeta, error) {
  1263  			g, err := crc.OperatorsV1().OperatorGroups(nsA).Get(context.TODO(), groupA.GetName(), metav1.GetOptions{})
  1264  			return g.ObjectMeta, err
  1265  		}
  1266  		require.NoError(GinkgoT(), awaitAnnotations(GinkgoT(), q, map[string]string{v1.OperatorGroupProvidedAPIsAnnotationKey: kvgA}))
  1267  
  1268  		By(`Create subscription for csvA in namespaceC`)
  1269  		cleanupSubAC := createSubscriptionForCatalog(crc, nsC, subAName, catalog, pkgA, stableChannel, pkgAStable, v1alpha1.ApprovalAutomatic)
  1270  		defer cleanupSubAC()
  1271  		subAC, err := fetchSubscription(crc, nsC, subAName, subscriptionHasInstallPlanChecker())
  1272  		require.NoError(GinkgoT(), err)
  1273  		require.NotNil(GinkgoT(), subAC)
  1274  
  1275  		By(`Await csvA's success`)
  1276  		_, err = fetchCSV(crc, nsC, csvA.GetName(), csvSucceededChecker)
  1277  		require.NoError(GinkgoT(), err)
  1278  
  1279  		By(`Ensure operatorGroupC has KindA.version.group in its providedAPIs annotation`)
  1280  		q = func() (metav1.ObjectMeta, error) {
  1281  			g, err := crc.OperatorsV1().OperatorGroups(nsC).Get(context.TODO(), groupC.GetName(), metav1.GetOptions{})
  1282  			return g.ObjectMeta, err
  1283  		}
  1284  		require.NoError(GinkgoT(), awaitAnnotations(GinkgoT(), q, map[string]string{v1.OperatorGroupProvidedAPIsAnnotationKey: kvgA}))
  1285  
  1286  		By(`Ensure operatorGroupA still has KindA.version.group in its providedAPIs annotation`)
  1287  		q = func() (metav1.ObjectMeta, error) {
  1288  			g, err := crc.OperatorsV1().OperatorGroups(nsA).Get(context.TODO(), groupA.GetName(), metav1.GetOptions{})
  1289  			return g.ObjectMeta, err
  1290  		}
  1291  		require.NoError(GinkgoT(), awaitAnnotations(GinkgoT(), q, map[string]string{v1.OperatorGroupProvidedAPIsAnnotationKey: kvgA}))
  1292  
  1293  		By(`Create subscription for csvB in namespaceB`)
  1294  		subBName := genName("b-")
  1295  		cleanupSubB := createSubscriptionForCatalog(crc, nsB, subBName, catalog, pkgB, stableChannel, pkgBStable, v1alpha1.ApprovalAutomatic)
  1296  		defer cleanupSubB()
  1297  		subB, err := fetchSubscription(crc, nsB, subBName, subscriptionHasInstallPlanChecker())
  1298  		require.NoError(GinkgoT(), err)
  1299  		require.NotNil(GinkgoT(), subB)
  1300  
  1301  		By(`Await csvB's success`)
  1302  		_, err = fetchCSV(crc, nsB, csvB.GetName(), csvSucceededChecker)
  1303  		require.NoError(GinkgoT(), err)
  1304  
  1305  		By(`Await copied csvBs`)
  1306  		_, err = fetchCSV(crc, nsA, csvB.GetName(), csvCopiedChecker)
  1307  		require.NoError(GinkgoT(), err)
  1308  		_, err = fetchCSV(crc, nsC, csvB.GetName(), csvCopiedChecker)
  1309  		require.NoError(GinkgoT(), err)
  1310  		_, err = fetchCSV(crc, nsD, csvB.GetName(), csvCopiedChecker)
  1311  		require.NoError(GinkgoT(), err)
  1312  
  1313  		By(`Ensure operatorGroupB has KindB.version.group in its providedAPIs annotation`)
  1314  		q = func() (metav1.ObjectMeta, error) {
  1315  			g, err := crc.OperatorsV1().OperatorGroups(nsB).Get(context.TODO(), groupB.GetName(), metav1.GetOptions{})
  1316  			return g.ObjectMeta, err
  1317  		}
  1318  		require.NoError(GinkgoT(), awaitAnnotations(GinkgoT(), q, map[string]string{v1.OperatorGroupProvidedAPIsAnnotationKey: kvgB}))
  1319  
  1320  		By(`Ensure operatorGroupA still has KindA.version.group in its providedAPIs annotation`)
  1321  		q = func() (metav1.ObjectMeta, error) {
  1322  			g, err := crc.OperatorsV1().OperatorGroups(nsA).Get(context.TODO(), groupA.GetName(), metav1.GetOptions{})
  1323  			return g.ObjectMeta, err
  1324  		}
  1325  		require.NoError(GinkgoT(), awaitAnnotations(GinkgoT(), q, map[string]string{v1.OperatorGroupProvidedAPIsAnnotationKey: kvgA}))
  1326  
  1327  		By(`Add namespaceD to operatorGroupC's targetNamespaces`)
  1328  		groupC, err = crc.OperatorsV1().OperatorGroups(groupC.GetNamespace()).Get(context.TODO(), groupC.GetName(), metav1.GetOptions{})
  1329  		require.NoError(GinkgoT(), err)
  1330  		groupC.Spec.TargetNamespaces = []string{nsC, nsD}
  1331  		_, err = crc.OperatorsV1().OperatorGroups(groupC.GetNamespace()).Update(context.TODO(), groupC, metav1.UpdateOptions{})
  1332  		require.NoError(GinkgoT(), err)
  1333  
  1334  		By(`Wait for csvA in namespaceC to fail with status "InterOperatorGroupOwnerConflict"`)
  1335  		fetchedCSVA, err = fetchCSV(crc, nsC, csvA.GetName(), csvFailedChecker)
  1336  		require.NoError(GinkgoT(), err)
  1337  		require.Equal(GinkgoT(), v1alpha1.CSVReasonInterOperatorGroupOwnerConflict, fetchedCSVA.Status.Reason)
  1338  
  1339  		By(`Wait for crdA's providedAPIs to be removed from operatorGroupC's providedAPIs annotation`)
  1340  		q = func() (metav1.ObjectMeta, error) {
  1341  			g, err := crc.OperatorsV1().OperatorGroups(nsC).Get(context.TODO(), groupC.GetName(), metav1.GetOptions{})
  1342  			return g.ObjectMeta, err
  1343  		}
  1344  		require.NoError(GinkgoT(), awaitAnnotations(GinkgoT(), q, map[string]string{v1.OperatorGroupProvidedAPIsAnnotationKey: ""}))
  1345  
  1346  		By(`Ensure operatorGroupA still has KindA.version.group in its providedAPIs annotation`)
  1347  		q = func() (metav1.ObjectMeta, error) {
  1348  			g, err := crc.OperatorsV1().OperatorGroups(nsA).Get(context.TODO(), groupA.GetName(), metav1.GetOptions{})
  1349  			return g.ObjectMeta, err
  1350  		}
  1351  		require.NoError(GinkgoT(), awaitAnnotations(GinkgoT(), q, map[string]string{v1.OperatorGroupProvidedAPIsAnnotationKey: kvgA}))
  1352  	})
  1353  
  1354  	// TODO: Test OperatorGroup resizing collisions
  1355  	// TODO: Test Subscriptions with depedencies and transitive dependencies in intersecting OperatorGroups
  1356  	// TODO: Test Subscription upgrade paths with + and - providedAPIs
  1357  	It("CSV copy watching all namespaces", func() {
  1358  
  1359  		csvName := genName("another-csv-") // must be lowercase for DNS-1123 validation
  1360  
  1361  		opGroupNamespace := generatedNamespace.GetName()
  1362  		matchingLabel := map[string]string{"inGroup": opGroupNamespace}
  1363  		otherNamespaceName := genName(opGroupNamespace + "-")
  1364  		GinkgoT().Log("Creating CRD")
  1365  		mainCRDPlural := genName("opgroup-")
  1366  		mainCRD := newCRD(mainCRDPlural)
  1367  		cleanupCRD, err := createCRD(c, mainCRD)
  1368  		require.NoError(GinkgoT(), err)
  1369  		defer cleanupCRD()
  1370  		operatorGroup, err := crc.OperatorsV1().OperatorGroups(opGroupNamespace).Get(context.TODO(), fmt.Sprintf("%v-operatorgroup", opGroupNamespace), metav1.GetOptions{})
  1371  		require.NoError(GinkgoT(), err)
  1372  
  1373  		expectedOperatorGroupStatus := v1.OperatorGroupStatus{
  1374  			Namespaces: []string{metav1.NamespaceAll},
  1375  		}
  1376  		GinkgoT().Log("Waiting on operator group to have correct status")
  1377  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
  1378  			fetched, fetchErr := crc.OperatorsV1().OperatorGroups(opGroupNamespace).Get(context.TODO(), operatorGroup.Name, metav1.GetOptions{})
  1379  			if fetchErr != nil {
  1380  				return false, fetchErr
  1381  			}
  1382  			if len(fetched.Status.Namespaces) > 0 {
  1383  				require.ElementsMatch(GinkgoT(), expectedOperatorGroupStatus.Namespaces, fetched.Status.Namespaces)
  1384  				fmt.Println(fetched.Status.Namespaces)
  1385  				return true, nil
  1386  			}
  1387  			return false, nil
  1388  		})
  1389  		require.NoError(GinkgoT(), err)
  1390  		GinkgoT().Log("Creating CSV")
  1391  		By(`Generate permissions`)
  1392  		serviceAccountName := genName("nginx-sa")
  1393  		permissions := []v1alpha1.StrategyDeploymentPermissions{
  1394  			{
  1395  				ServiceAccountName: serviceAccountName,
  1396  				Rules: []rbacv1.PolicyRule{
  1397  					{
  1398  						Verbs:     []string{rbacv1.VerbAll},
  1399  						APIGroups: []string{mainCRD.Spec.Group},
  1400  						Resources: []string{mainCRDPlural},
  1401  					},
  1402  				},
  1403  			},
  1404  		}
  1405  
  1406  		serviceAccount := &corev1.ServiceAccount{
  1407  			ObjectMeta: metav1.ObjectMeta{
  1408  				Namespace: opGroupNamespace,
  1409  				Name:      serviceAccountName,
  1410  			},
  1411  		}
  1412  		role := &rbacv1.Role{
  1413  			ObjectMeta: metav1.ObjectMeta{
  1414  				Namespace: opGroupNamespace,
  1415  				Name:      serviceAccountName + "-role",
  1416  			},
  1417  			Rules: permissions[0].Rules,
  1418  		}
  1419  		roleBinding := &rbacv1.RoleBinding{
  1420  			ObjectMeta: metav1.ObjectMeta{
  1421  				Namespace: opGroupNamespace,
  1422  				Name:      serviceAccountName + "-rb",
  1423  			},
  1424  			Subjects: []rbacv1.Subject{
  1425  				{
  1426  					Kind:      "ServiceAccount",
  1427  					Name:      serviceAccountName,
  1428  					Namespace: opGroupNamespace,
  1429  				},
  1430  			},
  1431  			RoleRef: rbacv1.RoleRef{
  1432  				Kind: "Role",
  1433  				Name: role.GetName(),
  1434  			},
  1435  		}
  1436  		serviceAccount, err = c.CreateServiceAccount(serviceAccount)
  1437  		require.NoError(GinkgoT(), err)
  1438  		defer func() {
  1439  			if env := os.Getenv("SKIP_CLEANUP"); env != "" {
  1440  				fmt.Printf("Skipping cleanup of serviceaccount %s/%s...\n", serviceAccount.GetNamespace(), serviceAccount.GetName())
  1441  				return
  1442  			}
  1443  			c.DeleteServiceAccount(serviceAccount.GetNamespace(), serviceAccount.GetName(), metav1.NewDeleteOptions(0))
  1444  		}()
  1445  		createdRole, err := c.CreateRole(role)
  1446  		require.NoError(GinkgoT(), err)
  1447  		defer func() {
  1448  			if env := os.Getenv("SKIP_CLEANUP"); env != "" {
  1449  				fmt.Printf("Skipping cleanup of role %s/%s...\n", role.GetNamespace(), role.GetName())
  1450  				return
  1451  			}
  1452  			c.DeleteRole(role.GetNamespace(), role.GetName(), metav1.NewDeleteOptions(0))
  1453  		}()
  1454  		createdRoleBinding, err := c.CreateRoleBinding(roleBinding)
  1455  		require.NoError(GinkgoT(), err)
  1456  		defer func() {
  1457  			if env := os.Getenv("SKIP_CLEANUP"); env != "" {
  1458  				fmt.Printf("Skipping cleanup of role binding %s/%s...\n", roleBinding.GetNamespace(), roleBinding.GetName())
  1459  				return
  1460  			}
  1461  			c.DeleteRoleBinding(roleBinding.GetNamespace(), roleBinding.GetName(), metav1.NewDeleteOptions(0))
  1462  		}()
  1463  		By(`Create a new NamedInstallStrategy`)
  1464  		deploymentName := genName("operator-deployment")
  1465  		namedStrategy := newNginxInstallStrategy(deploymentName, permissions, nil)
  1466  
  1467  		aCSV := newCSV(csvName, opGroupNamespace, "", semver.MustParse("0.0.0"), []apiextensionsv1.CustomResourceDefinition{mainCRD}, nil, &namedStrategy)
  1468  
  1469  		By(`Use the It spec name as label after stripping whitespaces`)
  1470  		aCSV.Labels = map[string]string{"label": K8sSafeCurrentTestDescription()}
  1471  		createdCSV, err := crc.OperatorsV1alpha1().ClusterServiceVersions(opGroupNamespace).Create(context.TODO(), &aCSV, metav1.CreateOptions{})
  1472  		require.NoError(GinkgoT(), err)
  1473  
  1474  		err = ownerutil.AddOwnerLabels(createdRole, createdCSV)
  1475  		require.NoError(GinkgoT(), err)
  1476  		createdRole.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue
  1477  		_, err = c.UpdateRole(createdRole)
  1478  		require.NoError(GinkgoT(), err)
  1479  
  1480  		err = ownerutil.AddOwnerLabels(createdRoleBinding, createdCSV)
  1481  		require.NoError(GinkgoT(), err)
  1482  		createdRoleBinding.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue
  1483  		_, err = c.UpdateRoleBinding(createdRoleBinding)
  1484  		require.NoError(GinkgoT(), err)
  1485  		GinkgoT().Log("wait for CSV to succeed")
  1486  		_, err = fetchCSV(crc, opGroupNamespace, createdCSV.GetName(), csvSucceededChecker)
  1487  		require.NoError(GinkgoT(), err)
  1488  		GinkgoT().Log("wait for roles to be promoted to clusterroles")
  1489  		var fetchedRole *rbacv1.ClusterRole
  1490  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
  1491  			fetchedRole, err = c.GetClusterRole(role.GetName())
  1492  			if err != nil {
  1493  				if apierrors.IsNotFound(err) {
  1494  					return false, nil
  1495  				}
  1496  				return false, err
  1497  			}
  1498  			return true, nil
  1499  		})
  1500  		require.EqualValues(GinkgoT(), append(role.Rules, rbacv1.PolicyRule{
  1501  			Verbs:     []string{"get", "list", "watch"},
  1502  			APIGroups: []string{""},
  1503  			Resources: []string{"namespaces"},
  1504  		}), fetchedRole.Rules)
  1505  		var fetchedRoleBinding *rbacv1.ClusterRoleBinding
  1506  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
  1507  			fetchedRoleBinding, err = c.GetClusterRoleBinding(roleBinding.GetName())
  1508  			if err != nil {
  1509  				if apierrors.IsNotFound(err) {
  1510  					return false, nil
  1511  				}
  1512  				return false, err
  1513  			}
  1514  			return true, nil
  1515  		})
  1516  		require.EqualValues(GinkgoT(), roleBinding.Subjects, fetchedRoleBinding.Subjects)
  1517  		require.EqualValues(GinkgoT(), roleBinding.RoleRef.Name, fetchedRoleBinding.RoleRef.Name)
  1518  		require.EqualValues(GinkgoT(), "rbac.authorization.k8s.io", fetchedRoleBinding.RoleRef.APIGroup)
  1519  		require.EqualValues(GinkgoT(), "ClusterRole", fetchedRoleBinding.RoleRef.Kind)
  1520  		GinkgoT().Log("ensure operator was granted namespace list permission")
  1521  		res, err := c.KubernetesInterface().AuthorizationV1().SubjectAccessReviews().Create(context.TODO(), &authorizationv1.SubjectAccessReview{
  1522  			Spec: authorizationv1.SubjectAccessReviewSpec{
  1523  				User: "system:serviceaccount:" + opGroupNamespace + ":" + serviceAccountName,
  1524  				ResourceAttributes: &authorizationv1.ResourceAttributes{
  1525  					Group:    corev1.GroupName,
  1526  					Version:  "v1",
  1527  					Resource: "namespaces",
  1528  					Verb:     "list",
  1529  				},
  1530  			},
  1531  		}, metav1.CreateOptions{})
  1532  		require.NoError(GinkgoT(), err)
  1533  		require.True(GinkgoT(), res.Status.Allowed, "got %#v", res.Status)
  1534  		GinkgoT().Log("Waiting for operator namespace csv to have annotations")
  1535  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
  1536  			fetchedCSV, fetchErr := crc.OperatorsV1alpha1().ClusterServiceVersions(opGroupNamespace).Get(context.TODO(), csvName, metav1.GetOptions{})
  1537  			if fetchErr != nil {
  1538  				if apierrors.IsNotFound(fetchErr) {
  1539  					return false, nil
  1540  				}
  1541  				GinkgoT().Logf("Error (in %v): %v", generatedNamespace.GetName(), fetchErr.Error())
  1542  				return false, fetchErr
  1543  			}
  1544  			if checkOperatorGroupAnnotations(fetchedCSV, operatorGroup, true, corev1.NamespaceAll) == nil {
  1545  				return true, nil
  1546  			}
  1547  			return false, nil
  1548  		})
  1549  		require.NoError(GinkgoT(), err)
  1550  
  1551  		csvList, err := crc.OperatorsV1alpha1().ClusterServiceVersions(corev1.NamespaceAll).List(context.TODO(), metav1.ListOptions{LabelSelector: fmt.Sprintf("label=%s", K8sSafeCurrentTestDescription())})
  1552  		require.NoError(GinkgoT(), err)
  1553  		GinkgoT().Logf("Found CSV count of %v", len(csvList.Items))
  1554  		GinkgoT().Logf("Create other namespace %s", otherNamespaceName)
  1555  		otherNamespace := corev1.Namespace{
  1556  			ObjectMeta: metav1.ObjectMeta{
  1557  				Name:   otherNamespaceName,
  1558  				Labels: matchingLabel,
  1559  			},
  1560  		}
  1561  		_, err = c.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), &otherNamespace, metav1.CreateOptions{})
  1562  		require.NoError(GinkgoT(), err)
  1563  		defer func() {
  1564  			err = c.KubernetesInterface().CoreV1().Namespaces().Delete(context.TODO(), otherNamespaceName, metav1.DeleteOptions{})
  1565  			require.NoError(GinkgoT(), err)
  1566  		}()
  1567  		GinkgoT().Log("Waiting to ensure copied CSV shows up in other namespace")
  1568  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
  1569  			fetchedCSV, fetchErr := crc.OperatorsV1alpha1().ClusterServiceVersions(otherNamespaceName).Get(context.TODO(), csvName, metav1.GetOptions{})
  1570  			if fetchErr != nil {
  1571  				if apierrors.IsNotFound(fetchErr) {
  1572  					return false, nil
  1573  				}
  1574  				GinkgoT().Logf("Error (in %v): %v", otherNamespaceName, fetchErr.Error())
  1575  				return false, fetchErr
  1576  			}
  1577  			if checkOperatorGroupAnnotations(fetchedCSV, operatorGroup, false, "") == nil {
  1578  				return true, nil
  1579  			}
  1580  			return false, nil
  1581  		})
  1582  		require.NoError(GinkgoT(), err)
  1583  		GinkgoT( // verify created CSV is cleaned up after operator group is "contracted"
  1584  		).Log("Modifying operator group to no longer watch all namespaces")
  1585  		currentOperatorGroup, err := crc.OperatorsV1().OperatorGroups(opGroupNamespace).Get(context.TODO(), operatorGroup.Name, metav1.GetOptions{})
  1586  		require.NoError(GinkgoT(), err)
  1587  		currentOperatorGroup.Spec.TargetNamespaces = []string{opGroupNamespace}
  1588  		_, err = crc.OperatorsV1().OperatorGroups(opGroupNamespace).Update(context.TODO(), currentOperatorGroup, metav1.UpdateOptions{})
  1589  		require.NoError(GinkgoT(), err)
  1590  		defer func() {
  1591  			GinkgoT().Log("Re-modifying operator group to be watching all namespaces")
  1592  			currentOperatorGroup, err = crc.OperatorsV1().OperatorGroups(opGroupNamespace).Get(context.TODO(), operatorGroup.Name, metav1.GetOptions{})
  1593  			require.NoError(GinkgoT(), err)
  1594  			currentOperatorGroup.Spec = v1.OperatorGroupSpec{}
  1595  			_, err = crc.OperatorsV1().OperatorGroups(opGroupNamespace).Update(context.TODO(), currentOperatorGroup, metav1.UpdateOptions{})
  1596  			require.NoError(GinkgoT(), err)
  1597  		}()
  1598  
  1599  		err = wait.Poll(pollInterval, 2*pollDuration, func() (bool, error) {
  1600  			_, fetchErr := crc.OperatorsV1alpha1().ClusterServiceVersions(otherNamespaceName).Get(context.TODO(), csvName, metav1.GetOptions{})
  1601  			if fetchErr != nil {
  1602  				if apierrors.IsNotFound(fetchErr) {
  1603  					return true, nil
  1604  				}
  1605  				GinkgoT().Logf("Error (in %v): %v", opGroupNamespace, fetchErr.Error())
  1606  				return false, fetchErr
  1607  			}
  1608  			return false, nil
  1609  		})
  1610  		require.NoError(GinkgoT(), err)
  1611  	})
  1612  	It("insufficient permissions resolve via RBAC", func() {
  1613  
  1614  		log := func(s string) {
  1615  			GinkgoT().Logf("%s: %s", time.Now().Format("15:04:05.9999"), s)
  1616  		}
  1617  
  1618  		csvName := genName("another-csv-")
  1619  
  1620  		newNamespaceName := genName(generatedNamespace.GetName() + "-")
  1621  
  1622  		_, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
  1623  			ObjectMeta: metav1.ObjectMeta{
  1624  				Name: newNamespaceName,
  1625  			},
  1626  		}, metav1.CreateOptions{})
  1627  		require.NoError(GinkgoT(), err)
  1628  		defer func() {
  1629  			err = c.KubernetesInterface().CoreV1().Namespaces().Delete(context.TODO(), newNamespaceName, metav1.DeleteOptions{})
  1630  			require.NoError(GinkgoT(), err)
  1631  		}()
  1632  
  1633  		log("Creating CRD")
  1634  		mainCRDPlural := genName("opgroup")
  1635  		mainCRD := newCRD(mainCRDPlural)
  1636  		cleanupCRD, err := createCRD(c, mainCRD)
  1637  		require.NoError(GinkgoT(), err)
  1638  		defer cleanupCRD()
  1639  
  1640  		log("Creating operator group")
  1641  		serviceAccountName := genName("nginx-sa")
  1642  		By(`intentionally creating an operator group without a service account already existing`)
  1643  		operatorGroup := v1.OperatorGroup{
  1644  			ObjectMeta: metav1.ObjectMeta{
  1645  				Name:      genName("e2e-operator-group-"),
  1646  				Namespace: newNamespaceName,
  1647  			},
  1648  			Spec: v1.OperatorGroupSpec{
  1649  				ServiceAccountName: serviceAccountName,
  1650  				TargetNamespaces:   []string{newNamespaceName},
  1651  			},
  1652  		}
  1653  		_, err = crc.OperatorsV1().OperatorGroups(newNamespaceName).Create(context.TODO(), &operatorGroup, metav1.CreateOptions{})
  1654  		require.NoError(GinkgoT(), err)
  1655  
  1656  		log("Creating CSV")
  1657  
  1658  		By(`Create a new NamedInstallStrategy`)
  1659  		deploymentName := genName("operator-deployment")
  1660  		namedStrategy := newNginxInstallStrategy(deploymentName, nil, nil)
  1661  
  1662  		aCSV := newCSV(csvName, newNamespaceName, "", semver.MustParse("0.0.0"), []apiextensionsv1.CustomResourceDefinition{mainCRD}, nil, &namedStrategy)
  1663  		createdCSV, err := crc.OperatorsV1alpha1().ClusterServiceVersions(newNamespaceName).Create(context.TODO(), &aCSV, metav1.CreateOptions{})
  1664  		require.NoError(GinkgoT(), err)
  1665  
  1666  		serviceAccount := &corev1.ServiceAccount{
  1667  			ObjectMeta: metav1.ObjectMeta{
  1668  				Namespace: newNamespaceName,
  1669  				Name:      serviceAccountName,
  1670  			},
  1671  		}
  1672  		ownerutil.AddNonBlockingOwner(serviceAccount, createdCSV)
  1673  		err = ownerutil.AddOwnerLabels(serviceAccount, createdCSV)
  1674  		require.NoError(GinkgoT(), err)
  1675  
  1676  		_, err = c.CreateServiceAccount(serviceAccount)
  1677  		require.NoError(GinkgoT(), err)
  1678  		By(`Create token secret for the serviceaccount`)
  1679  		_, cleanupSE := newTokenSecret(c, newNamespaceName, serviceAccount.GetName())
  1680  		defer cleanupSE()
  1681  
  1682  		log("wait for CSV to fail")
  1683  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
  1684  			fetched, err := crc.OperatorsV1alpha1().ClusterServiceVersions(newNamespaceName).Get(context.TODO(), createdCSV.GetName(), metav1.GetOptions{})
  1685  			if err != nil {
  1686  				return false, err
  1687  			}
  1688  			log(fmt.Sprintf("%s (%s): %s", fetched.Status.Phase, fetched.Status.Reason, fetched.Status.Message))
  1689  			return csvFailedChecker(fetched), nil
  1690  		})
  1691  		require.NoError(GinkgoT(), err)
  1692  
  1693  		By(`now add cluster admin permissions to service account`)
  1694  		role := &rbacv1.Role{
  1695  			ObjectMeta: metav1.ObjectMeta{
  1696  				Namespace: newNamespaceName,
  1697  				Name:      serviceAccountName + "-role",
  1698  			},
  1699  			Rules: []rbacv1.PolicyRule{
  1700  				{
  1701  					Verbs:     []string{"*"},
  1702  					APIGroups: []string{"*"},
  1703  					Resources: []string{"*"},
  1704  				},
  1705  			},
  1706  		}
  1707  		ownerutil.AddNonBlockingOwner(role, createdCSV)
  1708  		err = ownerutil.AddOwnerLabels(role, createdCSV)
  1709  		require.NoError(GinkgoT(), err)
  1710  
  1711  		roleBinding := &rbacv1.RoleBinding{
  1712  			ObjectMeta: metav1.ObjectMeta{
  1713  				Namespace: newNamespaceName,
  1714  				Name:      serviceAccountName + "-rb",
  1715  			},
  1716  			Subjects: []rbacv1.Subject{
  1717  				{
  1718  					Kind:      "ServiceAccount",
  1719  					Name:      serviceAccountName,
  1720  					Namespace: newNamespaceName,
  1721  				},
  1722  			},
  1723  			RoleRef: rbacv1.RoleRef{
  1724  				Kind: "Role",
  1725  				Name: role.GetName(),
  1726  			},
  1727  		}
  1728  		ownerutil.AddNonBlockingOwner(roleBinding, createdCSV)
  1729  		err = ownerutil.AddOwnerLabels(roleBinding, createdCSV)
  1730  		require.NoError(GinkgoT(), err)
  1731  
  1732  		_, err = c.CreateRole(role)
  1733  		require.NoError(GinkgoT(), err)
  1734  		_, err = c.CreateRoleBinding(roleBinding)
  1735  		require.NoError(GinkgoT(), err)
  1736  
  1737  		log("wait for CSV to succeeed")
  1738  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
  1739  			fetched, err := crc.OperatorsV1alpha1().ClusterServiceVersions(newNamespaceName).Get(context.TODO(), createdCSV.GetName(), metav1.GetOptions{})
  1740  			if err != nil {
  1741  				return false, err
  1742  			}
  1743  			log(fmt.Sprintf("%s (%s): %s", fetched.Status.Phase, fetched.Status.Reason, fetched.Status.Message))
  1744  			return csvSucceededChecker(fetched), nil
  1745  		})
  1746  		require.NoError(GinkgoT(), err)
  1747  	})
  1748  	It("insufficient permissions resolve via service account removal", func() {
  1749  
  1750  		log := func(s string) {
  1751  			GinkgoT().Logf("%s: %s", time.Now().Format("15:04:05.9999"), s)
  1752  		}
  1753  
  1754  		csvName := genName("another-csv-")
  1755  
  1756  		newNamespaceName := genName(generatedNamespace.GetName() + "-")
  1757  
  1758  		_, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
  1759  			ObjectMeta: metav1.ObjectMeta{
  1760  				Name: newNamespaceName,
  1761  			},
  1762  		}, metav1.CreateOptions{})
  1763  		require.NoError(GinkgoT(), err)
  1764  		defer func() {
  1765  			err = c.KubernetesInterface().CoreV1().Namespaces().Delete(context.TODO(), newNamespaceName, metav1.DeleteOptions{})
  1766  			require.NoError(GinkgoT(), err)
  1767  		}()
  1768  
  1769  		log("Creating CRD")
  1770  		mainCRDPlural := genName("opgroup")
  1771  		mainCRD := newCRD(mainCRDPlural)
  1772  		cleanupCRD, err := createCRD(c, mainCRD)
  1773  		require.NoError(GinkgoT(), err)
  1774  		defer cleanupCRD()
  1775  
  1776  		log("Creating operator group")
  1777  		serviceAccountName := genName("nginx-sa")
  1778  		By(`intentionally creating an operator group without a service account already existing`)
  1779  		operatorGroup := v1.OperatorGroup{
  1780  			ObjectMeta: metav1.ObjectMeta{
  1781  				Name:      genName("e2e-operator-group-"),
  1782  				Namespace: newNamespaceName,
  1783  			},
  1784  			Spec: v1.OperatorGroupSpec{
  1785  				ServiceAccountName: serviceAccountName,
  1786  				TargetNamespaces:   []string{newNamespaceName},
  1787  			},
  1788  		}
  1789  		_, err = crc.OperatorsV1().OperatorGroups(newNamespaceName).Create(context.TODO(), &operatorGroup, metav1.CreateOptions{})
  1790  		require.NoError(GinkgoT(), err)
  1791  
  1792  		log("Creating CSV")
  1793  
  1794  		By(`Create a new NamedInstallStrategy`)
  1795  		deploymentName := genName("operator-deployment")
  1796  		namedStrategy := newNginxInstallStrategy(deploymentName, nil, nil)
  1797  
  1798  		aCSV := newCSV(csvName, newNamespaceName, "", semver.MustParse("0.0.0"), []apiextensionsv1.CustomResourceDefinition{mainCRD}, nil, &namedStrategy)
  1799  		createdCSV, err := crc.OperatorsV1alpha1().ClusterServiceVersions(newNamespaceName).Create(context.TODO(), &aCSV, metav1.CreateOptions{})
  1800  		require.NoError(GinkgoT(), err)
  1801  
  1802  		serviceAccount := &corev1.ServiceAccount{
  1803  			ObjectMeta: metav1.ObjectMeta{
  1804  				Namespace: newNamespaceName,
  1805  				Name:      serviceAccountName,
  1806  			},
  1807  		}
  1808  		ownerutil.AddNonBlockingOwner(serviceAccount, createdCSV)
  1809  		err = ownerutil.AddOwnerLabels(serviceAccount, createdCSV)
  1810  		require.NoError(GinkgoT(), err)
  1811  
  1812  		_, err = c.CreateServiceAccount(serviceAccount)
  1813  		require.NoError(GinkgoT(), err)
  1814  		By(`Create token secret for the serviceaccount`)
  1815  		_, cleanupSE := newTokenSecret(c, newNamespaceName, serviceAccount.GetName())
  1816  		defer cleanupSE()
  1817  
  1818  		log("wait for CSV to fail")
  1819  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
  1820  			fetched, err := crc.OperatorsV1alpha1().ClusterServiceVersions(newNamespaceName).Get(context.TODO(), createdCSV.GetName(), metav1.GetOptions{})
  1821  			if err != nil {
  1822  				return false, err
  1823  			}
  1824  			log(fmt.Sprintf("%s (%s): %s", fetched.Status.Phase, fetched.Status.Reason, fetched.Status.Message))
  1825  			return csvFailedChecker(fetched), nil
  1826  		})
  1827  		require.NoError(GinkgoT(), err)
  1828  
  1829  		By(`now remove operator group specified service account`)
  1830  		createdOpGroup, err := crc.OperatorsV1().OperatorGroups(newNamespaceName).Get(context.TODO(), operatorGroup.GetName(), metav1.GetOptions{})
  1831  		require.NoError(GinkgoT(), err)
  1832  		createdOpGroup.Spec.ServiceAccountName = ""
  1833  		_, err = crc.OperatorsV1().OperatorGroups(newNamespaceName).Update(context.TODO(), createdOpGroup, metav1.UpdateOptions{})
  1834  		require.NoError(GinkgoT(), err)
  1835  
  1836  		log("wait for CSV to succeeed")
  1837  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
  1838  			fetched, err := crc.OperatorsV1alpha1().ClusterServiceVersions(newNamespaceName).Get(context.TODO(), createdCSV.GetName(), metav1.GetOptions{})
  1839  			if err != nil {
  1840  				return false, err
  1841  			}
  1842  			log(fmt.Sprintf("%s (%s): %s", fetched.Status.Phase, fetched.Status.Reason, fetched.Status.Message))
  1843  			return csvSucceededChecker(fetched), nil
  1844  		})
  1845  		require.NoError(GinkgoT(), err)
  1846  	})
  1847  
  1848  	It("cleanup csvs with bad namespace annotation", func() {
  1849  		By(`Versions of OLM at 0.14.1 and older had a bug that would place the wrong namespace annotation on copied CSVs,`)
  1850  		By(`preventing them from being GCd. This ensures that any leftover CSVs in that state are properly cleared up.`)
  1851  
  1852  		csvName := genName("another-csv-") // must be lowercase for DNS-1123 validation
  1853  
  1854  		opGroupNamespace := generatedNamespace.GetName()
  1855  		matchingLabel := map[string]string{"inGroup": opGroupNamespace}
  1856  		otherNamespaceName := genName(opGroupNamespace + "-")
  1857  		GinkgoT().Log("Creating CRD")
  1858  		mainCRDPlural := genName("opgroup-")
  1859  		mainCRD := newCRD(mainCRDPlural)
  1860  		cleanupCRD, err := createCRD(c, mainCRD)
  1861  		require.NoError(GinkgoT(), err)
  1862  		defer cleanupCRD()
  1863  		operatorGroup, err := crc.OperatorsV1().OperatorGroups(opGroupNamespace).Get(context.TODO(), fmt.Sprintf("%v-operatorgroup", opGroupNamespace), metav1.GetOptions{})
  1864  		require.NoError(GinkgoT(), err)
  1865  
  1866  		expectedOperatorGroupStatus := v1.OperatorGroupStatus{
  1867  			Namespaces: []string{metav1.NamespaceAll},
  1868  		}
  1869  		GinkgoT().Log("Waiting on operator group to have correct status")
  1870  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
  1871  			fetched, fetchErr := crc.OperatorsV1().OperatorGroups(opGroupNamespace).Get(context.TODO(), operatorGroup.Name, metav1.GetOptions{})
  1872  			if fetchErr != nil {
  1873  				return false, fetchErr
  1874  			}
  1875  			if len(fetched.Status.Namespaces) > 0 {
  1876  				require.ElementsMatch(GinkgoT(), expectedOperatorGroupStatus.Namespaces, fetched.Status.Namespaces)
  1877  				fmt.Println(fetched.Status.Namespaces)
  1878  				return true, nil
  1879  			}
  1880  			return false, nil
  1881  		})
  1882  		require.NoError(GinkgoT(), err)
  1883  		GinkgoT().Log("Creating CSV")
  1884  		By(`Generate permissions`)
  1885  		serviceAccountName := genName("nginx-sa")
  1886  		permissions := []v1alpha1.StrategyDeploymentPermissions{
  1887  			{
  1888  				ServiceAccountName: serviceAccountName,
  1889  				Rules: []rbacv1.PolicyRule{
  1890  					{
  1891  						Verbs:     []string{rbacv1.VerbAll},
  1892  						APIGroups: []string{mainCRD.Spec.Group},
  1893  						Resources: []string{mainCRDPlural},
  1894  					},
  1895  				},
  1896  			},
  1897  		}
  1898  
  1899  		serviceAccount := &corev1.ServiceAccount{
  1900  			ObjectMeta: metav1.ObjectMeta{
  1901  				Namespace: opGroupNamespace,
  1902  				Name:      serviceAccountName,
  1903  			},
  1904  		}
  1905  		role := &rbacv1.Role{
  1906  			ObjectMeta: metav1.ObjectMeta{
  1907  				Namespace: opGroupNamespace,
  1908  				Name:      serviceAccountName + "-role",
  1909  			},
  1910  			Rules: permissions[0].Rules,
  1911  		}
  1912  		roleBinding := &rbacv1.RoleBinding{
  1913  			ObjectMeta: metav1.ObjectMeta{
  1914  				Namespace: opGroupNamespace,
  1915  				Name:      serviceAccountName + "-rb",
  1916  			},
  1917  			Subjects: []rbacv1.Subject{
  1918  				{
  1919  					Kind:      "ServiceAccount",
  1920  					Name:      serviceAccountName,
  1921  					Namespace: opGroupNamespace,
  1922  				},
  1923  			},
  1924  			RoleRef: rbacv1.RoleRef{
  1925  				Kind: "Role",
  1926  				Name: role.GetName(),
  1927  			},
  1928  		}
  1929  		_, err = c.CreateServiceAccount(serviceAccount)
  1930  		require.NoError(GinkgoT(), err)
  1931  		defer func() {
  1932  			if env := os.Getenv("SKIP_CLEANUP"); env != "" {
  1933  				fmt.Printf("Skipping cleanup of serviceaccount %s/%s...\n", serviceAccount.GetNamespace(), serviceAccount.GetName())
  1934  				return
  1935  			}
  1936  			c.DeleteServiceAccount(serviceAccount.GetNamespace(), serviceAccount.GetName(), metav1.NewDeleteOptions(0))
  1937  		}()
  1938  		createdRole, err := c.CreateRole(role)
  1939  		require.NoError(GinkgoT(), err)
  1940  		defer func() {
  1941  			if env := os.Getenv("SKIP_CLEANUP"); env != "" {
  1942  				fmt.Printf("Skipping cleanup of role %s/%s...\n", role.GetNamespace(), role.GetName())
  1943  				return
  1944  			}
  1945  			c.DeleteRole(role.GetNamespace(), role.GetName(), metav1.NewDeleteOptions(0))
  1946  		}()
  1947  		createdRoleBinding, err := c.CreateRoleBinding(roleBinding)
  1948  		require.NoError(GinkgoT(), err)
  1949  		defer func() {
  1950  			if env := os.Getenv("SKIP_CLEANUP"); env != "" {
  1951  				fmt.Printf("Skipping cleanup of role binding %s/%s...\n", roleBinding.GetNamespace(), roleBinding.GetName())
  1952  				return
  1953  			}
  1954  			c.DeleteRoleBinding(roleBinding.GetNamespace(), roleBinding.GetName(), metav1.NewDeleteOptions(0))
  1955  		}()
  1956  		By(`Create a new NamedInstallStrategy`)
  1957  		deploymentName := genName("operator-deployment")
  1958  		namedStrategy := newNginxInstallStrategy(deploymentName, permissions, nil)
  1959  
  1960  		aCSV := newCSV(csvName, opGroupNamespace, "", semver.MustParse("0.0.0"), []apiextensionsv1.CustomResourceDefinition{mainCRD}, nil, &namedStrategy)
  1961  
  1962  		By(`Use the It spec name as label after stripping whitespaces`)
  1963  		aCSV.Labels = map[string]string{"label": K8sSafeCurrentTestDescription()}
  1964  		createdCSV, err := crc.OperatorsV1alpha1().ClusterServiceVersions(opGroupNamespace).Create(context.TODO(), &aCSV, metav1.CreateOptions{})
  1965  		require.NoError(GinkgoT(), err)
  1966  
  1967  		err = ownerutil.AddOwnerLabels(createdRole, createdCSV)
  1968  		require.NoError(GinkgoT(), err)
  1969  		createdRole.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue
  1970  		_, err = c.UpdateRole(createdRole)
  1971  		require.NoError(GinkgoT(), err)
  1972  
  1973  		err = ownerutil.AddOwnerLabels(createdRoleBinding, createdCSV)
  1974  		require.NoError(GinkgoT(), err)
  1975  		createdRoleBinding.Labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue
  1976  		_, err = c.UpdateRoleBinding(createdRoleBinding)
  1977  		require.NoError(GinkgoT(), err)
  1978  		GinkgoT().Log("wait for CSV to succeed")
  1979  		_, err = fetchCSV(crc, opGroupNamespace, createdCSV.GetName(), csvSucceededChecker)
  1980  		require.NoError(GinkgoT(), err)
  1981  		GinkgoT().Log("wait for roles to be promoted to clusterroles")
  1982  		var fetchedRole *rbacv1.ClusterRole
  1983  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
  1984  			fetchedRole, err = c.GetClusterRole(role.GetName())
  1985  			if err != nil {
  1986  				if apierrors.IsNotFound(err) {
  1987  					return false, nil
  1988  				}
  1989  				return false, err
  1990  			}
  1991  			return true, nil
  1992  		})
  1993  		require.NoError(GinkgoT(), err)
  1994  		require.EqualValues(GinkgoT(), append(role.Rules, rbacv1.PolicyRule{
  1995  			Verbs:     []string{"get", "list", "watch"},
  1996  			APIGroups: []string{""},
  1997  			Resources: []string{"namespaces"},
  1998  		}), fetchedRole.Rules)
  1999  		var fetchedRoleBinding *rbacv1.ClusterRoleBinding
  2000  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
  2001  			fetchedRoleBinding, err = c.GetClusterRoleBinding(roleBinding.GetName())
  2002  			if err != nil {
  2003  				if apierrors.IsNotFound(err) {
  2004  					return false, nil
  2005  				}
  2006  				return false, err
  2007  			}
  2008  			return true, nil
  2009  		})
  2010  		require.NoError(GinkgoT(), err)
  2011  		require.EqualValues(GinkgoT(), roleBinding.Subjects, fetchedRoleBinding.Subjects)
  2012  		require.EqualValues(GinkgoT(), roleBinding.RoleRef.Name, fetchedRoleBinding.RoleRef.Name)
  2013  		require.EqualValues(GinkgoT(), "rbac.authorization.k8s.io", fetchedRoleBinding.RoleRef.APIGroup)
  2014  		require.EqualValues(GinkgoT(), "ClusterRole", fetchedRoleBinding.RoleRef.Kind)
  2015  		GinkgoT().Log("ensure operator was granted namespace list permission")
  2016  		res, err := c.KubernetesInterface().AuthorizationV1().SubjectAccessReviews().Create(context.TODO(), &authorizationv1.SubjectAccessReview{
  2017  			Spec: authorizationv1.SubjectAccessReviewSpec{
  2018  				User: "system:serviceaccount:" + opGroupNamespace + ":" + serviceAccountName,
  2019  				ResourceAttributes: &authorizationv1.ResourceAttributes{
  2020  					Group:    corev1.GroupName,
  2021  					Version:  "v1",
  2022  					Resource: "namespaces",
  2023  					Verb:     "list",
  2024  				},
  2025  			},
  2026  		}, metav1.CreateOptions{})
  2027  		require.NoError(GinkgoT(), err)
  2028  		require.True(GinkgoT(), res.Status.Allowed, "got %#v", res.Status)
  2029  		GinkgoT().Log("Waiting for operator namespace csv to have annotations")
  2030  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
  2031  			fetchedCSV, fetchErr := crc.OperatorsV1alpha1().ClusterServiceVersions(opGroupNamespace).Get(context.TODO(), csvName, metav1.GetOptions{})
  2032  			if fetchErr != nil {
  2033  				if apierrors.IsNotFound(fetchErr) {
  2034  					return false, nil
  2035  				}
  2036  				GinkgoT().Logf("Error (in %v): %v", generatedNamespace.GetName(), fetchErr.Error())
  2037  				return false, fetchErr
  2038  			}
  2039  			if checkOperatorGroupAnnotations(fetchedCSV, operatorGroup, true, corev1.NamespaceAll) == nil {
  2040  				return true, nil
  2041  			}
  2042  			return false, nil
  2043  		})
  2044  		require.NoError(GinkgoT(), err)
  2045  
  2046  		csvList, err := crc.OperatorsV1alpha1().ClusterServiceVersions(corev1.NamespaceAll).List(context.TODO(), metav1.ListOptions{LabelSelector: fmt.Sprintf("label=%s", K8sSafeCurrentTestDescription())})
  2047  		require.NoError(GinkgoT(), err)
  2048  		GinkgoT().Logf("Found CSV count of %v", len(csvList.Items))
  2049  		GinkgoT().Logf("Create other namespace %s", otherNamespaceName)
  2050  		otherNamespace := corev1.Namespace{
  2051  			ObjectMeta: metav1.ObjectMeta{
  2052  				Name:   otherNamespaceName,
  2053  				Labels: matchingLabel,
  2054  			},
  2055  		}
  2056  		_, err = c.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), &otherNamespace, metav1.CreateOptions{})
  2057  		require.NoError(GinkgoT(), err)
  2058  		defer func() {
  2059  			err = c.KubernetesInterface().CoreV1().Namespaces().Delete(context.TODO(), otherNamespaceName, metav1.DeleteOptions{})
  2060  			require.NoError(GinkgoT(), err)
  2061  		}()
  2062  		GinkgoT().Log("Waiting to ensure copied CSV shows up in other namespace")
  2063  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
  2064  			fetchedCSV, fetchErr := crc.OperatorsV1alpha1().ClusterServiceVersions(otherNamespaceName).Get(context.TODO(), csvName, metav1.GetOptions{})
  2065  			if fetchErr != nil {
  2066  				if apierrors.IsNotFound(fetchErr) {
  2067  					return false, nil
  2068  				}
  2069  				GinkgoT().Logf("Error (in %v): %v", otherNamespaceName, fetchErr.Error())
  2070  				return false, fetchErr
  2071  			}
  2072  			if checkOperatorGroupAnnotations(fetchedCSV, operatorGroup, false, "") == nil {
  2073  				return true, nil
  2074  			}
  2075  			return false, nil
  2076  		})
  2077  		require.NoError(GinkgoT(), err)
  2078  		GinkgoT().Log("Copied CSV showed up in other namespace, giving copied CSV a bad OpertorGroup annotation")
  2079  		err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
  2080  			fetchedCSV, fetchErr := crc.OperatorsV1alpha1().ClusterServiceVersions(otherNamespaceName).Get(context.TODO(), csvName, metav1.GetOptions{})
  2081  			if fetchErr != nil {
  2082  				return false, fetchErr
  2083  			}
  2084  			fetchedCSV.Annotations[v1.OperatorGroupNamespaceAnnotationKey] = fetchedCSV.GetNamespace()
  2085  			_, updateErr := crc.OperatorsV1alpha1().ClusterServiceVersions(otherNamespaceName).Update(context.TODO(), fetchedCSV, metav1.UpdateOptions{})
  2086  			if updateErr != nil {
  2087  				GinkgoT().Logf("Error updating copied CSV (in %v): %v", otherNamespaceName, updateErr.Error())
  2088  				return false, updateErr
  2089  			}
  2090  			return true, nil
  2091  		})
  2092  		require.NoError(GinkgoT(), err)
  2093  		GinkgoT().Log("Done updating copied CSV with bad annotation OperatorGroup, waiting for CSV to be gc'd")
  2094  		err = wait.Poll(pollInterval, 2*pollDuration, func() (bool, error) {
  2095  			csv, fetchErr := crc.OperatorsV1alpha1().ClusterServiceVersions(otherNamespaceName).Get(context.TODO(), csvName, metav1.GetOptions{})
  2096  			if fetchErr != nil {
  2097  				if apierrors.IsNotFound(fetchErr) {
  2098  					return true, nil
  2099  				}
  2100  				GinkgoT().Logf("Error (in %v): %v", opGroupNamespace, fetchErr.Error())
  2101  				return false, fetchErr
  2102  			}
  2103  			By(`The CSV with the wrong annotation could have been replaced with a new copied CSV by this time`)
  2104  			By(`If we find a CSV in the namespace, and it contains the correct annotation, it means the CSV`)
  2105  			By(`with the wrong annotation was GCed`)
  2106  			if csv.Annotations[v1.OperatorGroupNamespaceAnnotationKey] != csv.GetNamespace() {
  2107  				return true, nil
  2108  			}
  2109  			return false, nil
  2110  		})
  2111  		require.NoError(GinkgoT(), err)
  2112  	})
  2113  	It("OperatorGroupLabels", func() {
  2114  
  2115  		By(`Create the namespaces that will have an OperatorGroup Label applied.`)
  2116  		testNamespaceA := genName("namespace-a-")
  2117  		testNamespaceB := genName("namespace-b-")
  2118  		testNamespaceC := genName("namespace-c-")
  2119  		testNamespaces := []string{
  2120  			testNamespaceA, testNamespaceB, testNamespaceC,
  2121  		}
  2122  
  2123  		By(`Create the namespaces`)
  2124  		for _, namespace := range testNamespaces {
  2125  			_, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
  2126  				ObjectMeta: metav1.ObjectMeta{
  2127  					Name: namespace,
  2128  				},
  2129  			}, metav1.CreateOptions{})
  2130  			require.NoError(GinkgoT(), err)
  2131  		}
  2132  
  2133  		By(`Cleanup namespaces`)
  2134  		defer func() {
  2135  			for _, namespace := range testNamespaces {
  2136  				err := c.KubernetesInterface().CoreV1().Namespaces().Delete(context.TODO(), namespace, metav1.DeleteOptions{})
  2137  				require.NoError(GinkgoT(), err)
  2138  			}
  2139  		}()
  2140  
  2141  		By(`Create an OperatorGroup`)
  2142  		operatorGroup := &v1.OperatorGroup{
  2143  			ObjectMeta: metav1.ObjectMeta{
  2144  				Name:      genName("e2e-operator-group-"),
  2145  				Namespace: testNamespaceA,
  2146  			},
  2147  			Spec: v1.OperatorGroupSpec{
  2148  				TargetNamespaces: []string{},
  2149  			},
  2150  		}
  2151  		operatorGroup, err := crc.OperatorsV1().OperatorGroups(testNamespaceA).Create(context.TODO(), operatorGroup, metav1.CreateOptions{})
  2152  		require.NoError(GinkgoT(), err)
  2153  
  2154  		By(`Cleanup OperatorGroup`)
  2155  		defer func() {
  2156  			err := crc.OperatorsV1().OperatorGroups(testNamespaceA).Delete(context.TODO(), operatorGroup.GetName(), metav1.DeleteOptions{})
  2157  			require.NoError(GinkgoT(), err)
  2158  		}()
  2159  
  2160  		By(`Create the OperatorGroup Label`)
  2161  		ogLabel, err := getOGLabelKey(operatorGroup)
  2162  		require.NoError(GinkgoT(), err)
  2163  
  2164  		By(`Create list options`)
  2165  		listOptions := metav1.ListOptions{
  2166  			LabelSelector: labels.Set(map[string]string{ogLabel: ""}).String(),
  2167  		}
  2168  
  2169  		namespaceList, err := pollForNamespaceListCount(c, listOptions, 0)
  2170  		require.NoError(GinkgoT(), err)
  2171  
  2172  		By(`Update the OperatorGroup to include a single namespace`)
  2173  		operatorGroup.Spec.TargetNamespaces = []string{testNamespaceA}
  2174  		updateOGSpecFunc := updateOperatorGroupSpecFunc(GinkgoT(), crc, testNamespaceA, operatorGroup.GetName())
  2175  		require.NoError(GinkgoT(), retry.RetryOnConflict(retry.DefaultBackoff, updateOGSpecFunc(operatorGroup.Spec)))
  2176  
  2177  		namespaceList, err = pollForNamespaceListCount(c, listOptions, 1)
  2178  		require.NoError(GinkgoT(), err)
  2179  		require.True(GinkgoT(), checkForOperatorGroupLabels(operatorGroup, namespaceList.Items))
  2180  
  2181  		By(`Update the OperatorGroup to include two namespaces`)
  2182  		operatorGroup.Spec.TargetNamespaces = []string{testNamespaceA, testNamespaceC}
  2183  		require.NoError(GinkgoT(), retry.RetryOnConflict(retry.DefaultBackoff, updateOGSpecFunc(operatorGroup.Spec)))
  2184  
  2185  		namespaceList, err = pollForNamespaceListCount(c, listOptions, 2)
  2186  		require.NoError(GinkgoT(), err)
  2187  		require.True(GinkgoT(), checkForOperatorGroupLabels(operatorGroup, namespaceList.Items))
  2188  
  2189  		By(`Update the OperatorGroup to include three namespaces`)
  2190  		operatorGroup.Spec.TargetNamespaces = []string{testNamespaceA, testNamespaceB, testNamespaceC}
  2191  		require.NoError(GinkgoT(), retry.RetryOnConflict(retry.DefaultBackoff, updateOGSpecFunc(operatorGroup.Spec)))
  2192  
  2193  		namespaceList, err = pollForNamespaceListCount(c, listOptions, 3)
  2194  		require.NoError(GinkgoT(), err)
  2195  		require.True(GinkgoT(), checkForOperatorGroupLabels(operatorGroup, namespaceList.Items))
  2196  
  2197  		By(`Update the OperatorGroup to include two namespaces`)
  2198  		operatorGroup.Spec.TargetNamespaces = []string{testNamespaceA, testNamespaceC}
  2199  		require.NoError(GinkgoT(), retry.RetryOnConflict(retry.DefaultBackoff, updateOGSpecFunc(operatorGroup.Spec)))
  2200  
  2201  		namespaceList, err = pollForNamespaceListCount(c, listOptions, 2)
  2202  		require.NoError(GinkgoT(), err)
  2203  		require.True(GinkgoT(), checkForOperatorGroupLabels(operatorGroup, namespaceList.Items))
  2204  
  2205  		By(`Make the OperatorGroup a Cluster OperatorGroup.`)
  2206  		operatorGroup.Spec.TargetNamespaces = []string{}
  2207  		require.NoError(GinkgoT(), retry.RetryOnConflict(retry.DefaultBackoff, updateOGSpecFunc(operatorGroup.Spec)))
  2208  
  2209  		namespaceList, err = pollForNamespaceListCount(c, listOptions, 0)
  2210  		require.NoError(GinkgoT(), err)
  2211  	})
  2212  	It("CleanupDeletedOperatorGroupLabels", func() {
  2213  
  2214  		By(`Create the namespaces that will have an OperatorGroup Label applied.`)
  2215  		testNamespaceA := genName("namespace-a-")
  2216  		testNamespaceB := genName("namespace-b-")
  2217  		testNamespaceC := genName("namespace-c-")
  2218  		testNamespaces := []string{
  2219  			testNamespaceA, testNamespaceB, testNamespaceC,
  2220  		}
  2221  
  2222  		By(`Create the namespaces`)
  2223  		for _, namespace := range testNamespaces {
  2224  			_, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
  2225  				ObjectMeta: metav1.ObjectMeta{
  2226  					Name: namespace,
  2227  				},
  2228  			}, metav1.CreateOptions{})
  2229  			require.NoError(GinkgoT(), err)
  2230  		}
  2231  
  2232  		By(`Cleanup namespaces`)
  2233  		defer func() {
  2234  			for _, namespace := range testNamespaces {
  2235  				err := c.KubernetesInterface().CoreV1().Namespaces().Delete(context.TODO(), namespace, metav1.DeleteOptions{})
  2236  				require.NoError(GinkgoT(), err)
  2237  			}
  2238  		}()
  2239  
  2240  		By(`Create an OperatorGroup with three target namespaces.`)
  2241  		operatorGroup := &v1.OperatorGroup{
  2242  			ObjectMeta: metav1.ObjectMeta{
  2243  				Name:      genName("e2e-operator-group-"),
  2244  				Namespace: testNamespaceA,
  2245  			},
  2246  			Spec: v1.OperatorGroupSpec{
  2247  				TargetNamespaces: testNamespaces,
  2248  			},
  2249  		}
  2250  		operatorGroup, err := crc.OperatorsV1().OperatorGroups(testNamespaceA).Create(context.TODO(), operatorGroup, metav1.CreateOptions{})
  2251  		require.NoError(GinkgoT(), err)
  2252  
  2253  		By(`Create the OperatorGroup Label`)
  2254  		ogLabel, err := getOGLabelKey(operatorGroup)
  2255  		require.NoError(GinkgoT(), err)
  2256  
  2257  		By(`Create list options`)
  2258  		listOptions := metav1.ListOptions{
  2259  			LabelSelector: labels.Set(map[string]string{ogLabel: ""}).String(),
  2260  		}
  2261  
  2262  		namespaceList, err := pollForNamespaceListCount(c, listOptions, 3)
  2263  		require.NoError(GinkgoT(), err)
  2264  		require.True(GinkgoT(), checkForOperatorGroupLabels(operatorGroup, namespaceList.Items))
  2265  
  2266  		By(`Delete the operatorGroup.`)
  2267  		err = crc.OperatorsV1().OperatorGroups(testNamespaceA).Delete(context.TODO(), operatorGroup.GetName(), metav1.DeleteOptions{})
  2268  		require.NoError(GinkgoT(), err)
  2269  
  2270  		By(`Check that no namespaces have the OperatorGroup.`)
  2271  		namespaceList, err = pollForNamespaceListCount(c, listOptions, 0)
  2272  		require.NoError(GinkgoT(), err)
  2273  	})
  2274  
  2275  	Context("Given a set of Namespaces", func() {
  2276  		var (
  2277  			c              operatorclient.ClientInterface
  2278  			crc            versioned.Interface
  2279  			testNamespaces []string
  2280  			testNamespaceA string
  2281  		)
  2282  
  2283  		BeforeEach(func() {
  2284  			c = newKubeClient()
  2285  			crc = newCRClient()
  2286  
  2287  			By(`Create the namespaces that will have an OperatorGroup Label applied.`)
  2288  			testNamespaceA = genName("namespace-a-")
  2289  			testNamespaceB := genName("namespace-b-")
  2290  			testNamespaceC := genName("namespace-c-")
  2291  			testNamespaces = []string{
  2292  				testNamespaceA, testNamespaceB, testNamespaceC,
  2293  			}
  2294  
  2295  			By(`Create the namespaces`)
  2296  			for _, namespace := range testNamespaces {
  2297  				_, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
  2298  					ObjectMeta: metav1.ObjectMeta{
  2299  						Name: namespace,
  2300  					},
  2301  				}, metav1.CreateOptions{})
  2302  				Expect(err).ToNot(HaveOccurred())
  2303  			}
  2304  		})
  2305  
  2306  		AfterEach(func() {
  2307  			By(`Cleanup namespaces`)
  2308  			for _, namespace := range testNamespaces {
  2309  				err := c.KubernetesInterface().CoreV1().Namespaces().Delete(context.TODO(), namespace, metav1.DeleteOptions{})
  2310  				Expect(err).ToNot(HaveOccurred())
  2311  			}
  2312  		})
  2313  
  2314  		Context("Associating these Namespaces with a label", func() {
  2315  			var (
  2316  				matchingLabel map[string]string
  2317  			)
  2318  
  2319  			BeforeEach(func() {
  2320  				matchingLabel = map[string]string{"foo": "bar"}
  2321  
  2322  				By(`Updating Namespace with labels`)
  2323  				for _, namespace := range testNamespaces {
  2324  					_, err := c.KubernetesInterface().CoreV1().Namespaces().Update(context.TODO(), &corev1.Namespace{
  2325  						ObjectMeta: metav1.ObjectMeta{
  2326  							Name:   namespace,
  2327  							Labels: matchingLabel,
  2328  						},
  2329  					}, metav1.UpdateOptions{})
  2330  					Expect(err).ToNot(HaveOccurred())
  2331  				}
  2332  
  2333  			})
  2334  
  2335  			When("an OperatorGroup is created having matching label selector defined", func() {
  2336  				var operatorGroup *v1.OperatorGroup
  2337  
  2338  				BeforeEach(func() {
  2339  					By(`Creating operator group`)
  2340  					operatorGroup = &v1.OperatorGroup{
  2341  						ObjectMeta: metav1.ObjectMeta{
  2342  							Name:      genName("e2e-operator-group-"),
  2343  							Namespace: testNamespaceA,
  2344  						},
  2345  						Spec: v1.OperatorGroupSpec{
  2346  							Selector: &metav1.LabelSelector{
  2347  								MatchLabels: matchingLabel,
  2348  							},
  2349  						},
  2350  					}
  2351  					var err error
  2352  					operatorGroup, err = crc.OperatorsV1().OperatorGroups(testNamespaceA).Create(context.TODO(), operatorGroup, metav1.CreateOptions{})
  2353  					Expect(err).ToNot(HaveOccurred())
  2354  				})
  2355  
  2356  				It("[FLAKE] OLM applies labels to Namespaces that are associated with an OperatorGroup", func() {
  2357  					By(`issue: https://github.com/operator-framework/operator-lifecycle-manager/issues/2637`)
  2358  					ogLabel, err := getOGLabelKey(operatorGroup)
  2359  					Expect(err).ToNot(HaveOccurred())
  2360  
  2361  					By(`Create list options`)
  2362  					listOptions := metav1.ListOptions{
  2363  						LabelSelector: labels.Set(map[string]string{ogLabel: ""}).String(),
  2364  					}
  2365  
  2366  					By(`Verify that all the namespaces listed in targetNamespaces field of OperatorGroup have labels applied on them`)
  2367  					namespaceList, err := pollForNamespaceListCount(c, listOptions, 3)
  2368  					Expect(err).ToNot(HaveOccurred())
  2369  					Expect(checkForOperatorGroupLabels(operatorGroup, namespaceList.Items)).Should(BeTrue())
  2370  				})
  2371  			})
  2372  		})
  2373  
  2374  		When("an OperatorGroup is created having above Namespaces defined under targetNamespaces field", func() {
  2375  			var operatorGroup *v1.OperatorGroup
  2376  
  2377  			BeforeEach(func() {
  2378  				By(`Create an OperatorGroup with three target namespaces.`)
  2379  				operatorGroup = &v1.OperatorGroup{
  2380  					ObjectMeta: metav1.ObjectMeta{
  2381  						Name:      genName("e2e-operator-group-"),
  2382  						Namespace: testNamespaceA,
  2383  					},
  2384  					Spec: v1.OperatorGroupSpec{
  2385  						TargetNamespaces: testNamespaces,
  2386  					},
  2387  				}
  2388  				var err error
  2389  				operatorGroup, err = crc.OperatorsV1().OperatorGroups(testNamespaceA).Create(context.TODO(), operatorGroup, metav1.CreateOptions{})
  2390  				Expect(err).ToNot(HaveOccurred())
  2391  			})
  2392  
  2393  			It("OLM applies labels to Namespaces that are associated with an OperatorGroup", func() {
  2394  
  2395  				ogLabel, err := getOGLabelKey(operatorGroup)
  2396  				Expect(err).ToNot(HaveOccurred())
  2397  
  2398  				By(`Create list options`)
  2399  				listOptions := metav1.ListOptions{
  2400  					LabelSelector: labels.Set(map[string]string{ogLabel: ""}).String(),
  2401  				}
  2402  
  2403  				By(`Verify that all the namespaces listed in targetNamespaces field of OperatorGroup have labels applied on them`)
  2404  				namespaceList, err := pollForNamespaceListCount(c, listOptions, 3)
  2405  				Expect(err).ToNot(HaveOccurred())
  2406  				Expect(checkForOperatorGroupLabels(operatorGroup, namespaceList.Items)).Should(BeTrue())
  2407  
  2408  			})
  2409  		})
  2410  	})
  2411  })
  2412  
  2413  func checkOperatorGroupAnnotations(obj metav1.Object, op *v1.OperatorGroup, checkTargetNamespaces bool, targetNamespaces string) error {
  2414  	if checkTargetNamespaces {
  2415  		if annotation, ok := obj.GetAnnotations()[v1.OperatorGroupTargetsAnnotationKey]; !ok || annotation != targetNamespaces {
  2416  			return fmt.Errorf("missing targetNamespaces annotation on %v", obj.GetName())
  2417  		}
  2418  	} else {
  2419  		if _, found := obj.GetAnnotations()[v1.OperatorGroupTargetsAnnotationKey]; found {
  2420  			return fmt.Errorf("targetNamespaces annotation unexpectedly found on %v", obj.GetName())
  2421  		}
  2422  	}
  2423  
  2424  	if annotation, ok := obj.GetAnnotations()[v1.OperatorGroupNamespaceAnnotationKey]; !ok || annotation != op.GetNamespace() {
  2425  		return fmt.Errorf("missing operatorNamespace on %v", obj.GetName())
  2426  	}
  2427  	if annotation, ok := obj.GetAnnotations()[v1.OperatorGroupAnnotationKey]; !ok || annotation != op.GetName() {
  2428  		return fmt.Errorf("missing operatorGroup annotation on %v", obj.GetName())
  2429  	}
  2430  
  2431  	return nil
  2432  }
  2433  
  2434  func newOperatorGroup(namespace, name string, annotations map[string]string, selector *metav1.LabelSelector, targetNamespaces []string, static bool) *v1.OperatorGroup {
  2435  	return &v1.OperatorGroup{
  2436  		ObjectMeta: metav1.ObjectMeta{
  2437  			Namespace:   namespace,
  2438  			Name:        name,
  2439  			Annotations: annotations,
  2440  		},
  2441  		Spec: v1.OperatorGroupSpec{
  2442  			TargetNamespaces:   targetNamespaces,
  2443  			Selector:           selector,
  2444  			StaticProvidedAPIs: static,
  2445  		},
  2446  	}
  2447  }
  2448  
  2449  func createProjectAdmin(t GinkgoTInterface, c operatorclient.ClientInterface, namespace string) (string, cleanupFunc) {
  2450  	sa, err := c.CreateServiceAccount(&corev1.ServiceAccount{
  2451  		ObjectMeta: metav1.ObjectMeta{
  2452  			Namespace: namespace,
  2453  			Name:      genName("padmin-"),
  2454  		},
  2455  	})
  2456  	require.NoError(t, err)
  2457  
  2458  	rb, err := c.CreateRoleBinding(&rbacv1.RoleBinding{
  2459  		ObjectMeta: metav1.ObjectMeta{
  2460  			Name:      genName("padmin-"),
  2461  			Namespace: namespace,
  2462  		},
  2463  		Subjects: []rbacv1.Subject{
  2464  			{
  2465  				Kind:      "ServiceAccount",
  2466  				Name:      sa.GetName(),
  2467  				Namespace: sa.GetNamespace(),
  2468  			},
  2469  		},
  2470  		RoleRef: rbacv1.RoleRef{
  2471  			APIGroup: "rbac.authorization.k8s.io",
  2472  			Kind:     "ClusterRole",
  2473  			Name:     "admin",
  2474  		},
  2475  	})
  2476  	require.NoError(t, err)
  2477  
  2478  	return "system:serviceaccount:" + namespace + ":" + sa.GetName(), func() {
  2479  		_ = c.DeleteServiceAccount(sa.GetNamespace(), sa.GetName(), metav1.NewDeleteOptions(0))
  2480  		_ = c.DeleteRoleBinding(rb.GetNamespace(), rb.GetName(), metav1.NewDeleteOptions(0))
  2481  	}
  2482  }
  2483  
  2484  func checkForOperatorGroupLabels(operatorGroup *v1.OperatorGroup, namespaces []corev1.Namespace) bool {
  2485  	for _, ns := range operatorGroup.Spec.TargetNamespaces {
  2486  		if !containsNamespace(namespaces, ns) {
  2487  			return false
  2488  		}
  2489  	}
  2490  	return true
  2491  }
  2492  
  2493  func updateOperatorGroupSpecFunc(t GinkgoTInterface, crc versioned.Interface, namespace, operatorGroupName string) func(v1.OperatorGroupSpec) func() error {
  2494  	return func(operatorGroupSpec v1.OperatorGroupSpec) func() error {
  2495  		return func() error {
  2496  			fetchedOG, err := crc.OperatorsV1().OperatorGroups(namespace).Get(context.TODO(), operatorGroupName, metav1.GetOptions{})
  2497  			require.NoError(t, err)
  2498  			fetchedOG.Spec = operatorGroupSpec
  2499  			_, err = crc.OperatorsV1().OperatorGroups(namespace).Update(context.TODO(), fetchedOG, metav1.UpdateOptions{})
  2500  			return err
  2501  		}
  2502  	}
  2503  }
  2504  
  2505  func pollForNamespaceListCount(c operatorclient.ClientInterface, listOptions metav1.ListOptions, expectedLength int) (list *corev1.NamespaceList, err error) {
  2506  	Eventually(func() (bool, error) {
  2507  		list, err = c.KubernetesInterface().CoreV1().Namespaces().List(context.TODO(), listOptions)
  2508  		if err != nil {
  2509  			return false, err
  2510  		}
  2511  		if len(list.Items) == expectedLength {
  2512  			return true, nil
  2513  		}
  2514  		return false, nil
  2515  	}).Should(BeTrue())
  2516  	return
  2517  }
  2518  
  2519  func containsNamespace(namespaces []corev1.Namespace, namespaceName string) bool {
  2520  	for i := range namespaces {
  2521  		if namespaces[i].GetName() == namespaceName {
  2522  			return true
  2523  		}
  2524  	}
  2525  	return false
  2526  }
  2527  
  2528  func getOGLabelKey(og *v1.OperatorGroup) (string, error) {
  2529  	ogUID := string(og.GetUID())
  2530  	if ogUID == "" {
  2531  		return "", fmt.Errorf("OperatorGroup UID is empty string")
  2532  	}
  2533  	return fmt.Sprintf("olm.operatorgroup.uid/%s", og.GetUID()), nil
  2534  }