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

     1  package e2e
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"strconv"
     8  	"strings"
     9  	"time"
    10  
    11  	. "github.com/onsi/ginkgo/v2"
    12  	. "github.com/onsi/gomega"
    13  	"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned"
    14  	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
    15  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
    16  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil"
    17  	appsv1 "k8s.io/api/apps/v1"
    18  	corev1 "k8s.io/api/core/v1"
    19  	rbacv1 "k8s.io/api/rbac/v1"
    20  	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    21  	"k8s.io/apimachinery/pkg/api/equality"
    22  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    23  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    24  	k8slabels "k8s.io/apimachinery/pkg/labels"
    25  	"k8s.io/apimachinery/pkg/util/diff"
    26  	"k8s.io/apimachinery/pkg/util/intstr"
    27  	"k8s.io/apimachinery/pkg/util/wait"
    28  	"k8s.io/apimachinery/pkg/watch"
    29  	apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
    30  	"sigs.k8s.io/controller-runtime/pkg/client"
    31  
    32  	operatorsv1 "github.com/operator-framework/api/pkg/operators/v1"
    33  	operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
    34  	"github.com/operator-framework/operator-lifecycle-manager/test/e2e/ctx"
    35  )
    36  
    37  var _ = Describe("ClusterServiceVersion", func() {
    38  	var (
    39  		generatedNamespace corev1.Namespace
    40  		c                  operatorclient.ClientInterface
    41  		crc                versioned.Interface
    42  	)
    43  
    44  	BeforeEach(func() {
    45  		c = ctx.Ctx().KubeClient()
    46  		crc = ctx.Ctx().OperatorClient()
    47  	})
    48  
    49  	AfterEach(func() {
    50  		TeardownNamespace(generatedNamespace.GetName())
    51  	})
    52  
    53  	Context("OwnNamespace OperatorGroup", func() {
    54  
    55  		BeforeEach(func() {
    56  			nsName := genName("csv-e2e-")
    57  			generatedNamespace = SetupGeneratedTestNamespace(nsName, nsName)
    58  		})
    59  
    60  		When("a CustomResourceDefinition was installed alongside a ClusterServiceVersion", func() {
    61  			var (
    62  				crd         apiextensionsv1.CustomResourceDefinition
    63  				apiname     string
    64  				apifullname string
    65  			)
    66  
    67  			BeforeEach(func() {
    68  				apiname = genName("api")
    69  				apifullname = apiname + "s.example.com"
    70  				crd = apiextensionsv1.CustomResourceDefinition{
    71  					ObjectMeta: metav1.ObjectMeta{
    72  						Name: apifullname,
    73  						Annotations: map[string]string{
    74  							"operatorframework.io/installed-alongside-0": fmt.Sprintf("%s/associated-csv", generatedNamespace.GetName()),
    75  						},
    76  					},
    77  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
    78  						Group: "example.com",
    79  						Scope: apiextensionsv1.ClusterScoped,
    80  						Names: apiextensionsv1.CustomResourceDefinitionNames{
    81  							Plural:   apiname + "s",
    82  							Singular: apiname,
    83  							Kind:     strings.Title(apiname),
    84  							ListKind: strings.Title(apiname) + "List",
    85  						},
    86  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{{
    87  							Name:    "v1",
    88  							Served:  true,
    89  							Storage: true,
    90  							Schema: &apiextensionsv1.CustomResourceValidation{
    91  								OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
    92  									Type: "object",
    93  								},
    94  							},
    95  						}},
    96  					},
    97  				}
    98  				Eventually(func() error {
    99  					return ctx.Ctx().Client().Create(context.Background(), &crd)
   100  				}).Should(Succeed())
   101  			})
   102  
   103  			AfterEach(func() {
   104  				Eventually(func() error {
   105  					return ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.TODO(), crd.GetName(), metav1.DeleteOptions{})
   106  				}).Should(Succeed())
   107  			})
   108  
   109  			It("[FLAKE] can satisfy an associated ClusterServiceVersion's ownership requirement", func() {
   110  				associated := operatorsv1alpha1.ClusterServiceVersion{
   111  					ObjectMeta: metav1.ObjectMeta{
   112  						Name:      "associated-csv",
   113  						Namespace: generatedNamespace.GetName(),
   114  					},
   115  					Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
   116  						CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{
   117  							Owned: []operatorsv1alpha1.CRDDescription{{
   118  								Name:    apifullname,
   119  								Version: "v1",
   120  								Kind:    "Test",
   121  							}},
   122  						},
   123  						InstallStrategy: newNginxInstallStrategy(genName("deployment-"), nil, nil),
   124  						InstallModes: []operatorsv1alpha1.InstallMode{
   125  							{
   126  								Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
   127  								Supported: true,
   128  							},
   129  						},
   130  					},
   131  				}
   132  				Expect(ctx.Ctx().Client().Create(context.Background(), &associated)).To(Succeed())
   133  
   134  				Eventually(func() ([]operatorsv1alpha1.RequirementStatus, error) {
   135  					if err := ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(&associated), &associated); err != nil {
   136  						return nil, err
   137  					}
   138  					var result []operatorsv1alpha1.RequirementStatus
   139  					for _, s := range associated.Status.RequirementStatus {
   140  						result = append(result, operatorsv1alpha1.RequirementStatus{
   141  							Group:   s.Group,
   142  							Version: s.Version,
   143  							Kind:    s.Kind,
   144  							Name:    s.Name,
   145  							Status:  s.Status,
   146  						})
   147  					}
   148  					return result, nil
   149  				}).Should(ContainElement(
   150  					operatorsv1alpha1.RequirementStatus{
   151  						Group:   apiextensionsv1.SchemeGroupVersion.Group,
   152  						Version: apiextensionsv1.SchemeGroupVersion.Version,
   153  						Kind:    "CustomResourceDefinition",
   154  						Name:    crd.GetName(),
   155  						Status:  operatorsv1alpha1.RequirementStatusReasonPresent,
   156  					},
   157  				))
   158  
   159  				Eventually(func() error {
   160  					return ctx.Ctx().Client().Delete(context.Background(), &associated)
   161  				}).Should(Succeed())
   162  			})
   163  
   164  			// Without this exception, upgrades can become blocked
   165  			// when the original CSV's CRD requirement becomes
   166  			// unsatisfied.
   167  			It("can satisfy an unassociated ClusterServiceVersion's ownership requirement if replaced by an associated ClusterServiceVersion", func() {
   168  				unassociated := operatorsv1alpha1.ClusterServiceVersion{
   169  					ObjectMeta: metav1.ObjectMeta{
   170  						Name:      "unassociated-csv",
   171  						Namespace: generatedNamespace.GetName(),
   172  					},
   173  					Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
   174  						CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{
   175  							Owned: []operatorsv1alpha1.CRDDescription{{
   176  								Name:    apifullname,
   177  								Version: "v1",
   178  								Kind:    "Test",
   179  							}},
   180  						},
   181  						InstallStrategy: newNginxInstallStrategy(genName("deployment-"), nil, nil),
   182  						InstallModes: []operatorsv1alpha1.InstallMode{
   183  							{
   184  								Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
   185  								Supported: true,
   186  							},
   187  						},
   188  					},
   189  				}
   190  				Expect(ctx.Ctx().Client().Create(context.Background(), &unassociated)).To(Succeed())
   191  
   192  				associated := operatorsv1alpha1.ClusterServiceVersion{
   193  					ObjectMeta: metav1.ObjectMeta{
   194  						Name:      "associated-csv",
   195  						Namespace: generatedNamespace.GetName(),
   196  					},
   197  					Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
   198  						CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{
   199  							Owned: []operatorsv1alpha1.CRDDescription{{
   200  								Name:    apifullname,
   201  								Version: "v1",
   202  								Kind:    "Test",
   203  							}},
   204  						},
   205  						InstallStrategy: newNginxInstallStrategy(genName("deployment-"), nil, nil),
   206  						InstallModes: []operatorsv1alpha1.InstallMode{
   207  							{
   208  								Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
   209  								Supported: true,
   210  							},
   211  						},
   212  						Replaces: unassociated.GetName(),
   213  					},
   214  				}
   215  				Expect(ctx.Ctx().Client().Create(context.Background(), &associated)).To(Succeed())
   216  
   217  				Eventually(func() error {
   218  					return ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(&unassociated), &unassociated)
   219  				}).Should(WithTransform(apierrors.IsNotFound, BeTrue()))
   220  
   221  				Eventually(func() error {
   222  					return ctx.Ctx().Client().Delete(context.Background(), &associated)
   223  				}).Should(Succeed())
   224  			})
   225  
   226  			It("can satisfy an unassociated ClusterServiceVersion's non-ownership requirement", func() {
   227  				unassociated := operatorsv1alpha1.ClusterServiceVersion{
   228  					ObjectMeta: metav1.ObjectMeta{
   229  						Name:      "unassociated-csv",
   230  						Namespace: generatedNamespace.GetName(),
   231  					},
   232  					Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
   233  						CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{
   234  							Required: []operatorsv1alpha1.CRDDescription{{
   235  								Name:    apifullname,
   236  								Version: "v1",
   237  								Kind:    "Test",
   238  							}},
   239  						},
   240  						InstallStrategy: newNginxInstallStrategy(genName("deployment-"), nil, nil),
   241  						InstallModes: []operatorsv1alpha1.InstallMode{
   242  							{
   243  								Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
   244  								Supported: true,
   245  							},
   246  						},
   247  					},
   248  				}
   249  				Expect(ctx.Ctx().Client().Create(context.Background(), &unassociated)).To(Succeed())
   250  
   251  				Eventually(func() ([]operatorsv1alpha1.RequirementStatus, error) {
   252  					if err := ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(&unassociated), &unassociated); err != nil {
   253  						return nil, err
   254  					}
   255  					var result []operatorsv1alpha1.RequirementStatus
   256  					for _, s := range unassociated.Status.RequirementStatus {
   257  						result = append(result, operatorsv1alpha1.RequirementStatus{
   258  							Group:   s.Group,
   259  							Version: s.Version,
   260  							Kind:    s.Kind,
   261  							Name:    s.Name,
   262  							Status:  s.Status,
   263  						})
   264  					}
   265  					return result, nil
   266  				}).Should(ContainElement(
   267  					operatorsv1alpha1.RequirementStatus{
   268  						Group:   apiextensionsv1.SchemeGroupVersion.Group,
   269  						Version: apiextensionsv1.SchemeGroupVersion.Version,
   270  						Kind:    "CustomResourceDefinition",
   271  						Name:    crd.GetName(),
   272  						Status:  operatorsv1alpha1.RequirementStatusReasonPresent,
   273  					},
   274  				))
   275  				Eventually(func() error {
   276  					return ctx.Ctx().Client().Delete(context.Background(), &unassociated)
   277  				}).Should(Succeed())
   278  			})
   279  		})
   280  
   281  		When("an unassociated ClusterServiceVersion in different namespace owns the same CRD", func() {
   282  			var (
   283  				crd         apiextensionsv1.CustomResourceDefinition
   284  				apiname     string
   285  				apifullname string
   286  			)
   287  
   288  			BeforeEach(func() {
   289  				apiname = genName("api")
   290  				apifullname = apiname + "s.example.com"
   291  				crd = apiextensionsv1.CustomResourceDefinition{
   292  					ObjectMeta: metav1.ObjectMeta{
   293  						Name: apifullname,
   294  						Annotations: map[string]string{
   295  							"operatorframework.io/installed-alongside-0": fmt.Sprintf("%s/associated-csv", generatedNamespace.GetName()),
   296  						},
   297  					},
   298  					Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   299  						Group: "example.com",
   300  						Scope: apiextensionsv1.ClusterScoped,
   301  						Names: apiextensionsv1.CustomResourceDefinitionNames{
   302  							Plural:   apiname + "s",
   303  							Singular: apiname,
   304  							Kind:     strings.Title(apiname),
   305  							ListKind: strings.Title(apiname) + "List",
   306  						},
   307  						Versions: []apiextensionsv1.CustomResourceDefinitionVersion{{
   308  							Name:    "v1",
   309  							Served:  true,
   310  							Storage: true,
   311  							Schema: &apiextensionsv1.CustomResourceValidation{
   312  								OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
   313  									Type: "object",
   314  								},
   315  							},
   316  						}},
   317  					},
   318  				}
   319  				Eventually(func() error {
   320  					return ctx.Ctx().Client().Create(context.Background(), &crd)
   321  				}).Should(Succeed())
   322  			})
   323  
   324  			It("can satisfy the unassociated ClusterServiceVersion's ownership requirement", func() {
   325  				associated := operatorsv1alpha1.ClusterServiceVersion{
   326  					ObjectMeta: metav1.ObjectMeta{
   327  						Name:      "associated-csv",
   328  						Namespace: generatedNamespace.GetName(),
   329  					},
   330  					Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
   331  						CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{
   332  							Owned: []operatorsv1alpha1.CRDDescription{{
   333  								Name:    apifullname,
   334  								Version: "v1",
   335  								Kind:    "Test",
   336  							}},
   337  						},
   338  						InstallStrategy: newNginxInstallStrategy(genName("deployment-"), nil, nil),
   339  						InstallModes: []operatorsv1alpha1.InstallMode{
   340  							{
   341  								Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
   342  								Supported: true,
   343  							},
   344  						},
   345  					},
   346  				}
   347  				Expect(ctx.Ctx().Client().Create(context.Background(), &associated)).To(Succeed())
   348  
   349  				unassociated := operatorsv1alpha1.ClusterServiceVersion{
   350  					ObjectMeta: metav1.ObjectMeta{
   351  						Name:      "unassociated-csv",
   352  						Namespace: generatedNamespace.GetName(),
   353  					},
   354  					Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
   355  						CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{
   356  							Owned: []operatorsv1alpha1.CRDDescription{{
   357  								Name:    apifullname,
   358  								Version: "v1",
   359  								Kind:    "Test",
   360  							}},
   361  						},
   362  						InstallStrategy: newNginxInstallStrategy(genName("deployment-"), nil, nil),
   363  						InstallModes: []operatorsv1alpha1.InstallMode{
   364  							{
   365  								Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
   366  								Supported: true,
   367  							},
   368  						},
   369  					},
   370  				}
   371  				Expect(ctx.Ctx().Client().Create(context.Background(), &unassociated)).To(Succeed())
   372  
   373  				Eventually(func() ([]operatorsv1alpha1.RequirementStatus, error) {
   374  					if err := ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(&unassociated), &unassociated); err != nil {
   375  						return nil, err
   376  					}
   377  					var result []operatorsv1alpha1.RequirementStatus
   378  					for _, s := range unassociated.Status.RequirementStatus {
   379  						result = append(result, operatorsv1alpha1.RequirementStatus{
   380  							Group:   s.Group,
   381  							Version: s.Version,
   382  							Kind:    s.Kind,
   383  							Name:    s.Name,
   384  							Status:  s.Status,
   385  						})
   386  					}
   387  					return result, nil
   388  				}).Should(ContainElement(
   389  					operatorsv1alpha1.RequirementStatus{
   390  						Group:   apiextensionsv1.SchemeGroupVersion.Group,
   391  						Version: apiextensionsv1.SchemeGroupVersion.Version,
   392  						Kind:    "CustomResourceDefinition",
   393  						Name:    crd.GetName(),
   394  						Status:  operatorsv1alpha1.RequirementStatusReasonPresent,
   395  					},
   396  				))
   397  			})
   398  		})
   399  	})
   400  
   401  	Context("AllNamespaces OperatorGroup", func() {
   402  		BeforeEach(func() {
   403  			generatedNamespace = SetupGeneratedTestNamespace(genName("csv-e2e-"))
   404  		})
   405  
   406  		When("a csv exists specifying two replicas with one max unavailable", func() {
   407  			var (
   408  				csv operatorsv1alpha1.ClusterServiceVersion
   409  			)
   410  
   411  			const (
   412  				TestReadinessGate = "operatorframework.io/test-readiness-gate"
   413  			)
   414  
   415  			BeforeEach(func() {
   416  				csv = operatorsv1alpha1.ClusterServiceVersion{
   417  					ObjectMeta: metav1.ObjectMeta{
   418  						GenerateName: "test-csv",
   419  						Namespace:    generatedNamespace.GetName(),
   420  					},
   421  					Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
   422  						InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
   423  							StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
   424  							StrategySpec: operatorsv1alpha1.StrategyDetailsDeployment{
   425  								DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
   426  									{
   427  										Name: "deployment",
   428  										Spec: appsv1.DeploymentSpec{
   429  											Strategy: appsv1.DeploymentStrategy{
   430  												Type: appsv1.RollingUpdateDeploymentStrategyType,
   431  												RollingUpdate: &appsv1.RollingUpdateDeployment{
   432  													MaxUnavailable: &[]intstr.IntOrString{intstr.FromInt(1)}[0],
   433  												},
   434  											},
   435  											Selector: &metav1.LabelSelector{
   436  												MatchLabels: map[string]string{"app": "foobar"},
   437  											},
   438  											Replicas: &[]int32{2}[0],
   439  											Template: corev1.PodTemplateSpec{
   440  												ObjectMeta: metav1.ObjectMeta{
   441  													Labels: map[string]string{"app": "foobar"},
   442  												},
   443  												Spec: corev1.PodSpec{
   444  													Containers: []corev1.Container{
   445  														{
   446  															Name:  "foobar",
   447  															Image: *dummyImage,
   448  														},
   449  													},
   450  													ReadinessGates: []corev1.PodReadinessGate{
   451  														{ConditionType: TestReadinessGate},
   452  													},
   453  												},
   454  											},
   455  										},
   456  									},
   457  								},
   458  							},
   459  						},
   460  						InstallModes: []operatorsv1alpha1.InstallMode{{
   461  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
   462  							Supported: true,
   463  						}},
   464  					},
   465  				}
   466  				Expect(ctx.Ctx().Client().Create(context.Background(), &csv)).To(Succeed())
   467  
   468  				Eventually(func() (*operatorsv1alpha1.ClusterServiceVersion, error) {
   469  					var ps corev1.PodList
   470  					if err := ctx.Ctx().Client().List(context.Background(), &ps, client.MatchingLabels{"app": "foobar"}); err != nil {
   471  						return nil, err
   472  					}
   473  
   474  					if len(ps.Items) != 2 {
   475  						return nil, fmt.Errorf("%d pods match deployment selector, want %d", len(ps.Items), 2)
   476  					}
   477  
   478  					for _, pod := range ps.Items {
   479  						index := -1
   480  						for i, c := range pod.Status.Conditions {
   481  							if c.Type == TestReadinessGate {
   482  								index = i
   483  								break
   484  							}
   485  						}
   486  						if index == -1 {
   487  							index = len(pod.Status.Conditions)
   488  							pod.Status.Conditions = append(pod.Status.Conditions, corev1.PodCondition{Type: TestReadinessGate})
   489  						}
   490  						if pod.Status.Conditions[index].Status == corev1.ConditionTrue {
   491  							continue
   492  						}
   493  						pod.Status.Conditions[index].Status = corev1.ConditionTrue
   494  						if err := ctx.Ctx().Client().Status().Update(context.Background(), &pod); err != nil {
   495  							return nil, err
   496  						}
   497  					}
   498  
   499  					if err := ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(&csv), &csv); err != nil {
   500  						return nil, err
   501  					}
   502  					return &csv, nil
   503  				}).Should(CSVHasPhase(operatorsv1alpha1.CSVPhaseSucceeded))
   504  			})
   505  
   506  			It("remains in phase Succeeded when only one pod is available", func() {
   507  				Eventually(func() int32 {
   508  					dep, err := c.GetDeployment(generatedNamespace.GetName(), "deployment")
   509  					if err != nil || dep == nil {
   510  						return 0
   511  					}
   512  					return dep.Status.ReadyReplicas
   513  				}).Should(Equal(int32(2)))
   514  
   515  				var ps corev1.PodList
   516  				Expect(ctx.Ctx().Client().List(context.Background(), &ps, client.MatchingLabels{"app": "foobar"})).To(Succeed())
   517  				Expect(ps.Items).To(Not(BeEmpty()))
   518  
   519  				Expect(ctx.Ctx().Client().Delete(context.Background(), &ps.Items[0])).To(Succeed())
   520  
   521  				Consistently(func() (*operatorsv1alpha1.ClusterServiceVersion, error) {
   522  					return &csv, ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(&csv), &csv)
   523  				}).Should(CSVHasPhase(operatorsv1alpha1.CSVPhaseSucceeded))
   524  			})
   525  		})
   526  		When("a copied csv exists", func() {
   527  			var (
   528  				target   corev1.Namespace
   529  				original operatorsv1alpha1.ClusterServiceVersion
   530  				copyCSV  operatorsv1alpha1.ClusterServiceVersion
   531  			)
   532  
   533  			BeforeEach(func() {
   534  				target = corev1.Namespace{
   535  					ObjectMeta: metav1.ObjectMeta{
   536  						GenerateName: "watched-",
   537  					},
   538  				}
   539  				Expect(ctx.Ctx().Client().Create(context.Background(), &target)).To(Succeed())
   540  
   541  				original = operatorsv1alpha1.ClusterServiceVersion{
   542  					TypeMeta: metav1.TypeMeta{
   543  						Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
   544  						APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
   545  					},
   546  					ObjectMeta: metav1.ObjectMeta{
   547  						GenerateName: "csv-",
   548  						Namespace:    generatedNamespace.GetName(),
   549  					},
   550  					Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
   551  						InstallStrategy: newNginxInstallStrategy(genName("csv-"), nil, nil),
   552  						InstallModes: []operatorsv1alpha1.InstallMode{
   553  							{
   554  								Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
   555  								Supported: true,
   556  							},
   557  						},
   558  					},
   559  				}
   560  				Expect(ctx.Ctx().Client().Create(context.Background(), &original)).To(Succeed())
   561  
   562  				Eventually(func() error {
   563  					key := client.ObjectKeyFromObject(&original)
   564  					key.Namespace = target.GetName()
   565  					return ctx.Ctx().Client().Get(context.Background(), key, &copyCSV)
   566  				}).Should(Succeed())
   567  			})
   568  
   569  			AfterEach(func() {
   570  				TeardownNamespace(target.GetName())
   571  			})
   572  
   573  			It("is synchronized with the original csv", func() {
   574  				Eventually(func() error {
   575  					key := client.ObjectKeyFromObject(&copyCSV)
   576  
   577  					key.Namespace = target.Name
   578  					if err := ctx.Ctx().Client().Get(context.Background(), key, &copyCSV); err != nil {
   579  						return err
   580  					}
   581  
   582  					copyCSV.Status.LastUpdateTime = &metav1.Time{Time: time.Unix(1, 0)}
   583  					return ctx.Ctx().Client().Status().Update(context.Background(), &copyCSV)
   584  				}).Should(Succeed())
   585  
   586  				Eventually(func() (bool, error) {
   587  					key := client.ObjectKeyFromObject(&original)
   588  
   589  					if err := ctx.Ctx().Client().Get(context.Background(), key, &original); err != nil {
   590  						return false, err
   591  					}
   592  
   593  					key.Namespace = target.Name
   594  					if err := ctx.Ctx().Client().Get(context.Background(), key, &copyCSV); err != nil {
   595  						return false, err
   596  					}
   597  
   598  					return original.Status.LastUpdateTime.Equal(copyCSV.Status.LastUpdateTime), nil
   599  				}).Should(BeTrue(), "Change to status of copy should have been reverted")
   600  			})
   601  		})
   602  		When("a csv requires a serviceaccount solely owned by a non-csv", func() {
   603  			var (
   604  				cm  corev1.ConfigMap
   605  				sa  corev1.ServiceAccount
   606  				csv operatorsv1alpha1.ClusterServiceVersion
   607  			)
   608  
   609  			BeforeEach(func() {
   610  				cm = corev1.ConfigMap{
   611  					ObjectMeta: metav1.ObjectMeta{
   612  						GenerateName: "cm-",
   613  						Namespace:    generatedNamespace.GetName(),
   614  					},
   615  				}
   616  				Expect(ctx.Ctx().Client().Create(context.Background(), &cm)).To(Succeed())
   617  
   618  				sa = corev1.ServiceAccount{
   619  					ObjectMeta: metav1.ObjectMeta{
   620  						GenerateName: "sa-",
   621  						Namespace:    generatedNamespace.GetName(),
   622  						OwnerReferences: []metav1.OwnerReference{
   623  							{
   624  								Name:       cm.GetName(),
   625  								APIVersion: corev1.SchemeGroupVersion.String(),
   626  								Kind:       "ConfigMap",
   627  								UID:        cm.GetUID(),
   628  							},
   629  						},
   630  					},
   631  				}
   632  				Expect(ctx.Ctx().Client().Create(context.Background(), &sa)).To(Succeed())
   633  
   634  				csv = operatorsv1alpha1.ClusterServiceVersion{
   635  					TypeMeta: metav1.TypeMeta{
   636  						Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
   637  						APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
   638  					},
   639  					ObjectMeta: metav1.ObjectMeta{
   640  						GenerateName: "csv-",
   641  						Namespace:    generatedNamespace.GetName(),
   642  					},
   643  					Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
   644  						InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
   645  							StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
   646  							StrategySpec: operatorsv1alpha1.StrategyDetailsDeployment{
   647  								DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
   648  									{
   649  										Name: "foo",
   650  										Spec: appsv1.DeploymentSpec{
   651  											Selector: &metav1.LabelSelector{
   652  												MatchLabels: map[string]string{"app": "foo"},
   653  											},
   654  											Template: corev1.PodTemplateSpec{
   655  												ObjectMeta: metav1.ObjectMeta{
   656  													Labels: map[string]string{"app": "foo"},
   657  												},
   658  												Spec: corev1.PodSpec{Containers: []corev1.Container{
   659  													{
   660  														Name:  genName("foo"),
   661  														Image: *dummyImage,
   662  													},
   663  												}},
   664  											},
   665  										},
   666  									},
   667  								},
   668  								Permissions: []operatorsv1alpha1.StrategyDeploymentPermissions{
   669  									{
   670  										ServiceAccountName: sa.GetName(),
   671  										Rules:              []rbacv1.PolicyRule{},
   672  									},
   673  								},
   674  							},
   675  						},
   676  						InstallModes: []operatorsv1alpha1.InstallMode{
   677  							{
   678  								Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
   679  								Supported: true,
   680  							},
   681  						},
   682  					},
   683  				}
   684  				Expect(ctx.Ctx().Client().Create(context.Background(), &csv)).To(Succeed())
   685  			})
   686  
   687  			AfterEach(func() {
   688  				if cm.GetName() != "" {
   689  					Expect(ctx.Ctx().Client().Delete(context.Background(), &cm)).To(Succeed())
   690  				}
   691  			})
   692  
   693  			It("considers the serviceaccount requirement satisfied", func() {
   694  				Eventually(func() (operatorsv1alpha1.StatusReason, error) {
   695  					if err := ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(&csv), &csv); err != nil {
   696  						return "", err
   697  					}
   698  					for _, requirement := range csv.Status.RequirementStatus {
   699  						if requirement.Name != sa.GetName() {
   700  							continue
   701  						}
   702  						return requirement.Status, nil
   703  					}
   704  					return "", fmt.Errorf("missing expected requirement %q", sa.GetName())
   705  				}).Should(Equal(operatorsv1alpha1.RequirementStatusReasonPresent))
   706  			})
   707  		})
   708  
   709  		It("create with unmet requirements min kube version", func() {
   710  
   711  			depName := genName("dep-")
   712  			csv := operatorsv1alpha1.ClusterServiceVersion{
   713  				TypeMeta: metav1.TypeMeta{
   714  					Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
   715  					APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
   716  				},
   717  				ObjectMeta: metav1.ObjectMeta{
   718  					Name: genName("csv"),
   719  				},
   720  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
   721  					MinKubeVersion: "999.999.999",
   722  					InstallModes: []operatorsv1alpha1.InstallMode{
   723  						{
   724  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
   725  							Supported: true,
   726  						},
   727  						{
   728  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
   729  							Supported: true,
   730  						},
   731  						{
   732  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
   733  							Supported: true,
   734  						},
   735  						{
   736  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
   737  							Supported: true,
   738  						},
   739  					},
   740  					InstallStrategy: newNginxInstallStrategy(depName, nil, nil),
   741  				},
   742  			}
   743  
   744  			cleanupCSV, err := createCSV(c, crc, csv, generatedNamespace.GetName(), false, false)
   745  			Expect(err).ShouldNot(HaveOccurred())
   746  			defer cleanupCSV()
   747  
   748  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvPendingChecker)
   749  			Expect(err).ShouldNot(HaveOccurred())
   750  
   751  			By("Shouldn't create deployment")
   752  			Consistently(func() bool {
   753  				_, err := c.GetDeployment(generatedNamespace.GetName(), depName)
   754  				return apierrors.IsNotFound(err)
   755  			}).Should(BeTrue())
   756  		})
   757  		// TODO: same test but missing serviceaccount instead
   758  		It("create with unmet requirements CRD", func() {
   759  
   760  			depName := genName("dep-")
   761  			csv := operatorsv1alpha1.ClusterServiceVersion{
   762  				TypeMeta: metav1.TypeMeta{
   763  					Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
   764  					APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
   765  				},
   766  				ObjectMeta: metav1.ObjectMeta{
   767  					Name: genName("csv"),
   768  				},
   769  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
   770  					MinKubeVersion: "0.0.0",
   771  					InstallModes: []operatorsv1alpha1.InstallMode{
   772  						{
   773  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
   774  							Supported: true,
   775  						},
   776  						{
   777  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
   778  							Supported: true,
   779  						},
   780  						{
   781  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
   782  							Supported: true,
   783  						},
   784  						{
   785  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
   786  							Supported: true,
   787  						},
   788  					},
   789  
   790  					InstallStrategy: newNginxInstallStrategy(depName, nil, nil),
   791  					CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{
   792  						Owned: []operatorsv1alpha1.CRDDescription{
   793  							{
   794  								DisplayName: "Not In Cluster",
   795  								Description: "A CRD that is not currently in the cluster",
   796  								Name:        "not.in.cluster.com",
   797  								Version:     "v1alpha1",
   798  								Kind:        "NotInCluster",
   799  							},
   800  						},
   801  					},
   802  				},
   803  			}
   804  
   805  			cleanupCSV, err := createCSV(c, crc, csv, generatedNamespace.GetName(), false, false)
   806  			Expect(err).ShouldNot(HaveOccurred())
   807  			defer cleanupCSV()
   808  
   809  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvPendingChecker)
   810  			Expect(err).ShouldNot(HaveOccurred())
   811  
   812  			By("Shouldn't create deployment")
   813  			Consistently(func() bool {
   814  				_, err := c.GetDeployment(generatedNamespace.GetName(), depName)
   815  				return apierrors.IsNotFound(err)
   816  			}).Should(BeTrue())
   817  		})
   818  
   819  		It("create with unmet permissions CRD", func() {
   820  			saName := genName("dep-")
   821  			permissions := []operatorsv1alpha1.StrategyDeploymentPermissions{
   822  				{
   823  					ServiceAccountName: saName,
   824  					Rules: []rbacv1.PolicyRule{
   825  						{
   826  							Verbs:     []string{"create"},
   827  							APIGroups: []string{""},
   828  							Resources: []string{"deployment"},
   829  						},
   830  					},
   831  				},
   832  			}
   833  
   834  			clusterPermissions := []operatorsv1alpha1.StrategyDeploymentPermissions{
   835  				{
   836  					ServiceAccountName: saName,
   837  					Rules: []rbacv1.PolicyRule{
   838  						{
   839  							Verbs:     []string{"get"},
   840  							APIGroups: []string{""},
   841  							Resources: []string{"deployment"},
   842  						},
   843  					},
   844  				},
   845  			}
   846  
   847  			crdPlural := genName("ins")
   848  			crdName := crdPlural + ".cluster.com"
   849  			depName := genName("dep-")
   850  			csv := operatorsv1alpha1.ClusterServiceVersion{
   851  				TypeMeta: metav1.TypeMeta{
   852  					Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
   853  					APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
   854  				},
   855  				ObjectMeta: metav1.ObjectMeta{
   856  					Name: genName("csv"),
   857  				},
   858  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
   859  					InstallModes: []operatorsv1alpha1.InstallMode{
   860  						{
   861  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
   862  							Supported: true,
   863  						},
   864  						{
   865  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
   866  							Supported: true,
   867  						},
   868  						{
   869  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
   870  							Supported: true,
   871  						},
   872  						{
   873  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
   874  							Supported: true,
   875  						},
   876  					},
   877  					InstallStrategy: newNginxInstallStrategy(depName, permissions, clusterPermissions),
   878  					CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{
   879  						Owned: []operatorsv1alpha1.CRDDescription{
   880  							{
   881  								Name:        crdName,
   882  								Version:     "v1alpha1",
   883  								Kind:        crdPlural,
   884  								DisplayName: crdName,
   885  								Description: crdName,
   886  							},
   887  						},
   888  					},
   889  				},
   890  			}
   891  
   892  			By("Create dependency first (CRD)")
   893  			cleanupCRD, err := createCRD(c, apiextensionsv1.CustomResourceDefinition{
   894  				ObjectMeta: metav1.ObjectMeta{
   895  					Name: crdName,
   896  				},
   897  				Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   898  					Group: "cluster.com",
   899  					Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   900  						{
   901  							Name:    "v1alpha1",
   902  							Served:  true,
   903  							Storage: true,
   904  							Schema: &apiextensionsv1.CustomResourceValidation{
   905  								OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
   906  									Type:        "object",
   907  									Description: "my crd schema",
   908  								},
   909  							},
   910  						},
   911  					},
   912  					Names: apiextensionsv1.CustomResourceDefinitionNames{
   913  						Plural:   crdPlural,
   914  						Singular: crdPlural,
   915  						Kind:     crdPlural,
   916  						ListKind: "list" + crdPlural,
   917  					},
   918  					Scope: apiextensionsv1.NamespaceScoped,
   919  				},
   920  			})
   921  			Expect(err).ShouldNot(HaveOccurred())
   922  			defer cleanupCRD()
   923  
   924  			cleanupCSV, err := createCSV(c, crc, csv, generatedNamespace.GetName(), true, false)
   925  			Expect(err).ShouldNot(HaveOccurred())
   926  			defer cleanupCSV()
   927  
   928  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvPendingChecker)
   929  			Expect(err).ShouldNot(HaveOccurred())
   930  
   931  			By("Shouldn't create deployment")
   932  			Consistently(func() bool {
   933  				_, err := c.GetDeployment(generatedNamespace.GetName(), depName)
   934  				return apierrors.IsNotFound(err)
   935  			}).Should(BeTrue())
   936  		})
   937  		It("create with unmet requirements API service", func() {
   938  
   939  			depName := genName("dep-")
   940  			csv := operatorsv1alpha1.ClusterServiceVersion{
   941  				TypeMeta: metav1.TypeMeta{
   942  					Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
   943  					APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
   944  				},
   945  				ObjectMeta: metav1.ObjectMeta{
   946  					Name: genName("csv"),
   947  				},
   948  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
   949  					MinKubeVersion: "0.0.0",
   950  					InstallModes: []operatorsv1alpha1.InstallMode{
   951  						{
   952  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
   953  							Supported: true,
   954  						},
   955  						{
   956  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
   957  							Supported: true,
   958  						},
   959  						{
   960  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
   961  							Supported: true,
   962  						},
   963  						{
   964  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
   965  							Supported: true,
   966  						},
   967  					},
   968  					InstallStrategy: newNginxInstallStrategy(depName, nil, nil),
   969  					APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{
   970  						Required: []operatorsv1alpha1.APIServiceDescription{
   971  							{
   972  								DisplayName: "Not In Cluster",
   973  								Description: "An apiservice that is not currently in the cluster",
   974  								Group:       "not.in.cluster.com",
   975  								Version:     "v1alpha1",
   976  								Kind:        "NotInCluster",
   977  							},
   978  						},
   979  					},
   980  				},
   981  			}
   982  
   983  			cleanupCSV, err := createCSV(c, crc, csv, generatedNamespace.GetName(), false, false)
   984  			Expect(err).ShouldNot(HaveOccurred())
   985  			defer cleanupCSV()
   986  
   987  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvPendingChecker)
   988  			Expect(err).ShouldNot(HaveOccurred())
   989  
   990  			By("Shouldn't create deployment")
   991  			Consistently(func() bool {
   992  				_, err := c.GetDeployment(generatedNamespace.GetName(), depName)
   993  				return apierrors.IsNotFound(err)
   994  			}).Should(BeTrue())
   995  		})
   996  		It("create with unmet permissions API service", func() {
   997  
   998  			saName := genName("dep-")
   999  			permissions := []operatorsv1alpha1.StrategyDeploymentPermissions{
  1000  				{
  1001  					ServiceAccountName: saName,
  1002  					Rules: []rbacv1.PolicyRule{
  1003  						{
  1004  							Verbs:     []string{"create"},
  1005  							APIGroups: []string{""},
  1006  							Resources: []string{"deployment"},
  1007  						},
  1008  					},
  1009  				},
  1010  			}
  1011  
  1012  			clusterPermissions := []operatorsv1alpha1.StrategyDeploymentPermissions{
  1013  				{
  1014  					ServiceAccountName: saName,
  1015  					Rules: []rbacv1.PolicyRule{
  1016  						{
  1017  							Verbs:     []string{"get"},
  1018  							APIGroups: []string{""},
  1019  							Resources: []string{"deployment"},
  1020  						},
  1021  					},
  1022  				},
  1023  			}
  1024  
  1025  			depName := genName("dep-")
  1026  			csv := operatorsv1alpha1.ClusterServiceVersion{
  1027  				TypeMeta: metav1.TypeMeta{
  1028  					Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
  1029  					APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
  1030  				},
  1031  				ObjectMeta: metav1.ObjectMeta{
  1032  					Name: genName("csv"),
  1033  				},
  1034  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  1035  					MinKubeVersion: "0.0.0",
  1036  					InstallModes: []operatorsv1alpha1.InstallMode{
  1037  						{
  1038  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  1039  							Supported: true,
  1040  						},
  1041  						{
  1042  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  1043  							Supported: true,
  1044  						},
  1045  						{
  1046  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  1047  							Supported: true,
  1048  						},
  1049  						{
  1050  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  1051  							Supported: true,
  1052  						},
  1053  					},
  1054  					InstallStrategy: newNginxInstallStrategy(depName, permissions, clusterPermissions),
  1055  					// "Cheating a little; this is an APIservice that will exist for the e2e tests"
  1056  					APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{
  1057  						Required: []operatorsv1alpha1.APIServiceDescription{
  1058  							{
  1059  								Group:       "packages.operators.coreos.com",
  1060  								Version:     "v1",
  1061  								Kind:        "PackageManifest",
  1062  								DisplayName: "Package Manifest",
  1063  								Description: "An apiservice that exists",
  1064  							},
  1065  						},
  1066  					},
  1067  				},
  1068  			}
  1069  
  1070  			cleanupCSV, err := createCSV(c, crc, csv, generatedNamespace.GetName(), false, false)
  1071  			Expect(err).ShouldNot(HaveOccurred())
  1072  			defer cleanupCSV()
  1073  
  1074  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvPendingChecker)
  1075  			Expect(err).ShouldNot(HaveOccurred())
  1076  
  1077  			By("Shouldn't create deployment")
  1078  			Consistently(func() bool {
  1079  				_, err := c.GetDeployment(generatedNamespace.GetName(), depName)
  1080  				return apierrors.IsNotFound(err)
  1081  			}).Should(BeTrue())
  1082  		})
  1083  		It("create with unmet requirements native API", func() {
  1084  
  1085  			depName := genName("dep-")
  1086  			csv := operatorsv1alpha1.ClusterServiceVersion{
  1087  				TypeMeta: metav1.TypeMeta{
  1088  					Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
  1089  					APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
  1090  				},
  1091  				ObjectMeta: metav1.ObjectMeta{
  1092  					Name: genName("csv"),
  1093  				},
  1094  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  1095  					MinKubeVersion: "0.0.0",
  1096  					InstallModes: []operatorsv1alpha1.InstallMode{
  1097  						{
  1098  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  1099  							Supported: true,
  1100  						},
  1101  						{
  1102  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  1103  							Supported: true,
  1104  						},
  1105  						{
  1106  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  1107  							Supported: true,
  1108  						},
  1109  						{
  1110  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  1111  							Supported: true,
  1112  						},
  1113  					},
  1114  					InstallStrategy: newNginxInstallStrategy(depName, nil, nil),
  1115  					NativeAPIs:      []metav1.GroupVersionKind{{Group: "kubenative.io", Version: "v1", Kind: "Native"}},
  1116  				},
  1117  			}
  1118  
  1119  			cleanupCSV, err := createCSV(c, crc, csv, generatedNamespace.GetName(), false, false)
  1120  			Expect(err).ShouldNot(HaveOccurred())
  1121  			defer cleanupCSV()
  1122  
  1123  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvPendingChecker)
  1124  			Expect(err).ShouldNot(HaveOccurred())
  1125  
  1126  			By("Shouldn't create deployment")
  1127  			Consistently(func() bool {
  1128  				_, err := c.GetDeployment(generatedNamespace.GetName(), depName)
  1129  				return apierrors.IsNotFound(err)
  1130  			}).Should(BeTrue())
  1131  		})
  1132  		// TODO: same test but create serviceaccount instead
  1133  		It("create requirements met CRD", func() {
  1134  
  1135  			saName := genName("sa-")
  1136  			permissions := []operatorsv1alpha1.StrategyDeploymentPermissions{
  1137  				{
  1138  					ServiceAccountName: saName,
  1139  					Rules: []rbacv1.PolicyRule{
  1140  						{
  1141  							Verbs:     []string{"create"},
  1142  							APIGroups: []string{""},
  1143  							Resources: []string{"deployment"},
  1144  						},
  1145  					},
  1146  				},
  1147  			}
  1148  
  1149  			clusterPermissions := []operatorsv1alpha1.StrategyDeploymentPermissions{
  1150  				{
  1151  					ServiceAccountName: saName,
  1152  					Rules: []rbacv1.PolicyRule{
  1153  						{
  1154  							Verbs:     []string{"get"},
  1155  							APIGroups: []string{""},
  1156  							Resources: []string{"deployment"},
  1157  						},
  1158  						{
  1159  							Verbs:           []string{"put", "post", "get"},
  1160  							NonResourceURLs: []string{"/osb", "/osb/*"},
  1161  						},
  1162  					},
  1163  				},
  1164  			}
  1165  
  1166  			crdPlural := genName("ins")
  1167  			crdName := crdPlural + ".cluster.com"
  1168  			depName := genName("dep-")
  1169  			csv := operatorsv1alpha1.ClusterServiceVersion{
  1170  				TypeMeta: metav1.TypeMeta{
  1171  					Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
  1172  					APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
  1173  				},
  1174  				ObjectMeta: metav1.ObjectMeta{
  1175  					Name: genName("csv"),
  1176  				},
  1177  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  1178  					MinKubeVersion: "0.0.0",
  1179  					InstallModes: []operatorsv1alpha1.InstallMode{
  1180  						{
  1181  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  1182  							Supported: true,
  1183  						},
  1184  						{
  1185  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  1186  							Supported: true,
  1187  						},
  1188  						{
  1189  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  1190  							Supported: true,
  1191  						},
  1192  						{
  1193  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  1194  							Supported: true,
  1195  						},
  1196  					},
  1197  					InstallStrategy: newNginxInstallStrategy(depName, permissions, clusterPermissions),
  1198  					CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{
  1199  						Owned: []operatorsv1alpha1.CRDDescription{
  1200  							{
  1201  								Name:        crdName,
  1202  								Version:     "v1alpha1",
  1203  								Kind:        crdPlural,
  1204  								DisplayName: crdName,
  1205  								Description: crdName,
  1206  							},
  1207  						},
  1208  					},
  1209  				},
  1210  			}
  1211  
  1212  			By("Create CSV first, knowing it will fail")
  1213  			cleanupCSV, err := createCSV(c, crc, csv, generatedNamespace.GetName(), true, false)
  1214  			Expect(err).ShouldNot(HaveOccurred())
  1215  			defer cleanupCSV()
  1216  
  1217  			fetchedCSV, err := fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvPendingChecker)
  1218  			Expect(err).ShouldNot(HaveOccurred())
  1219  
  1220  			sa := corev1.ServiceAccount{}
  1221  			sa.SetName(saName)
  1222  			sa.SetNamespace(generatedNamespace.GetName())
  1223  			sa.SetOwnerReferences([]metav1.OwnerReference{{
  1224  				Name:       fetchedCSV.GetName(),
  1225  				APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
  1226  				Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
  1227  				UID:        fetchedCSV.GetUID(),
  1228  			}})
  1229  			_, err = c.CreateServiceAccount(&sa)
  1230  			Expect(err).ShouldNot(HaveOccurred(), "could not create ServiceAccount %#v", sa)
  1231  
  1232  			crd := apiextensionsv1.CustomResourceDefinition{
  1233  				ObjectMeta: metav1.ObjectMeta{
  1234  					Name: crdName,
  1235  				},
  1236  				Spec: apiextensionsv1.CustomResourceDefinitionSpec{
  1237  					Group: "cluster.com",
  1238  					Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
  1239  						{
  1240  							Name:    "v1alpha1",
  1241  							Served:  true,
  1242  							Storage: true,
  1243  							Schema: &apiextensionsv1.CustomResourceValidation{
  1244  								OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
  1245  									Type:        "object",
  1246  									Description: "my crd schema",
  1247  								},
  1248  							},
  1249  						},
  1250  					},
  1251  					Names: apiextensionsv1.CustomResourceDefinitionNames{
  1252  						Plural:   crdPlural,
  1253  						Singular: crdPlural,
  1254  						Kind:     crdPlural,
  1255  						ListKind: "list" + crdPlural,
  1256  					},
  1257  					Scope: apiextensionsv1.NamespaceScoped,
  1258  				},
  1259  			}
  1260  			crd.SetOwnerReferences([]metav1.OwnerReference{{
  1261  				Name:       fetchedCSV.GetName(),
  1262  				APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
  1263  				Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
  1264  				UID:        fetchedCSV.GetUID(),
  1265  			}})
  1266  			cleanupCRD, err := createCRD(c, crd)
  1267  			defer cleanupCRD()
  1268  			Expect(err).ShouldNot(HaveOccurred())
  1269  
  1270  			By("Create Role/Cluster Roles and RoleBindings")
  1271  			role := rbacv1.Role{
  1272  				Rules: []rbacv1.PolicyRule{
  1273  					{
  1274  						Verbs:     []string{"create"},
  1275  						APIGroups: []string{""},
  1276  						Resources: []string{"deployment"},
  1277  					},
  1278  				},
  1279  			}
  1280  			role.SetName(genName("dep-"))
  1281  			role.SetNamespace(generatedNamespace.GetName())
  1282  			_, err = c.CreateRole(&role)
  1283  			Expect(err).ShouldNot(HaveOccurred(), "could not create Role")
  1284  
  1285  			roleBinding := rbacv1.RoleBinding{
  1286  				Subjects: []rbacv1.Subject{
  1287  					{
  1288  						Kind:      "ServiceAccount",
  1289  						APIGroup:  "",
  1290  						Name:      sa.GetName(),
  1291  						Namespace: sa.GetNamespace(),
  1292  					},
  1293  				},
  1294  				RoleRef: rbacv1.RoleRef{
  1295  					APIGroup: "rbac.authorization.k8s.io",
  1296  					Kind:     "Role",
  1297  					Name:     role.GetName(),
  1298  				},
  1299  			}
  1300  			roleBinding.SetName(genName("dep-"))
  1301  			roleBinding.SetNamespace(generatedNamespace.GetName())
  1302  			_, err = c.CreateRoleBinding(&roleBinding)
  1303  			Expect(err).ShouldNot(HaveOccurred(), "could not create RoleBinding")
  1304  
  1305  			clusterRole := rbacv1.ClusterRole{
  1306  				Rules: []rbacv1.PolicyRule{
  1307  					{
  1308  						Verbs:     []string{"get"},
  1309  						APIGroups: []string{""},
  1310  						Resources: []string{"deployment"},
  1311  					},
  1312  				},
  1313  			}
  1314  			clusterRole.SetName(genName("dep-"))
  1315  			_, err = c.CreateClusterRole(&clusterRole)
  1316  			Expect(err).ShouldNot(HaveOccurred(), "could not create ClusterRole")
  1317  
  1318  			nonResourceClusterRole := rbacv1.ClusterRole{
  1319  				Rules: []rbacv1.PolicyRule{
  1320  					{
  1321  						Verbs:           []string{"put", "post", "get"},
  1322  						NonResourceURLs: []string{"/osb", "/osb/*"},
  1323  					},
  1324  				},
  1325  			}
  1326  			nonResourceClusterRole.SetName(genName("dep-"))
  1327  			_, err = c.CreateClusterRole(&nonResourceClusterRole)
  1328  			Expect(err).ShouldNot(HaveOccurred(), "could not create ClusterRole")
  1329  
  1330  			clusterRoleBinding := rbacv1.ClusterRoleBinding{
  1331  				Subjects: []rbacv1.Subject{
  1332  					{
  1333  						Kind:      "ServiceAccount",
  1334  						APIGroup:  "",
  1335  						Name:      sa.GetName(),
  1336  						Namespace: sa.GetNamespace(),
  1337  					},
  1338  				},
  1339  				RoleRef: rbacv1.RoleRef{
  1340  					APIGroup: "rbac.authorization.k8s.io",
  1341  					Kind:     "ClusterRole",
  1342  					Name:     clusterRole.GetName(),
  1343  				},
  1344  			}
  1345  			clusterRoleBinding.SetName(genName("dep-"))
  1346  			_, err = c.CreateClusterRoleBinding(&clusterRoleBinding)
  1347  			Expect(err).ShouldNot(HaveOccurred(), "could not create ClusterRoleBinding")
  1348  
  1349  			nonResourceClusterRoleBinding := rbacv1.ClusterRoleBinding{
  1350  				Subjects: []rbacv1.Subject{
  1351  					{
  1352  						Kind:      "ServiceAccount",
  1353  						APIGroup:  "",
  1354  						Name:      sa.GetName(),
  1355  						Namespace: sa.GetNamespace(),
  1356  					},
  1357  				},
  1358  				RoleRef: rbacv1.RoleRef{
  1359  					APIGroup: "rbac.authorization.k8s.io",
  1360  					Kind:     "ClusterRole",
  1361  					Name:     nonResourceClusterRole.GetName(),
  1362  				},
  1363  			}
  1364  			nonResourceClusterRoleBinding.SetName(genName("dep-"))
  1365  			_, err = c.CreateClusterRoleBinding(&nonResourceClusterRoleBinding)
  1366  			Expect(err).ShouldNot(HaveOccurred(), "could not create ClusterRoleBinding")
  1367  
  1368  			ctx.Ctx().Logf("checking for deployment")
  1369  			By("Poll for deployment to be ready")
  1370  			Eventually(func() (bool, error) {
  1371  				dep, err := c.GetDeployment(generatedNamespace.GetName(), depName)
  1372  				if apierrors.IsNotFound(err) {
  1373  					ctx.Ctx().Logf("deployment %s not found\n", depName)
  1374  					return false, nil
  1375  				} else if err != nil {
  1376  					ctx.Ctx().Logf("unexpected error fetching deployment %s\n", depName)
  1377  					return false, err
  1378  				}
  1379  				if dep.Status.UpdatedReplicas == *(dep.Spec.Replicas) &&
  1380  					dep.Status.Replicas == *(dep.Spec.Replicas) &&
  1381  					dep.Status.AvailableReplicas == *(dep.Spec.Replicas) {
  1382  					ctx.Ctx().Logf("deployment ready")
  1383  					return true, nil
  1384  				}
  1385  				ctx.Ctx().Logf("deployment not ready")
  1386  				return false, nil
  1387  			}).Should(BeTrue())
  1388  
  1389  			fetchedCSV, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvSucceededChecker)
  1390  			Expect(err).ShouldNot(HaveOccurred())
  1391  
  1392  			By("Delete CRD")
  1393  			cleanupCRD()
  1394  
  1395  			By("Wait for CSV failure")
  1396  			fetchedCSV, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvPendingChecker)
  1397  			Expect(err).ShouldNot(HaveOccurred())
  1398  
  1399  			By("Recreate the CRD")
  1400  			cleanupCRD, err = createCRD(c, crd)
  1401  			Expect(err).ShouldNot(HaveOccurred())
  1402  			defer cleanupCRD()
  1403  
  1404  			By("Wait for CSV success again")
  1405  			fetchedCSV, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvSucceededChecker)
  1406  			Expect(err).ShouldNot(HaveOccurred())
  1407  		})
  1408  		It("create requirements met API service", func() {
  1409  
  1410  			sa := corev1.ServiceAccount{}
  1411  			sa.SetName(genName("sa-"))
  1412  			sa.SetNamespace(generatedNamespace.GetName())
  1413  			_, err := c.CreateServiceAccount(&sa)
  1414  			Expect(err).ShouldNot(HaveOccurred(), "could not create ServiceAccount")
  1415  
  1416  			permissions := []operatorsv1alpha1.StrategyDeploymentPermissions{
  1417  				{
  1418  					ServiceAccountName: sa.GetName(),
  1419  					Rules: []rbacv1.PolicyRule{
  1420  						{
  1421  							Verbs:     []string{"create"},
  1422  							APIGroups: []string{""},
  1423  							Resources: []string{"deployment"},
  1424  						},
  1425  					},
  1426  				},
  1427  			}
  1428  
  1429  			clusterPermissions := []operatorsv1alpha1.StrategyDeploymentPermissions{
  1430  				{
  1431  					ServiceAccountName: sa.GetName(),
  1432  					Rules: []rbacv1.PolicyRule{
  1433  						{
  1434  							Verbs:     []string{"get"},
  1435  							APIGroups: []string{""},
  1436  							Resources: []string{"deployment"},
  1437  						},
  1438  					},
  1439  				},
  1440  			}
  1441  
  1442  			depName := genName("dep-")
  1443  			csv := operatorsv1alpha1.ClusterServiceVersion{
  1444  				TypeMeta: metav1.TypeMeta{
  1445  					Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
  1446  					APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
  1447  				},
  1448  				ObjectMeta: metav1.ObjectMeta{
  1449  					Name: genName("csv"),
  1450  				},
  1451  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  1452  					MinKubeVersion: "0.0.0",
  1453  					InstallModes: []operatorsv1alpha1.InstallMode{
  1454  						{
  1455  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  1456  							Supported: true,
  1457  						},
  1458  						{
  1459  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  1460  							Supported: true,
  1461  						},
  1462  						{
  1463  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  1464  							Supported: true,
  1465  						},
  1466  						{
  1467  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  1468  							Supported: true,
  1469  						},
  1470  					},
  1471  					InstallStrategy: newNginxInstallStrategy(depName, permissions, clusterPermissions),
  1472  					// "Cheating a little; this is an APIservice that will exist for the e2e tests"
  1473  					APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{
  1474  						Required: []operatorsv1alpha1.APIServiceDescription{
  1475  							{
  1476  								Group:       "packages.operators.coreos.com",
  1477  								Version:     "v1",
  1478  								Kind:        "PackageManifest",
  1479  								DisplayName: "Package Manifest",
  1480  								Description: "An apiservice that exists",
  1481  							},
  1482  						},
  1483  					},
  1484  				},
  1485  			}
  1486  
  1487  			By("Create Role/Cluster Roles and RoleBindings")
  1488  			role := rbacv1.Role{
  1489  				Rules: []rbacv1.PolicyRule{
  1490  					{
  1491  						Verbs:     []string{"create"},
  1492  						APIGroups: []string{""},
  1493  						Resources: []string{"deployment"},
  1494  					},
  1495  				},
  1496  			}
  1497  			role.SetName(genName("dep-"))
  1498  			role.SetNamespace(generatedNamespace.GetName())
  1499  			_, err = c.CreateRole(&role)
  1500  			Expect(err).ShouldNot(HaveOccurred(), "could not create Role")
  1501  
  1502  			roleBinding := rbacv1.RoleBinding{
  1503  				Subjects: []rbacv1.Subject{
  1504  					{
  1505  						Kind:      "ServiceAccount",
  1506  						APIGroup:  "",
  1507  						Name:      sa.GetName(),
  1508  						Namespace: sa.GetNamespace(),
  1509  					},
  1510  				},
  1511  				RoleRef: rbacv1.RoleRef{
  1512  					APIGroup: "rbac.authorization.k8s.io",
  1513  					Kind:     "Role",
  1514  					Name:     role.GetName(),
  1515  				},
  1516  			}
  1517  			roleBinding.SetName(genName("dep-"))
  1518  			roleBinding.SetNamespace(generatedNamespace.GetName())
  1519  			_, err = c.CreateRoleBinding(&roleBinding)
  1520  			Expect(err).ShouldNot(HaveOccurred(), "could not create RoleBinding")
  1521  
  1522  			clusterRole := rbacv1.ClusterRole{
  1523  				Rules: []rbacv1.PolicyRule{
  1524  					{
  1525  						Verbs:     []string{"get"},
  1526  						APIGroups: []string{""},
  1527  						Resources: []string{"deployment"},
  1528  					},
  1529  				},
  1530  			}
  1531  			clusterRole.SetName(genName("dep-"))
  1532  			_, err = c.CreateClusterRole(&clusterRole)
  1533  			Expect(err).ShouldNot(HaveOccurred(), "could not create ClusterRole")
  1534  
  1535  			clusterRoleBinding := rbacv1.ClusterRoleBinding{
  1536  				Subjects: []rbacv1.Subject{
  1537  					{
  1538  						Kind:      "ServiceAccount",
  1539  						APIGroup:  "",
  1540  						Name:      sa.GetName(),
  1541  						Namespace: sa.GetNamespace(),
  1542  					},
  1543  				},
  1544  				RoleRef: rbacv1.RoleRef{
  1545  					APIGroup: "rbac.authorization.k8s.io",
  1546  					Kind:     "ClusterRole",
  1547  					Name:     clusterRole.GetName(),
  1548  				},
  1549  			}
  1550  			clusterRoleBinding.SetName(genName("dep-"))
  1551  			_, err = c.CreateClusterRoleBinding(&clusterRoleBinding)
  1552  			Expect(err).ShouldNot(HaveOccurred(), "could not create ClusterRoleBinding")
  1553  
  1554  			cleanupCSV, err := createCSV(c, crc, csv, generatedNamespace.GetName(), false, false)
  1555  			Expect(err).ShouldNot(HaveOccurred())
  1556  			defer cleanupCSV()
  1557  
  1558  			fetchedCSV, err := fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvSucceededChecker)
  1559  			Expect(err).ShouldNot(HaveOccurred())
  1560  
  1561  			By("Fetch cluster service version again to check for unnecessary control loops")
  1562  			sameCSV, err := fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvSucceededChecker)
  1563  			Expect(err).ShouldNot(HaveOccurred())
  1564  			Expect(equality.Semantic.DeepEqual(fetchedCSV, sameCSV)).Should(BeTrue(), diff.ObjectDiff(fetchedCSV, sameCSV))
  1565  		})
  1566  		It("create with owned API service", func() {
  1567  
  1568  			depName := genName("hat-server")
  1569  			mockGroup := fmt.Sprintf("hats.%s.redhat.com", genName(""))
  1570  			version := "v1alpha1"
  1571  			mockGroupVersion := strings.Join([]string{mockGroup, version}, "/")
  1572  			mockKinds := []string{"fez", "fedora"}
  1573  			depSpec := newMockExtServerDeployment(depName, []mockGroupVersionKind{{depName, mockGroupVersion, mockKinds, 5443}})
  1574  			apiServiceName := strings.Join([]string{version, mockGroup}, ".")
  1575  
  1576  			By("Create CSV for the package-server")
  1577  			strategy := operatorsv1alpha1.StrategyDetailsDeployment{
  1578  				DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
  1579  					{
  1580  						Name: depName,
  1581  						Spec: depSpec,
  1582  					},
  1583  				},
  1584  			}
  1585  
  1586  			owned := make([]operatorsv1alpha1.APIServiceDescription, len(mockKinds))
  1587  			for i, kind := range mockKinds {
  1588  				owned[i] = operatorsv1alpha1.APIServiceDescription{
  1589  					Name:           apiServiceName,
  1590  					Group:          mockGroup,
  1591  					Version:        version,
  1592  					Kind:           kind,
  1593  					DeploymentName: depName,
  1594  					ContainerPort:  int32(5443),
  1595  					DisplayName:    kind,
  1596  					Description:    fmt.Sprintf("A %s", kind),
  1597  				}
  1598  			}
  1599  
  1600  			csv := operatorsv1alpha1.ClusterServiceVersion{
  1601  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  1602  					MinKubeVersion: "0.0.0",
  1603  					InstallModes: []operatorsv1alpha1.InstallMode{
  1604  						{
  1605  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  1606  							Supported: true,
  1607  						},
  1608  						{
  1609  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  1610  							Supported: true,
  1611  						},
  1612  						{
  1613  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  1614  							Supported: true,
  1615  						},
  1616  						{
  1617  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  1618  							Supported: true,
  1619  						},
  1620  					},
  1621  					InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
  1622  						StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
  1623  						StrategySpec: strategy,
  1624  					},
  1625  					APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{
  1626  						Owned: owned,
  1627  					},
  1628  				},
  1629  			}
  1630  			csv.SetName(depName)
  1631  
  1632  			By("Create the APIService CSV")
  1633  			cleanupCSV, err := createCSV(c, crc, csv, generatedNamespace.GetName(), false, false)
  1634  			Expect(err).ShouldNot(HaveOccurred())
  1635  			defer func() {
  1636  				watcher, err := c.ApiregistrationV1Interface().ApiregistrationV1().APIServices().Watch(context.TODO(), metav1.ListOptions{FieldSelector: "metadata.name=" + apiServiceName})
  1637  				Expect(err).ShouldNot(HaveOccurred())
  1638  
  1639  				deleted := make(chan struct{})
  1640  				go func() {
  1641  					defer GinkgoRecover()
  1642  					events := watcher.ResultChan()
  1643  					for {
  1644  						select {
  1645  						case evt := <-events:
  1646  							if evt.Type == watch.Deleted {
  1647  								deleted <- struct{}{}
  1648  								return
  1649  							}
  1650  						case <-time.After(pollDuration):
  1651  							Fail("API service not cleaned up after CSV deleted")
  1652  						}
  1653  					}
  1654  				}()
  1655  
  1656  				cleanupCSV()
  1657  				<-deleted
  1658  			}()
  1659  
  1660  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvSucceededChecker)
  1661  			Expect(err).ShouldNot(HaveOccurred())
  1662  
  1663  			By("Should create Deployment")
  1664  			dep, err := c.GetDeployment(generatedNamespace.GetName(), depName)
  1665  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected Deployment")
  1666  
  1667  			By("Should create APIService")
  1668  			apiService, err := c.GetAPIService(apiServiceName)
  1669  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected APIService")
  1670  
  1671  			By("Should create Service")
  1672  			serviceName := fmt.Sprintf("%s-service", depName)
  1673  			_, err = c.GetService(generatedNamespace.GetName(), serviceName)
  1674  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected Service")
  1675  
  1676  			By("Should create certificate Secret")
  1677  			secretName := fmt.Sprintf("%s-cert", serviceName)
  1678  			_, err = c.GetSecret(generatedNamespace.GetName(), secretName)
  1679  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected Secret")
  1680  
  1681  			By("Should create a Role for the Secret")
  1682  			_, err = c.GetRole(generatedNamespace.GetName(), secretName)
  1683  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected Secret Role")
  1684  
  1685  			By("Should create a RoleBinding for the Secret")
  1686  			_, err = c.GetRoleBinding(generatedNamespace.GetName(), secretName)
  1687  			Expect(err).ShouldNot(HaveOccurred(), "error getting exptected Secret RoleBinding")
  1688  
  1689  			By("Should create a system:auth-delegator Cluster RoleBinding")
  1690  			_, err = c.GetClusterRoleBinding(fmt.Sprintf("%s-system:auth-delegator", serviceName))
  1691  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected system:auth-delegator ClusterRoleBinding")
  1692  
  1693  			By("Should create an extension-apiserver-authentication-reader RoleBinding in kube-system")
  1694  			_, err = c.GetRoleBinding("kube-system", fmt.Sprintf("%s-auth-reader", serviceName))
  1695  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected extension-apiserver-authentication-reader RoleBinding")
  1696  
  1697  			By("Store the ca sha annotation")
  1698  			oldCAAnnotation, ok := dep.Spec.Template.GetAnnotations()[install.OLMCAHashAnnotationKey]
  1699  			Expect(ok).Should(BeTrue(), "expected olm sha annotation not present on existing pod template")
  1700  
  1701  			caSecret, err := c.KubernetesInterface().CoreV1().Secrets(generatedNamespace.GetName()).Get(context.TODO(), secretName, metav1.GetOptions{})
  1702  			Expect(err).Should(BeNil())
  1703  
  1704  			caPEM, certPEM, privPEM := generateExpiredCerts(install.HostnamesForService(serviceName, generatedNamespace.GetName()))
  1705  			By(`Induce a cert rotation`)
  1706  			Eventually(Apply(caSecret, func(caSecret *corev1.Secret) error {
  1707  				caSecret.Data[install.OLMCAPEMKey] = caPEM
  1708  				caSecret.Data["tls.crt"] = certPEM
  1709  				caSecret.Data["tls.key"] = privPEM
  1710  				return nil
  1711  			})).Should(Succeed())
  1712  
  1713  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, func(csv *operatorsv1alpha1.ClusterServiceVersion) bool {
  1714  				By("Should create deployment")
  1715  				dep, err = c.GetDeployment(generatedNamespace.GetName(), depName)
  1716  				if err != nil {
  1717  					return false
  1718  				}
  1719  
  1720  				By("Should have a new ca hash annotation")
  1721  				newCAAnnotation, ok := dep.Spec.Template.GetAnnotations()[install.OLMCAHashAnnotationKey]
  1722  				if !ok {
  1723  					ctx.Ctx().Logf("expected olm sha annotation not present in new pod template")
  1724  					return false
  1725  				}
  1726  
  1727  				if newCAAnnotation != oldCAAnnotation {
  1728  					By("Check for success")
  1729  					return csvSucceededChecker(csv)
  1730  				}
  1731  
  1732  				return false
  1733  			})
  1734  			Expect(err).ShouldNot(HaveOccurred(), "failed to rotate cert")
  1735  
  1736  			By("Get the APIService UID")
  1737  			oldAPIServiceUID := apiService.GetUID()
  1738  
  1739  			By("Delete the APIService")
  1740  			err = c.DeleteAPIService(apiServiceName, &metav1.DeleteOptions{})
  1741  			Expect(err).ShouldNot(HaveOccurred())
  1742  
  1743  			By("Wait for CSV success")
  1744  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.GetName(), func(csv *operatorsv1alpha1.ClusterServiceVersion) bool {
  1745  				By("Should create an APIService")
  1746  				apiService, err := c.GetAPIService(apiServiceName)
  1747  				if err != nil {
  1748  					return false
  1749  				}
  1750  
  1751  				if csvSucceededChecker(csv) {
  1752  					return apiService.GetUID() != oldAPIServiceUID
  1753  				}
  1754  				return false
  1755  			})
  1756  			Expect(err).ShouldNot(HaveOccurred())
  1757  		})
  1758  		It("update with owned API service", func() {
  1759  
  1760  			depName := genName("hat-server")
  1761  			mockGroup := fmt.Sprintf("hats.%s.redhat.com", genName(""))
  1762  			version := "v1alpha1"
  1763  			mockGroupVersion := strings.Join([]string{mockGroup, version}, "/")
  1764  			mockKinds := []string{"fedora"}
  1765  			depSpec := newMockExtServerDeployment(depName, []mockGroupVersionKind{{depName, mockGroupVersion, mockKinds, 5443}})
  1766  			apiServiceName := strings.Join([]string{version, mockGroup}, ".")
  1767  
  1768  			By("Create CSVs for the hat-server")
  1769  			strategy := operatorsv1alpha1.StrategyDetailsDeployment{
  1770  				DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
  1771  					{
  1772  						Name: depName,
  1773  						Spec: depSpec,
  1774  					},
  1775  				},
  1776  			}
  1777  
  1778  			owned := make([]operatorsv1alpha1.APIServiceDescription, len(mockKinds))
  1779  			for i, kind := range mockKinds {
  1780  				owned[i] = operatorsv1alpha1.APIServiceDescription{
  1781  					Name:           apiServiceName,
  1782  					Group:          mockGroup,
  1783  					Version:        version,
  1784  					Kind:           kind,
  1785  					DeploymentName: depName,
  1786  					ContainerPort:  int32(5443),
  1787  					DisplayName:    kind,
  1788  					Description:    fmt.Sprintf("A %s", kind),
  1789  				}
  1790  			}
  1791  
  1792  			csv := operatorsv1alpha1.ClusterServiceVersion{
  1793  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  1794  					MinKubeVersion: "0.0.0",
  1795  					InstallModes: []operatorsv1alpha1.InstallMode{
  1796  						{
  1797  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  1798  							Supported: true,
  1799  						},
  1800  						{
  1801  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  1802  							Supported: true,
  1803  						},
  1804  						{
  1805  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  1806  							Supported: true,
  1807  						},
  1808  						{
  1809  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  1810  							Supported: true,
  1811  						},
  1812  					},
  1813  					InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
  1814  						StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
  1815  						StrategySpec: strategy,
  1816  					},
  1817  					APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{
  1818  						Owned: owned,
  1819  					},
  1820  				},
  1821  			}
  1822  			csv.SetName("csv-hat-1")
  1823  
  1824  			By("Create the APIService CSV")
  1825  			_, err := createCSV(c, crc, csv, generatedNamespace.GetName(), false, false)
  1826  			Expect(err).ShouldNot(HaveOccurred())
  1827  
  1828  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvSucceededChecker)
  1829  			Expect(err).ShouldNot(HaveOccurred())
  1830  
  1831  			By("Should create Deployment")
  1832  			_, err = c.GetDeployment(generatedNamespace.GetName(), depName)
  1833  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected Deployment")
  1834  
  1835  			By("Should create APIService")
  1836  			_, err = c.GetAPIService(apiServiceName)
  1837  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected APIService")
  1838  
  1839  			By("Should create Service")
  1840  			serviceName := fmt.Sprintf("%s-service", depName)
  1841  			_, err = c.GetService(generatedNamespace.GetName(), serviceName)
  1842  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected Service")
  1843  
  1844  			By("Should create certificate Secret")
  1845  			secretName := fmt.Sprintf("%s-cert", serviceName)
  1846  			_, err = c.GetSecret(generatedNamespace.GetName(), secretName)
  1847  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected Secret")
  1848  
  1849  			By("Should create a Role for the Secret")
  1850  			_, err = c.GetRole(generatedNamespace.GetName(), secretName)
  1851  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected Secret Role")
  1852  
  1853  			By("Should create a RoleBinding for the Secret")
  1854  			_, err = c.GetRoleBinding(generatedNamespace.GetName(), secretName)
  1855  			Expect(err).ShouldNot(HaveOccurred(), "error getting exptected Secret RoleBinding")
  1856  
  1857  			By("Should create a system:auth-delegator Cluster RoleBinding")
  1858  			_, err = c.GetClusterRoleBinding(fmt.Sprintf("%s-system:auth-delegator", serviceName))
  1859  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected system:auth-delegator ClusterRoleBinding")
  1860  
  1861  			By("Should create an extension-apiserver-authentication-reader RoleBinding in kube-system")
  1862  			_, err = c.GetRoleBinding("kube-system", fmt.Sprintf("%s-auth-reader", serviceName))
  1863  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected extension-apiserver-authentication-reader RoleBinding")
  1864  
  1865  			By("Create a new CSV that owns the same API Service and replace the old CSV")
  1866  			csv2 := operatorsv1alpha1.ClusterServiceVersion{
  1867  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  1868  					Replaces:       csv.Name,
  1869  					MinKubeVersion: "0.0.0",
  1870  					InstallModes: []operatorsv1alpha1.InstallMode{
  1871  						{
  1872  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  1873  							Supported: true,
  1874  						},
  1875  						{
  1876  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  1877  							Supported: true,
  1878  						},
  1879  						{
  1880  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  1881  							Supported: true,
  1882  						},
  1883  						{
  1884  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  1885  							Supported: true,
  1886  						},
  1887  					},
  1888  					InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
  1889  						StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
  1890  						StrategySpec: strategy,
  1891  					},
  1892  					APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{
  1893  						Owned: owned,
  1894  					},
  1895  				},
  1896  			}
  1897  			csv2.SetName("csv-hat-2")
  1898  
  1899  			By("Create CSV2 to replace CSV")
  1900  			cleanupCSV2, err := createCSV(c, crc, csv2, generatedNamespace.GetName(), false, true)
  1901  			Expect(err).ShouldNot(HaveOccurred())
  1902  			defer cleanupCSV2()
  1903  
  1904  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv2.Name, csvSucceededChecker)
  1905  			Expect(err).ShouldNot(HaveOccurred())
  1906  
  1907  			By("Should create Deployment")
  1908  			_, err = c.GetDeployment(generatedNamespace.GetName(), depName)
  1909  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected Deployment")
  1910  
  1911  			By("Should create APIService")
  1912  			_, err = c.GetAPIService(apiServiceName)
  1913  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected APIService")
  1914  
  1915  			By("Should create Service")
  1916  			Eventually(func() error {
  1917  				_, err := c.GetService(generatedNamespace.GetName(), serviceName)
  1918  				return err
  1919  			}, timeout, interval).ShouldNot(HaveOccurred())
  1920  
  1921  			By("Should create certificate Secret")
  1922  			secretName = fmt.Sprintf("%s-cert", serviceName)
  1923  			Eventually(func() error {
  1924  				_, err = c.GetSecret(generatedNamespace.GetName(), secretName)
  1925  				return err
  1926  			}, timeout, interval).ShouldNot(HaveOccurred())
  1927  
  1928  			By("Should create a Role for the Secret")
  1929  			_, err = c.GetRole(generatedNamespace.GetName(), secretName)
  1930  			Eventually(func() error {
  1931  				_, err = c.GetRole(generatedNamespace.GetName(), secretName)
  1932  				return err
  1933  			}, timeout, interval).ShouldNot(HaveOccurred())
  1934  
  1935  			By("Should create a RoleBinding for the Secret")
  1936  			Eventually(func() error {
  1937  				_, err = c.GetRoleBinding(generatedNamespace.GetName(), secretName)
  1938  				return err
  1939  			}, timeout, interval).ShouldNot(HaveOccurred())
  1940  
  1941  			By("Should create a system:auth-delegator Cluster RoleBinding")
  1942  			Eventually(func() error {
  1943  				_, err = c.GetClusterRoleBinding(fmt.Sprintf("%s-system:auth-delegator", serviceName))
  1944  				return err
  1945  			}, timeout, interval).ShouldNot(HaveOccurred())
  1946  
  1947  			By("Should create an extension-apiserver-authentication-reader RoleBinding in kube-system")
  1948  			Eventually(func() error {
  1949  				_, err = c.GetRoleBinding("kube-system", fmt.Sprintf("%s-auth-reader", serviceName))
  1950  				return err
  1951  			}, timeout, interval).ShouldNot(HaveOccurred())
  1952  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected extension-apiserver-authentication-reader RoleBinding")
  1953  
  1954  			By("Should eventually GC the CSV")
  1955  			err = waitForCsvToDelete(generatedNamespace.GetName(), csv.Name, crc)
  1956  			Expect(err).ShouldNot(HaveOccurred())
  1957  
  1958  			By("Rename the initial CSV")
  1959  			csv.SetName("csv-hat-3")
  1960  
  1961  			By("Recreate the old CSV")
  1962  			cleanupCSV, err := createCSV(c, crc, csv, generatedNamespace.GetName(), false, true)
  1963  			Expect(err).ShouldNot(HaveOccurred())
  1964  			defer cleanupCSV()
  1965  
  1966  			fetched, err := fetchCSV(crc, generatedNamespace.GetName(), csv.Name, buildCSVReasonChecker(operatorsv1alpha1.CSVReasonOwnerConflict))
  1967  			Expect(err).ShouldNot(HaveOccurred())
  1968  			Expect(fetched.Status.Phase).Should(Equal(operatorsv1alpha1.CSVPhaseFailed))
  1969  		})
  1970  		It("create same CSV with owned API service multi namespace", func() {
  1971  
  1972  			By("Create new namespace in a new operator group")
  1973  			secondNamespaceName := genName(generatedNamespace.GetName() + "-")
  1974  			matchingLabel := map[string]string{"inGroup": secondNamespaceName}
  1975  
  1976  			_, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
  1977  				ObjectMeta: metav1.ObjectMeta{
  1978  					Name:   secondNamespaceName,
  1979  					Labels: matchingLabel,
  1980  				},
  1981  			}, metav1.CreateOptions{})
  1982  			Expect(err).ShouldNot(HaveOccurred())
  1983  			defer func() {
  1984  				err = c.KubernetesInterface().CoreV1().Namespaces().Delete(context.TODO(), secondNamespaceName, metav1.DeleteOptions{})
  1985  				Expect(err).ShouldNot(HaveOccurred())
  1986  			}()
  1987  
  1988  			By("Create a new operator group for the new namespace")
  1989  			operatorGroup := operatorsv1.OperatorGroup{
  1990  				ObjectMeta: metav1.ObjectMeta{
  1991  					Name:      genName("e2e-operator-group-"),
  1992  					Namespace: secondNamespaceName,
  1993  				},
  1994  				Spec: operatorsv1.OperatorGroupSpec{
  1995  					Selector: &metav1.LabelSelector{
  1996  						MatchLabels: matchingLabel,
  1997  					},
  1998  				},
  1999  			}
  2000  			_, err = crc.OperatorsV1().OperatorGroups(secondNamespaceName).Create(context.TODO(), &operatorGroup, metav1.CreateOptions{})
  2001  			Expect(err).ShouldNot(HaveOccurred())
  2002  			defer func() {
  2003  				err = crc.OperatorsV1().OperatorGroups(secondNamespaceName).Delete(context.TODO(), operatorGroup.Name, metav1.DeleteOptions{})
  2004  				Expect(err).ShouldNot(HaveOccurred())
  2005  			}()
  2006  
  2007  			ctx.Ctx().Logf("Waiting on new operator group to have correct status")
  2008  			Eventually(func() ([]string, error) {
  2009  				og, err := crc.OperatorsV1().OperatorGroups(secondNamespaceName).Get(context.TODO(), operatorGroup.Name, metav1.GetOptions{})
  2010  				if err != nil {
  2011  					return nil, err
  2012  				}
  2013  				return og.Status.Namespaces, nil
  2014  			}).Should(ConsistOf([]string{secondNamespaceName}))
  2015  
  2016  			depName := genName("hat-server")
  2017  			mockGroup := fmt.Sprintf("hats.%s.redhat.com", genName(""))
  2018  			version := "v1alpha1"
  2019  			mockGroupVersion := strings.Join([]string{mockGroup, version}, "/")
  2020  			mockKinds := []string{"fedora"}
  2021  			depSpec := newMockExtServerDeployment(depName, []mockGroupVersionKind{{depName, mockGroupVersion, mockKinds, 5443}})
  2022  			apiServiceName := strings.Join([]string{version, mockGroup}, ".")
  2023  
  2024  			By("Create CSVs for the hat-server")
  2025  			strategy := operatorsv1alpha1.StrategyDetailsDeployment{
  2026  				DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
  2027  					{
  2028  						Name: depName,
  2029  						Spec: depSpec,
  2030  					},
  2031  				},
  2032  			}
  2033  
  2034  			owned := make([]operatorsv1alpha1.APIServiceDescription, len(mockKinds))
  2035  			for i, kind := range mockKinds {
  2036  				owned[i] = operatorsv1alpha1.APIServiceDescription{
  2037  					Name:           apiServiceName,
  2038  					Group:          mockGroup,
  2039  					Version:        version,
  2040  					Kind:           kind,
  2041  					DeploymentName: depName,
  2042  					ContainerPort:  int32(5443),
  2043  					DisplayName:    kind,
  2044  					Description:    fmt.Sprintf("A %s", kind),
  2045  				}
  2046  			}
  2047  
  2048  			csv := operatorsv1alpha1.ClusterServiceVersion{
  2049  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  2050  					MinKubeVersion: "0.0.0",
  2051  					InstallModes: []operatorsv1alpha1.InstallMode{
  2052  						{
  2053  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  2054  							Supported: true,
  2055  						},
  2056  						{
  2057  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  2058  							Supported: true,
  2059  						},
  2060  						{
  2061  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  2062  							Supported: true,
  2063  						},
  2064  						{
  2065  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  2066  							Supported: true,
  2067  						},
  2068  					},
  2069  					InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
  2070  						StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
  2071  						StrategySpec: strategy,
  2072  					},
  2073  					APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{
  2074  						Owned: owned,
  2075  					},
  2076  				},
  2077  			}
  2078  			csv.SetName("csv-hat-1")
  2079  
  2080  			By("Create the initial CSV")
  2081  			cleanupCSV, err := createCSV(c, crc, csv, generatedNamespace.GetName(), false, false)
  2082  			Expect(err).ShouldNot(HaveOccurred())
  2083  			defer cleanupCSV()
  2084  
  2085  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvSucceededChecker)
  2086  			Expect(err).ShouldNot(HaveOccurred())
  2087  
  2088  			By("Should create Deployment")
  2089  			_, err = c.GetDeployment(generatedNamespace.GetName(), depName)
  2090  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected Deployment")
  2091  
  2092  			By("Should create APIService")
  2093  			_, err = c.GetAPIService(apiServiceName)
  2094  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected APIService")
  2095  
  2096  			By("Should create Service")
  2097  			serviceName := fmt.Sprintf("%s-service", depName)
  2098  			_, err = c.GetService(generatedNamespace.GetName(), serviceName)
  2099  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected Service")
  2100  
  2101  			By("Should create certificate Secret")
  2102  			secretName := fmt.Sprintf("%s-cert", serviceName)
  2103  			_, err = c.GetSecret(generatedNamespace.GetName(), secretName)
  2104  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected Secret")
  2105  
  2106  			By("Should create a Role for the Secret")
  2107  			_, err = c.GetRole(generatedNamespace.GetName(), secretName)
  2108  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected Secret Role")
  2109  
  2110  			By("Should create a RoleBinding for the Secret")
  2111  			_, err = c.GetRoleBinding(generatedNamespace.GetName(), secretName)
  2112  			Expect(err).ShouldNot(HaveOccurred(), "error getting exptected Secret RoleBinding")
  2113  
  2114  			By("Should create a system:auth-delegator Cluster RoleBinding")
  2115  			_, err = c.GetClusterRoleBinding(fmt.Sprintf("%s-system:auth-delegator", serviceName))
  2116  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected system:auth-delegator ClusterRoleBinding")
  2117  
  2118  			By("Should create an extension-apiserver-authentication-reader RoleBinding in kube-system")
  2119  			_, err = c.GetRoleBinding("kube-system", fmt.Sprintf("%s-auth-reader", serviceName))
  2120  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected extension-apiserver-authentication-reader RoleBinding")
  2121  
  2122  			By("Create a new CSV that owns the same API Service but in a different namespace")
  2123  			csv2 := operatorsv1alpha1.ClusterServiceVersion{
  2124  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  2125  					MinKubeVersion: "0.0.0",
  2126  					InstallModes: []operatorsv1alpha1.InstallMode{
  2127  						{
  2128  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  2129  							Supported: true,
  2130  						},
  2131  						{
  2132  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  2133  							Supported: true,
  2134  						},
  2135  						{
  2136  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  2137  							Supported: true,
  2138  						},
  2139  						{
  2140  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  2141  							Supported: true,
  2142  						},
  2143  					},
  2144  					InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
  2145  						StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
  2146  						StrategySpec: strategy,
  2147  					},
  2148  					APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{
  2149  						Owned: owned,
  2150  					},
  2151  				},
  2152  			}
  2153  			csv2.SetName("csv-hat-2")
  2154  
  2155  			By("Create CSV2 to replace CSV")
  2156  			_, err = createCSV(c, crc, csv2, secondNamespaceName, false, true)
  2157  			Expect(err).ShouldNot(HaveOccurred())
  2158  
  2159  			_, err = fetchCSV(crc, secondNamespaceName, csv2.Name, csvFailedChecker)
  2160  			Expect(err).ShouldNot(HaveOccurred())
  2161  		})
  2162  		It("orphaned API service clean up", func() {
  2163  
  2164  			mockGroup := fmt.Sprintf("hats.%s.redhat.com", genName(""))
  2165  			version := "v1alpha1"
  2166  			apiServiceName := strings.Join([]string{version, mockGroup}, ".")
  2167  
  2168  			apiService := &apiregistrationv1.APIService{
  2169  				ObjectMeta: metav1.ObjectMeta{
  2170  					Name: apiServiceName,
  2171  				},
  2172  				Spec: apiregistrationv1.APIServiceSpec{
  2173  					Group:                mockGroup,
  2174  					Version:              version,
  2175  					GroupPriorityMinimum: 100,
  2176  					VersionPriority:      100,
  2177  				},
  2178  			}
  2179  
  2180  			watcher, err := c.ApiregistrationV1Interface().ApiregistrationV1().APIServices().Watch(context.TODO(), metav1.ListOptions{FieldSelector: "metadata.name=" + apiServiceName})
  2181  			Expect(err).ShouldNot(HaveOccurred())
  2182  
  2183  			deleted := make(chan struct{})
  2184  			quit := make(chan struct{})
  2185  			defer close(quit)
  2186  			go func() {
  2187  				defer GinkgoRecover()
  2188  				events := watcher.ResultChan()
  2189  				for {
  2190  					select {
  2191  					case <-quit:
  2192  						return
  2193  					case evt := <-events:
  2194  						if evt.Type == watch.Deleted {
  2195  							deleted <- struct{}{}
  2196  						}
  2197  					case <-time.After(pollDuration):
  2198  						Fail("orphaned apiservice not cleaned up as expected")
  2199  					}
  2200  				}
  2201  			}()
  2202  
  2203  			_, err = c.CreateAPIService(apiService)
  2204  			Expect(err).ShouldNot(HaveOccurred(), "error creating expected APIService")
  2205  			orphanedAPISvc, err := c.GetAPIService(apiServiceName)
  2206  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected APIService")
  2207  
  2208  			newLabels := map[string]string{"olm.owner": "hat-serverfd4r5", "olm.owner.kind": "ClusterServiceVersion", "olm.owner.namespace": "nonexistent-namespace"}
  2209  			orphanedAPISvc.SetLabels(newLabels)
  2210  			_, err = c.UpdateAPIService(orphanedAPISvc)
  2211  			Expect(err).ShouldNot(HaveOccurred(), "error updating APIService")
  2212  			<-deleted
  2213  
  2214  			_, err = c.CreateAPIService(apiService)
  2215  			Expect(err).ShouldNot(HaveOccurred(), "error creating expected APIService")
  2216  			orphanedAPISvc, err = c.GetAPIService(apiServiceName)
  2217  			Expect(err).ShouldNot(HaveOccurred(), "error getting expected APIService")
  2218  
  2219  			newLabels = map[string]string{"olm.owner": "hat-serverfd4r5", "olm.owner.kind": "ClusterServiceVersion", "olm.owner.namespace": generatedNamespace.GetName()}
  2220  			orphanedAPISvc.SetLabels(newLabels)
  2221  			_, err = c.UpdateAPIService(orphanedAPISvc)
  2222  			Expect(err).ShouldNot(HaveOccurred(), "error updating APIService")
  2223  			<-deleted
  2224  		})
  2225  		It("CSV annotations overwrite pod template annotations defined in a StrategyDetailsDeployment", func() {
  2226  			By("Create a StrategyDetailsDeployment that defines the `foo1` and `foo2` annotations on a pod template")
  2227  			nginxName := genName("nginx-")
  2228  			strategy := operatorsv1alpha1.StrategyDetailsDeployment{
  2229  				DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
  2230  					{
  2231  						Name: genName("dep-"),
  2232  						Spec: newNginxDeployment(nginxName),
  2233  					},
  2234  				},
  2235  			}
  2236  			strategy.DeploymentSpecs[0].Spec.Template.Annotations = map[string]string{
  2237  				"foo1": "notBar1",
  2238  				"foo2": "bar2",
  2239  			}
  2240  
  2241  			By("Create a CSV that defines the `foo1` and `foo3` annotations")
  2242  			csv := operatorsv1alpha1.ClusterServiceVersion{
  2243  				TypeMeta: metav1.TypeMeta{
  2244  					Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
  2245  					APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
  2246  				},
  2247  				ObjectMeta: metav1.ObjectMeta{
  2248  					Name: genName("csv"),
  2249  					Annotations: map[string]string{
  2250  						"foo1": "bar1",
  2251  						"foo3": "bar3",
  2252  					},
  2253  				},
  2254  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  2255  					MinKubeVersion: "0.0.0",
  2256  					InstallModes: []operatorsv1alpha1.InstallMode{
  2257  						{
  2258  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  2259  							Supported: true,
  2260  						},
  2261  						{
  2262  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  2263  							Supported: true,
  2264  						},
  2265  						{
  2266  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  2267  							Supported: true,
  2268  						},
  2269  						{
  2270  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  2271  							Supported: true,
  2272  						},
  2273  					},
  2274  					InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
  2275  						StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
  2276  						StrategySpec: strategy,
  2277  					},
  2278  				},
  2279  			}
  2280  
  2281  			By("Create the CSV and make sure to clean it up")
  2282  			cleanupCSV, err := createCSV(c, crc, csv, generatedNamespace.GetName(), false, false)
  2283  			Expect(err).ShouldNot(HaveOccurred())
  2284  			defer cleanupCSV()
  2285  
  2286  			By("Wait for current CSV to succeed")
  2287  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvSucceededChecker)
  2288  			Expect(err).ShouldNot(HaveOccurred())
  2289  
  2290  			By("Should have created deployment")
  2291  			dep, err := c.GetDeployment(generatedNamespace.GetName(), strategy.DeploymentSpecs[0].Name)
  2292  			Expect(err).ShouldNot(HaveOccurred())
  2293  			Expect(dep).ShouldNot(BeNil())
  2294  
  2295  			By("Make sure that the pods annotations are correct")
  2296  			annotations := dep.Spec.Template.Annotations
  2297  			Expect(annotations["foo1"]).Should(Equal("bar1"))
  2298  			Expect(annotations["foo2"]).Should(Equal("bar2"))
  2299  			Expect(annotations["foo3"]).Should(Equal("bar3"))
  2300  		})
  2301  		It("Set labels for the Deployment created via the ClusterServiceVersion", func() {
  2302  			By("Create a StrategyDetailsDeployment that defines labels for Deployment inside")
  2303  			nginxName := genName("nginx-")
  2304  			strategy := operatorsv1alpha1.StrategyDetailsDeployment{
  2305  				DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
  2306  					{
  2307  						Name: genName("dep-"),
  2308  						Spec: newNginxDeployment(nginxName),
  2309  						Label: k8slabels.Set{
  2310  							"application":      "nginx",
  2311  							"application.type": "proxy",
  2312  						},
  2313  					},
  2314  				},
  2315  			}
  2316  
  2317  			csv := operatorsv1alpha1.ClusterServiceVersion{
  2318  				TypeMeta: metav1.TypeMeta{
  2319  					Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
  2320  					APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
  2321  				},
  2322  				ObjectMeta: metav1.ObjectMeta{
  2323  					Name: genName("csv"),
  2324  				},
  2325  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  2326  					MinKubeVersion: "0.0.0",
  2327  					InstallModes: []operatorsv1alpha1.InstallMode{
  2328  						{
  2329  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  2330  							Supported: true,
  2331  						},
  2332  						{
  2333  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  2334  							Supported: true,
  2335  						},
  2336  						{
  2337  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  2338  							Supported: true,
  2339  						},
  2340  						{
  2341  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  2342  							Supported: true,
  2343  						},
  2344  					},
  2345  					InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
  2346  						StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
  2347  						StrategySpec: strategy,
  2348  					},
  2349  				},
  2350  			}
  2351  
  2352  			By("Create the CSV and make sure to clean it up")
  2353  			cleanupCSV, err := createCSV(c, crc, csv, generatedNamespace.GetName(), false, false)
  2354  			Expect(err).ShouldNot(HaveOccurred())
  2355  			defer cleanupCSV()
  2356  
  2357  			By("Wait for current CSV to succeed")
  2358  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvSucceededChecker)
  2359  			Expect(err).ShouldNot(HaveOccurred())
  2360  
  2361  			By("Should have created deployment")
  2362  			dep, err := c.GetDeployment(generatedNamespace.GetName(), strategy.DeploymentSpecs[0].Name)
  2363  			Expect(err).ShouldNot(HaveOccurred())
  2364  			Expect(dep).ShouldNot(BeNil())
  2365  
  2366  			By("Make sure that the deployment labels are correct")
  2367  			labels := dep.GetLabels()
  2368  			Expect(labels["olm.owner"]).Should(Equal(csv.GetName()))
  2369  			Expect(labels["olm.owner.namespace"]).Should(Equal(generatedNamespace.GetName()))
  2370  			Expect(labels["application"]).Should(Equal("nginx"))
  2371  			Expect(labels["application.type"]).Should(Equal("proxy"))
  2372  		})
  2373  		It("update same deployment name", func() {
  2374  
  2375  			By("Create dependency first (CRD)")
  2376  			crdPlural := genName("ins")
  2377  			crdName := crdPlural + ".cluster.com"
  2378  			cleanupCRD, err := createCRD(c, apiextensionsv1.CustomResourceDefinition{
  2379  				ObjectMeta: metav1.ObjectMeta{
  2380  					Name: crdName,
  2381  				},
  2382  				Spec: apiextensionsv1.CustomResourceDefinitionSpec{
  2383  					Group: "cluster.com",
  2384  					Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
  2385  						{
  2386  							Name:    "v1alpha1",
  2387  							Served:  true,
  2388  							Storage: true,
  2389  							Schema: &apiextensionsv1.CustomResourceValidation{
  2390  								OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
  2391  									Type:        "object",
  2392  									Description: "my crd schema",
  2393  								},
  2394  							},
  2395  						},
  2396  					},
  2397  					Names: apiextensionsv1.CustomResourceDefinitionNames{
  2398  						Plural:   crdPlural,
  2399  						Singular: crdPlural,
  2400  						Kind:     crdPlural,
  2401  						ListKind: "list" + crdPlural,
  2402  					},
  2403  					Scope: apiextensionsv1.NamespaceScoped,
  2404  				},
  2405  			})
  2406  
  2407  			By("Create current CSV")
  2408  			nginxName := genName("nginx-")
  2409  			strategy := operatorsv1alpha1.StrategyDetailsDeployment{
  2410  				DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
  2411  					{
  2412  						Name: genName("dep-"),
  2413  						Spec: newNginxDeployment(nginxName),
  2414  					},
  2415  				},
  2416  			}
  2417  
  2418  			Expect(err).ShouldNot(HaveOccurred())
  2419  
  2420  			Expect(err).ShouldNot(HaveOccurred())
  2421  			defer cleanupCRD()
  2422  			csv := operatorsv1alpha1.ClusterServiceVersion{
  2423  				TypeMeta: metav1.TypeMeta{
  2424  					Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
  2425  					APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
  2426  				},
  2427  				ObjectMeta: metav1.ObjectMeta{
  2428  					Name: genName("csv"),
  2429  				},
  2430  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  2431  					MinKubeVersion: "0.0.0",
  2432  					InstallModes: []operatorsv1alpha1.InstallMode{
  2433  						{
  2434  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  2435  							Supported: true,
  2436  						},
  2437  						{
  2438  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  2439  							Supported: true,
  2440  						},
  2441  						{
  2442  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  2443  							Supported: true,
  2444  						},
  2445  						{
  2446  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  2447  							Supported: true,
  2448  						},
  2449  					},
  2450  					InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
  2451  						StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
  2452  						StrategySpec: strategy,
  2453  					},
  2454  					CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{
  2455  						Owned: []operatorsv1alpha1.CRDDescription{
  2456  							{
  2457  								Name:        crdName,
  2458  								Version:     "v1alpha1",
  2459  								Kind:        crdPlural,
  2460  								DisplayName: crdName,
  2461  								Description: "In the cluster",
  2462  							},
  2463  						},
  2464  					},
  2465  				},
  2466  			}
  2467  
  2468  			By("Don't need to cleanup this CSV, it will be deleted by the upgrade process")
  2469  			_, err = createCSV(c, crc, csv, generatedNamespace.GetName(), false, false)
  2470  			Expect(err).ShouldNot(HaveOccurred())
  2471  
  2472  			By("Wait for current CSV to succeed")
  2473  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvSucceededChecker)
  2474  			Expect(err).ShouldNot(HaveOccurred())
  2475  
  2476  			By("Should have created deployment")
  2477  			dep, err := c.GetDeployment(generatedNamespace.GetName(), strategy.DeploymentSpecs[0].Name)
  2478  			Expect(err).ShouldNot(HaveOccurred())
  2479  			Expect(dep).ShouldNot(BeNil())
  2480  
  2481  			By("Create updated CSV with the same name but a different spec")
  2482  			strategyNew := operatorsv1alpha1.StrategyDetailsDeployment{
  2483  				DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
  2484  					{
  2485  						Name: strategy.DeploymentSpecs[0].Name,
  2486  						Spec: newNginxDeployment(nginxName),
  2487  					},
  2488  				},
  2489  			}
  2490  
  2491  			Expect(err).ShouldNot(HaveOccurred())
  2492  
  2493  			csvNew := operatorsv1alpha1.ClusterServiceVersion{
  2494  				TypeMeta: metav1.TypeMeta{
  2495  					Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
  2496  					APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
  2497  				},
  2498  				ObjectMeta: metav1.ObjectMeta{
  2499  					Name: genName("csv"),
  2500  				},
  2501  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  2502  					Replaces: csv.Name,
  2503  					InstallModes: []operatorsv1alpha1.InstallMode{
  2504  						{
  2505  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  2506  							Supported: true,
  2507  						},
  2508  						{
  2509  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  2510  							Supported: true,
  2511  						},
  2512  						{
  2513  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  2514  							Supported: true,
  2515  						},
  2516  						{
  2517  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  2518  							Supported: true,
  2519  						},
  2520  					},
  2521  					InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
  2522  						StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
  2523  						StrategySpec: strategyNew,
  2524  					},
  2525  					CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{
  2526  						Owned: []operatorsv1alpha1.CRDDescription{
  2527  							{
  2528  								Name:        crdName,
  2529  								Version:     "v1alpha1",
  2530  								Kind:        crdPlural,
  2531  								DisplayName: crdName,
  2532  								Description: "In the cluster",
  2533  							},
  2534  						},
  2535  					},
  2536  				},
  2537  			}
  2538  
  2539  			cleanupNewCSV, err := createCSV(c, crc, csvNew, generatedNamespace.GetName(), true, false)
  2540  			Expect(err).ShouldNot(HaveOccurred())
  2541  			defer cleanupNewCSV()
  2542  
  2543  			By("Wait for updated CSV to succeed")
  2544  			fetchedCSV, err := fetchCSV(crc, generatedNamespace.GetName(), csvNew.Name, csvSucceededChecker)
  2545  			Expect(err).ShouldNot(HaveOccurred())
  2546  
  2547  			By("Should have updated existing deployment")
  2548  			depUpdated, err := c.GetDeployment(generatedNamespace.GetName(), strategyNew.DeploymentSpecs[0].Name)
  2549  			Expect(err).ShouldNot(HaveOccurred())
  2550  			Expect(depUpdated).ShouldNot(BeNil())
  2551  			Expect(strategyNew.DeploymentSpecs[0].Spec.Template.Spec.Containers[0].Name).Should(Equal(depUpdated.Spec.Template.Spec.Containers[0].Name))
  2552  
  2553  			By("Should eventually GC the CSV")
  2554  			err = waitForCsvToDelete(generatedNamespace.GetName(), csv.Name, crc)
  2555  			Expect(err).ShouldNot(HaveOccurred())
  2556  
  2557  			By("Fetch cluster service version again to check for unnecessary control loops")
  2558  			sameCSV, err := fetchCSV(crc, generatedNamespace.GetName(), csvNew.Name, csvSucceededChecker)
  2559  			Expect(err).ShouldNot(HaveOccurred())
  2560  			Expect(equality.Semantic.DeepEqual(fetchedCSV, sameCSV)).Should(BeTrue(), diff.ObjectDiff(fetchedCSV, sameCSV))
  2561  		})
  2562  		It("update different deployment name", func() {
  2563  
  2564  			By("Create dependency first (CRD)")
  2565  			crdPlural := genName("ins2")
  2566  			crdName := crdPlural + ".cluster.com"
  2567  			cleanupCRD, err := createCRD(c, apiextensionsv1.CustomResourceDefinition{
  2568  				ObjectMeta: metav1.ObjectMeta{
  2569  					Name: crdName,
  2570  				},
  2571  				Spec: apiextensionsv1.CustomResourceDefinitionSpec{
  2572  					Group: "cluster.com",
  2573  					Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
  2574  						{
  2575  							Name:    "v1alpha1",
  2576  							Served:  true,
  2577  							Storage: true,
  2578  							Schema: &apiextensionsv1.CustomResourceValidation{
  2579  								OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
  2580  									Type:        "object",
  2581  									Description: "my crd schema",
  2582  								},
  2583  							},
  2584  						},
  2585  					},
  2586  					Names: apiextensionsv1.CustomResourceDefinitionNames{
  2587  						Plural:   crdPlural,
  2588  						Singular: crdPlural,
  2589  						Kind:     crdPlural,
  2590  						ListKind: "list" + crdPlural,
  2591  					},
  2592  					Scope: apiextensionsv1.NamespaceScoped,
  2593  				},
  2594  			})
  2595  			Expect(err).ShouldNot(HaveOccurred())
  2596  			defer cleanupCRD()
  2597  
  2598  			By("create current CSV")
  2599  			strategy := operatorsv1alpha1.StrategyDetailsDeployment{
  2600  				DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
  2601  					{
  2602  						Name: genName("dep-"),
  2603  						Spec: newNginxDeployment(genName("nginx-")),
  2604  					},
  2605  				},
  2606  			}
  2607  
  2608  			Expect(err).ShouldNot(HaveOccurred())
  2609  
  2610  			csv := operatorsv1alpha1.ClusterServiceVersion{
  2611  				TypeMeta: metav1.TypeMeta{
  2612  					Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
  2613  					APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
  2614  				},
  2615  				ObjectMeta: metav1.ObjectMeta{
  2616  					Name: genName("csv"),
  2617  				},
  2618  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  2619  					MinKubeVersion: "0.0.0",
  2620  					InstallModes: []operatorsv1alpha1.InstallMode{
  2621  						{
  2622  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  2623  							Supported: true,
  2624  						},
  2625  						{
  2626  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  2627  							Supported: true,
  2628  						},
  2629  						{
  2630  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  2631  							Supported: true,
  2632  						},
  2633  						{
  2634  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  2635  							Supported: true,
  2636  						},
  2637  					},
  2638  					InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
  2639  						StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
  2640  						StrategySpec: strategy,
  2641  					},
  2642  					CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{
  2643  						Owned: []operatorsv1alpha1.CRDDescription{
  2644  							{
  2645  								Name:        crdName,
  2646  								Version:     "v1alpha1",
  2647  								Kind:        crdPlural,
  2648  								DisplayName: crdName,
  2649  								Description: "In the cluster2",
  2650  							},
  2651  						},
  2652  					},
  2653  				},
  2654  			}
  2655  
  2656  			By("don't need to clean up this CSV, it will be deleted by the upgrade process")
  2657  			_, err = createCSV(c, crc, csv, generatedNamespace.GetName(), false, false)
  2658  			Expect(err).ShouldNot(HaveOccurred())
  2659  
  2660  			By("Wait for current CSV to succeed")
  2661  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvSucceededChecker)
  2662  			Expect(err).ShouldNot(HaveOccurred())
  2663  
  2664  			By("Should have created deployment")
  2665  			dep, err := c.GetDeployment(generatedNamespace.GetName(), strategy.DeploymentSpecs[0].Name)
  2666  			Expect(err).ShouldNot(HaveOccurred())
  2667  			Expect(dep).ShouldNot(BeNil())
  2668  
  2669  			By("Create updated CSV")
  2670  			strategyNew := operatorsv1alpha1.StrategyDetailsDeployment{
  2671  				DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
  2672  					{
  2673  						Name: genName("dep2"),
  2674  						Spec: newNginxDeployment(genName("nginx-")),
  2675  					},
  2676  				},
  2677  			}
  2678  
  2679  			Expect(err).ShouldNot(HaveOccurred())
  2680  
  2681  			csvNew := operatorsv1alpha1.ClusterServiceVersion{
  2682  				TypeMeta: metav1.TypeMeta{
  2683  					Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
  2684  					APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
  2685  				},
  2686  				ObjectMeta: metav1.ObjectMeta{
  2687  					Name: genName("csv2"),
  2688  				},
  2689  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  2690  					Replaces: csv.Name,
  2691  					InstallModes: []operatorsv1alpha1.InstallMode{
  2692  						{
  2693  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  2694  							Supported: true,
  2695  						},
  2696  						{
  2697  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  2698  							Supported: true,
  2699  						},
  2700  						{
  2701  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  2702  							Supported: true,
  2703  						},
  2704  						{
  2705  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  2706  							Supported: true,
  2707  						},
  2708  					},
  2709  					InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
  2710  						StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
  2711  						StrategySpec: strategyNew,
  2712  					},
  2713  					CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{
  2714  						Owned: []operatorsv1alpha1.CRDDescription{
  2715  							{
  2716  								Name:        crdName,
  2717  								Version:     "v1alpha1",
  2718  								Kind:        crdPlural,
  2719  								DisplayName: crdName,
  2720  								Description: "In the cluster2",
  2721  							},
  2722  						},
  2723  					},
  2724  				},
  2725  			}
  2726  
  2727  			cleanupNewCSV, err := createCSV(c, crc, csvNew, generatedNamespace.GetName(), true, false)
  2728  			Expect(err).ShouldNot(HaveOccurred())
  2729  			defer cleanupNewCSV()
  2730  
  2731  			By("Wait for updated CSV to succeed")
  2732  			fetchedCSV, err := fetchCSV(crc, generatedNamespace.GetName(), csvNew.Name, csvSucceededChecker)
  2733  			Expect(err).ShouldNot(HaveOccurred())
  2734  
  2735  			By("Fetch cluster service version again to check for unnecessary control loops")
  2736  			sameCSV, err := fetchCSV(crc, generatedNamespace.GetName(), csvNew.Name, csvSucceededChecker)
  2737  			Expect(err).ShouldNot(HaveOccurred())
  2738  			Expect(equality.Semantic.DeepEqual(fetchedCSV, sameCSV)).Should(BeTrue(), diff.ObjectDiff(fetchedCSV, sameCSV))
  2739  
  2740  			By("Should have created new deployment and deleted old")
  2741  			depNew, err := c.GetDeployment(generatedNamespace.GetName(), strategyNew.DeploymentSpecs[0].Name)
  2742  			Expect(err).ShouldNot(HaveOccurred())
  2743  			Expect(depNew).ShouldNot(BeNil())
  2744  			err = waitForDeploymentToDelete(generatedNamespace.GetName(), strategy.DeploymentSpecs[0].Name, c)
  2745  			Expect(err).ShouldNot(HaveOccurred())
  2746  
  2747  			By("Should eventually GC the CSV")
  2748  			err = waitForCsvToDelete(generatedNamespace.GetName(), csv.Name, crc)
  2749  			Expect(err).ShouldNot(HaveOccurred())
  2750  		})
  2751  		It("update multiple intermediates", func() {
  2752  
  2753  			By("Create dependency first (CRD)")
  2754  			crdPlural := genName("ins3")
  2755  			crdName := crdPlural + ".cluster.com"
  2756  			cleanupCRD, err := createCRD(c, apiextensionsv1.CustomResourceDefinition{
  2757  				ObjectMeta: metav1.ObjectMeta{
  2758  					Name: crdName,
  2759  				},
  2760  				Spec: apiextensionsv1.CustomResourceDefinitionSpec{
  2761  					Group: "cluster.com",
  2762  					Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
  2763  						{
  2764  							Name:    "v1alpha1",
  2765  							Served:  true,
  2766  							Storage: true,
  2767  							Schema: &apiextensionsv1.CustomResourceValidation{
  2768  								OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
  2769  									Type:        "object",
  2770  									Description: "my crd schema",
  2771  								},
  2772  							},
  2773  						},
  2774  					},
  2775  					Names: apiextensionsv1.CustomResourceDefinitionNames{
  2776  						Plural:   crdPlural,
  2777  						Singular: crdPlural,
  2778  						Kind:     crdPlural,
  2779  						ListKind: "list" + crdPlural,
  2780  					},
  2781  					Scope: apiextensionsv1.NamespaceScoped,
  2782  				},
  2783  			})
  2784  			Expect(err).ShouldNot(HaveOccurred())
  2785  			defer cleanupCRD()
  2786  
  2787  			By("create current CSV")
  2788  			strategy := operatorsv1alpha1.StrategyDetailsDeployment{
  2789  				DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
  2790  					{
  2791  						Name: genName("dep-"),
  2792  						Spec: newNginxDeployment(genName("nginx-")),
  2793  					},
  2794  				},
  2795  			}
  2796  
  2797  			Expect(err).ShouldNot(HaveOccurred())
  2798  
  2799  			csv := operatorsv1alpha1.ClusterServiceVersion{
  2800  				TypeMeta: metav1.TypeMeta{
  2801  					Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
  2802  					APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
  2803  				},
  2804  				ObjectMeta: metav1.ObjectMeta{
  2805  					Name: genName("csv"),
  2806  				},
  2807  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  2808  					MinKubeVersion: "0.0.0",
  2809  					InstallModes: []operatorsv1alpha1.InstallMode{
  2810  						{
  2811  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  2812  							Supported: true,
  2813  						},
  2814  						{
  2815  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  2816  							Supported: true,
  2817  						},
  2818  						{
  2819  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  2820  							Supported: true,
  2821  						},
  2822  						{
  2823  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  2824  							Supported: true,
  2825  						},
  2826  					},
  2827  					InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
  2828  						StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
  2829  						StrategySpec: strategy,
  2830  					},
  2831  					CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{
  2832  						Owned: []operatorsv1alpha1.CRDDescription{
  2833  							{
  2834  								Name:        crdName,
  2835  								Version:     "v1alpha1",
  2836  								Kind:        crdPlural,
  2837  								DisplayName: crdName,
  2838  								Description: "In the cluster3",
  2839  							},
  2840  						},
  2841  					},
  2842  				},
  2843  			}
  2844  
  2845  			By("don't need to clean up this CSV, it will be deleted by the upgrade process")
  2846  			_, err = createCSV(c, crc, csv, generatedNamespace.GetName(), false, false)
  2847  			Expect(err).ShouldNot(HaveOccurred())
  2848  
  2849  			By("Wait for current CSV to succeed")
  2850  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvSucceededChecker)
  2851  			Expect(err).ShouldNot(HaveOccurred())
  2852  
  2853  			By("Should have created deployment")
  2854  			dep, err := c.GetDeployment(generatedNamespace.GetName(), strategy.DeploymentSpecs[0].Name)
  2855  			Expect(err).ShouldNot(HaveOccurred())
  2856  			Expect(dep).ShouldNot(BeNil())
  2857  
  2858  			By("Create updated CSV")
  2859  			strategyNew := operatorsv1alpha1.StrategyDetailsDeployment{
  2860  				DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
  2861  					{
  2862  						Name: genName("dep2"),
  2863  						Spec: newNginxDeployment(genName("nginx-")),
  2864  					},
  2865  				},
  2866  			}
  2867  
  2868  			Expect(err).ShouldNot(HaveOccurred())
  2869  
  2870  			csvNew := operatorsv1alpha1.ClusterServiceVersion{
  2871  				TypeMeta: metav1.TypeMeta{
  2872  					Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
  2873  					APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
  2874  				},
  2875  				ObjectMeta: metav1.ObjectMeta{
  2876  					Name: genName("csv2"),
  2877  				},
  2878  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  2879  					Replaces: csv.Name,
  2880  					InstallModes: []operatorsv1alpha1.InstallMode{
  2881  						{
  2882  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  2883  							Supported: true,
  2884  						},
  2885  						{
  2886  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  2887  							Supported: true,
  2888  						},
  2889  						{
  2890  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  2891  							Supported: true,
  2892  						},
  2893  						{
  2894  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  2895  							Supported: true,
  2896  						},
  2897  					},
  2898  					InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
  2899  						StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
  2900  						StrategySpec: strategyNew,
  2901  					},
  2902  					CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{
  2903  						Owned: []operatorsv1alpha1.CRDDescription{
  2904  							{
  2905  								Name:        crdName,
  2906  								Version:     "v1alpha1",
  2907  								Kind:        crdPlural,
  2908  								DisplayName: crdName,
  2909  								Description: "In the cluster3",
  2910  							},
  2911  						},
  2912  					},
  2913  				},
  2914  			}
  2915  
  2916  			cleanupNewCSV, err := createCSV(c, crc, csvNew, generatedNamespace.GetName(), true, false)
  2917  			Expect(err).ShouldNot(HaveOccurred())
  2918  			defer cleanupNewCSV()
  2919  
  2920  			By("Wait for updated CSV to succeed")
  2921  			fetchedCSV, err := fetchCSV(crc, generatedNamespace.GetName(), csvNew.Name, csvSucceededChecker)
  2922  			Expect(err).ShouldNot(HaveOccurred())
  2923  
  2924  			By("Fetch cluster service version again to check for unnecessary control loops")
  2925  			sameCSV, err := fetchCSV(crc, generatedNamespace.GetName(), csvNew.Name, csvSucceededChecker)
  2926  			Expect(err).ShouldNot(HaveOccurred())
  2927  			Expect(equality.Semantic.DeepEqual(fetchedCSV, sameCSV)).Should(BeTrue(), diff.ObjectDiff(fetchedCSV, sameCSV))
  2928  
  2929  			By("Should have created new deployment and deleted old")
  2930  			depNew, err := c.GetDeployment(generatedNamespace.GetName(), strategyNew.DeploymentSpecs[0].Name)
  2931  			Expect(err).ShouldNot(HaveOccurred())
  2932  			Expect(depNew).ShouldNot(BeNil())
  2933  			err = waitForDeploymentToDelete(generatedNamespace.GetName(), strategy.DeploymentSpecs[0].Name, c)
  2934  			Expect(err).ShouldNot(HaveOccurred())
  2935  
  2936  			By("Should eventually GC the CSV")
  2937  			err = waitForCsvToDelete(generatedNamespace.GetName(), csv.Name, crc)
  2938  			Expect(err).ShouldNot(HaveOccurred())
  2939  		})
  2940  		It("update in place", func() {
  2941  
  2942  			By("Create dependency first (CRD)")
  2943  			crdPlural := genName("ins")
  2944  			crdName := crdPlural + ".cluster.com"
  2945  			cleanupCRD, err := createCRD(c, apiextensionsv1.CustomResourceDefinition{
  2946  				ObjectMeta: metav1.ObjectMeta{
  2947  					Name: crdName,
  2948  				},
  2949  				Spec: apiextensionsv1.CustomResourceDefinitionSpec{
  2950  					Group: "cluster.com",
  2951  					Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
  2952  						{
  2953  							Name:    "v1alpha1",
  2954  							Served:  true,
  2955  							Storage: true,
  2956  							Schema: &apiextensionsv1.CustomResourceValidation{
  2957  								OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
  2958  									Type:        "object",
  2959  									Description: "my crd schema",
  2960  								},
  2961  							},
  2962  						},
  2963  					},
  2964  					Names: apiextensionsv1.CustomResourceDefinitionNames{
  2965  						Plural:   crdPlural,
  2966  						Singular: crdPlural,
  2967  						Kind:     crdPlural,
  2968  						ListKind: "list" + crdPlural,
  2969  					},
  2970  					Scope: apiextensionsv1.NamespaceScoped,
  2971  				},
  2972  			})
  2973  
  2974  			By("Create current CSV")
  2975  			nginxName := genName("nginx-")
  2976  			strategy := operatorsv1alpha1.StrategyDetailsDeployment{
  2977  				DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
  2978  					{
  2979  						Name: genName("dep-"),
  2980  						Spec: newNginxDeployment(nginxName),
  2981  					},
  2982  				},
  2983  			}
  2984  
  2985  			Expect(err).ShouldNot(HaveOccurred())
  2986  
  2987  			Expect(err).ShouldNot(HaveOccurred())
  2988  			defer cleanupCRD()
  2989  			csv := operatorsv1alpha1.ClusterServiceVersion{
  2990  				TypeMeta: metav1.TypeMeta{
  2991  					Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
  2992  					APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
  2993  				},
  2994  				ObjectMeta: metav1.ObjectMeta{
  2995  					Name: genName("csv"),
  2996  				},
  2997  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  2998  					MinKubeVersion: "0.0.0",
  2999  					InstallModes: []operatorsv1alpha1.InstallMode{
  3000  						{
  3001  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  3002  							Supported: true,
  3003  						},
  3004  						{
  3005  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  3006  							Supported: true,
  3007  						},
  3008  						{
  3009  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  3010  							Supported: true,
  3011  						},
  3012  						{
  3013  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  3014  							Supported: true,
  3015  						},
  3016  					},
  3017  					InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
  3018  						StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
  3019  						StrategySpec: strategy,
  3020  					},
  3021  					CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{
  3022  						Owned: []operatorsv1alpha1.CRDDescription{
  3023  							{
  3024  								Name:        crdName,
  3025  								Version:     "v1alpha1",
  3026  								Kind:        crdPlural,
  3027  								DisplayName: crdName,
  3028  								Description: "In the cluster",
  3029  							},
  3030  						},
  3031  					},
  3032  				},
  3033  			}
  3034  
  3035  			cleanupCSV, err := createCSV(c, crc, csv, generatedNamespace.GetName(), false, true)
  3036  			Expect(err).ShouldNot(HaveOccurred())
  3037  			defer cleanupCSV()
  3038  
  3039  			By("Wait for current CSV to succeed")
  3040  			fetchedCSV, err := fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvSucceededChecker)
  3041  			Expect(err).ShouldNot(HaveOccurred())
  3042  
  3043  			By("Should have created deployment")
  3044  			dep, err := c.GetDeployment(generatedNamespace.GetName(), strategy.DeploymentSpecs[0].Name)
  3045  			Expect(err).ShouldNot(HaveOccurred())
  3046  			Expect(dep).ShouldNot(BeNil())
  3047  
  3048  			By("Create updated CSV")
  3049  			strategyNew := strategy
  3050  			strategyNew.DeploymentSpecs[0].Spec.Template.Spec.Containers = []corev1.Container{
  3051  				{
  3052  					Name:  genName("nginx-"),
  3053  					Image: *dummyImage,
  3054  					Ports: []corev1.ContainerPort{
  3055  						{
  3056  							ContainerPort: 80,
  3057  						},
  3058  					},
  3059  					ImagePullPolicy: corev1.PullIfNotPresent,
  3060  				},
  3061  			}
  3062  
  3063  			By("Also set something outside the spec template - this should be ignored")
  3064  			var five int32 = 5
  3065  			strategyNew.DeploymentSpecs[0].Spec.Replicas = &five
  3066  
  3067  			Expect(err).ShouldNot(HaveOccurred())
  3068  
  3069  			fetchedCSV.Spec.InstallStrategy.StrategySpec = strategyNew
  3070  
  3071  			By("Update CSV directly")
  3072  			_, err = crc.OperatorsV1alpha1().ClusterServiceVersions(generatedNamespace.GetName()).Update(context.TODO(), fetchedCSV, metav1.UpdateOptions{})
  3073  			Expect(err).ShouldNot(HaveOccurred())
  3074  
  3075  			By("wait for deployment spec to be updated")
  3076  			Eventually(func() (string, error) {
  3077  				fetched, err := c.GetDeployment(generatedNamespace.GetName(), strategyNew.DeploymentSpecs[0].Name)
  3078  				if err != nil {
  3079  					return "", err
  3080  				}
  3081  				ctx.Ctx().Logf("waiting for deployment to update...")
  3082  				return fetched.Spec.Template.Spec.Containers[0].Name, nil
  3083  			}).Should(Equal(strategyNew.DeploymentSpecs[0].Spec.Template.Spec.Containers[0].Name))
  3084  
  3085  			By("Wait for updated CSV to succeed")
  3086  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvSucceededChecker)
  3087  			Expect(err).ShouldNot(HaveOccurred())
  3088  
  3089  			depUpdated, err := c.GetDeployment(generatedNamespace.GetName(), strategyNew.DeploymentSpecs[0].Name)
  3090  			Expect(err).ShouldNot(HaveOccurred())
  3091  			Expect(depUpdated).ShouldNot(BeNil())
  3092  
  3093  			By("Deployment should have changed even though the CSV is otherwise the same")
  3094  			Expect(strategyNew.DeploymentSpecs[0].Spec.Template.Spec.Containers[0].Name).Should(Equal(depUpdated.Spec.Template.Spec.Containers[0].Name))
  3095  			Expect(strategyNew.DeploymentSpecs[0].Spec.Template.Spec.Containers[0].Image).Should(Equal(depUpdated.Spec.Template.Spec.Containers[0].Image))
  3096  
  3097  			By("Field updated even though template spec didn't change, because it was part of a template spec change as well")
  3098  			Expect(*strategyNew.DeploymentSpecs[0].Spec.Replicas).Should(Equal(*depUpdated.Spec.Replicas))
  3099  		})
  3100  		It("update multiple version CRD", func() {
  3101  
  3102  			By("Create initial CRD which has 2 versions: v1alpha1 & v1alpha2")
  3103  			crdPlural := genName("ins4")
  3104  			crdName := crdPlural + ".cluster.com"
  3105  			cleanupCRD, err := createCRD(c, apiextensionsv1.CustomResourceDefinition{
  3106  				ObjectMeta: metav1.ObjectMeta{
  3107  					Name: crdName,
  3108  				},
  3109  				Spec: apiextensionsv1.CustomResourceDefinitionSpec{
  3110  					Group: "cluster.com",
  3111  					Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
  3112  						{
  3113  							Name:    "v1alpha1",
  3114  							Served:  true,
  3115  							Storage: true,
  3116  							Schema: &apiextensionsv1.CustomResourceValidation{
  3117  								OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
  3118  									Type:        "object",
  3119  									Description: "my crd schema",
  3120  								},
  3121  							},
  3122  						},
  3123  						{
  3124  							Name:    "v1alpha2",
  3125  							Served:  true,
  3126  							Storage: false,
  3127  							Schema: &apiextensionsv1.CustomResourceValidation{
  3128  								OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
  3129  									Type:        "object",
  3130  									Description: "my crd schema",
  3131  								},
  3132  							},
  3133  						},
  3134  					},
  3135  					Names: apiextensionsv1.CustomResourceDefinitionNames{
  3136  						Plural:   crdPlural,
  3137  						Singular: crdPlural,
  3138  						Kind:     crdPlural,
  3139  						ListKind: "list" + crdPlural,
  3140  					},
  3141  					Scope: apiextensionsv1.NamespaceScoped,
  3142  				},
  3143  			})
  3144  			Expect(err).ShouldNot(HaveOccurred())
  3145  			defer cleanupCRD()
  3146  
  3147  			By("create initial deployment strategy")
  3148  			strategy := operatorsv1alpha1.StrategyDetailsDeployment{
  3149  				DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
  3150  					{
  3151  						Name: genName("dep1-"),
  3152  						Spec: newNginxDeployment(genName("nginx-")),
  3153  					},
  3154  				},
  3155  			}
  3156  
  3157  			Expect(err).ShouldNot(HaveOccurred())
  3158  
  3159  			By("First CSV with owning CRD v1alpha1")
  3160  			csv := operatorsv1alpha1.ClusterServiceVersion{
  3161  				TypeMeta: metav1.TypeMeta{
  3162  					Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
  3163  					APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
  3164  				},
  3165  				ObjectMeta: metav1.ObjectMeta{
  3166  					Name: genName("csv"),
  3167  				},
  3168  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  3169  					MinKubeVersion: "0.0.0",
  3170  					InstallModes: []operatorsv1alpha1.InstallMode{
  3171  						{
  3172  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  3173  							Supported: true,
  3174  						},
  3175  						{
  3176  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  3177  							Supported: true,
  3178  						},
  3179  						{
  3180  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  3181  							Supported: true,
  3182  						},
  3183  						{
  3184  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  3185  							Supported: true,
  3186  						},
  3187  					},
  3188  					InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
  3189  						StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
  3190  						StrategySpec: strategy,
  3191  					},
  3192  					CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{
  3193  						Owned: []operatorsv1alpha1.CRDDescription{
  3194  							{
  3195  								Name:        crdName,
  3196  								Version:     "v1alpha1",
  3197  								Kind:        crdPlural,
  3198  								DisplayName: crdName,
  3199  								Description: "In the cluster4",
  3200  							},
  3201  						},
  3202  					},
  3203  				},
  3204  			}
  3205  
  3206  			By("CSV will be deleted by the upgrade process later")
  3207  			_, err = createCSV(c, crc, csv, generatedNamespace.GetName(), false, false)
  3208  			Expect(err).ShouldNot(HaveOccurred())
  3209  
  3210  			By("Wait for current CSV to succeed")
  3211  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvSucceededChecker)
  3212  			Expect(err).ShouldNot(HaveOccurred())
  3213  
  3214  			By("Should have created deployment")
  3215  			dep, err := c.GetDeployment(generatedNamespace.GetName(), strategy.DeploymentSpecs[0].Name)
  3216  			Expect(err).ShouldNot(HaveOccurred())
  3217  			Expect(dep).ShouldNot(BeNil())
  3218  
  3219  			By("Create updated deployment strategy")
  3220  			strategyNew := operatorsv1alpha1.StrategyDetailsDeployment{
  3221  				DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
  3222  					{
  3223  						Name: genName("dep2-"),
  3224  						Spec: newNginxDeployment(genName("nginx-")),
  3225  					},
  3226  				},
  3227  			}
  3228  
  3229  			Expect(err).ShouldNot(HaveOccurred())
  3230  
  3231  			By("Second CSV with owning CRD v1alpha1 and v1alpha2")
  3232  			csvNew := operatorsv1alpha1.ClusterServiceVersion{
  3233  				TypeMeta: metav1.TypeMeta{
  3234  					Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
  3235  					APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
  3236  				},
  3237  				ObjectMeta: metav1.ObjectMeta{
  3238  					Name: genName("csv2"),
  3239  				},
  3240  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  3241  					Replaces: csv.Name,
  3242  					InstallModes: []operatorsv1alpha1.InstallMode{
  3243  						{
  3244  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  3245  							Supported: true,
  3246  						},
  3247  						{
  3248  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  3249  							Supported: true,
  3250  						},
  3251  						{
  3252  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  3253  							Supported: true,
  3254  						},
  3255  						{
  3256  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  3257  							Supported: true,
  3258  						},
  3259  					},
  3260  					InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
  3261  						StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
  3262  						StrategySpec: strategyNew,
  3263  					},
  3264  					CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{
  3265  						Owned: []operatorsv1alpha1.CRDDescription{
  3266  							{
  3267  								Name:        crdName,
  3268  								Version:     "v1alpha1",
  3269  								Kind:        crdPlural,
  3270  								DisplayName: crdName,
  3271  								Description: "In the cluster4",
  3272  							},
  3273  							{
  3274  								Name:        crdName,
  3275  								Version:     "v1alpha2",
  3276  								Kind:        crdPlural,
  3277  								DisplayName: crdName,
  3278  								Description: "In the cluster4",
  3279  							},
  3280  						},
  3281  					},
  3282  				},
  3283  			}
  3284  
  3285  			By("Create newly updated CSV")
  3286  			_, err = createCSV(c, crc, csvNew, generatedNamespace.GetName(), false, false)
  3287  			Expect(err).ShouldNot(HaveOccurred())
  3288  
  3289  			By("Wait for updated CSV to succeed")
  3290  			fetchedCSV, err := fetchCSV(crc, generatedNamespace.GetName(), csvNew.Name, csvSucceededChecker)
  3291  			Expect(err).ShouldNot(HaveOccurred())
  3292  
  3293  			By("Fetch cluster service version again to check for unnecessary control loops")
  3294  			sameCSV, err := fetchCSV(crc, generatedNamespace.GetName(), csvNew.Name, csvSucceededChecker)
  3295  			Expect(err).ShouldNot(HaveOccurred())
  3296  			Expect(equality.Semantic.DeepEqual(fetchedCSV, sameCSV)).Should(BeTrue(), diff.ObjectDiff(fetchedCSV, sameCSV))
  3297  
  3298  			By("Should have created new deployment and deleted old one")
  3299  			depNew, err := c.GetDeployment(generatedNamespace.GetName(), strategyNew.DeploymentSpecs[0].Name)
  3300  			Expect(err).ShouldNot(HaveOccurred())
  3301  			Expect(depNew).ShouldNot(BeNil())
  3302  			err = waitForDeploymentToDelete(generatedNamespace.GetName(), strategy.DeploymentSpecs[0].Name, c)
  3303  			Expect(err).ShouldNot(HaveOccurred())
  3304  
  3305  			By("Create updated deployment strategy")
  3306  			strategyNew2 := operatorsv1alpha1.StrategyDetailsDeployment{
  3307  				DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
  3308  					{
  3309  						Name: genName("dep3-"),
  3310  						Spec: newNginxDeployment(genName("nginx-")),
  3311  					},
  3312  				},
  3313  			}
  3314  			Expect(err).ShouldNot(HaveOccurred())
  3315  
  3316  			By("Third CSV with owning CRD v1alpha2")
  3317  			csvNew2 := operatorsv1alpha1.ClusterServiceVersion{
  3318  				TypeMeta: metav1.TypeMeta{
  3319  					Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
  3320  					APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
  3321  				},
  3322  				ObjectMeta: metav1.ObjectMeta{
  3323  					Name: genName("csv3"),
  3324  				},
  3325  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  3326  					Replaces: csvNew.Name,
  3327  					InstallModes: []operatorsv1alpha1.InstallMode{
  3328  						{
  3329  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  3330  							Supported: true,
  3331  						},
  3332  						{
  3333  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  3334  							Supported: true,
  3335  						},
  3336  						{
  3337  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  3338  							Supported: true,
  3339  						},
  3340  						{
  3341  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  3342  							Supported: true,
  3343  						},
  3344  					},
  3345  					InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
  3346  						StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
  3347  						StrategySpec: strategyNew2,
  3348  					},
  3349  					CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{
  3350  						Owned: []operatorsv1alpha1.CRDDescription{
  3351  							{
  3352  								Name:        crdName,
  3353  								Version:     "v1alpha2",
  3354  								Kind:        crdPlural,
  3355  								DisplayName: crdName,
  3356  								Description: "In the cluster4",
  3357  							},
  3358  						},
  3359  					},
  3360  				},
  3361  			}
  3362  
  3363  			By("Create newly updated CSV")
  3364  			cleanupNewCSV, err := createCSV(c, crc, csvNew2, generatedNamespace.GetName(), true, false)
  3365  			Expect(err).ShouldNot(HaveOccurred())
  3366  			defer cleanupNewCSV()
  3367  
  3368  			By("Wait for updated CSV to succeed")
  3369  			fetchedCSV, err = fetchCSV(crc, generatedNamespace.GetName(), csvNew2.Name, csvSucceededChecker)
  3370  			Expect(err).ShouldNot(HaveOccurred())
  3371  
  3372  			By("Fetch cluster service version again to check for unnecessary control loops")
  3373  			sameCSV, err = fetchCSV(crc, generatedNamespace.GetName(), csvNew2.Name, csvSucceededChecker)
  3374  			Expect(err).ShouldNot(HaveOccurred())
  3375  			Expect(equality.Semantic.DeepEqual(fetchedCSV, sameCSV)).Should(BeTrue(), diff.ObjectDiff(fetchedCSV, sameCSV))
  3376  
  3377  			By("Should have created new deployment and deleted old one")
  3378  			depNew, err = c.GetDeployment(generatedNamespace.GetName(), strategyNew2.DeploymentSpecs[0].Name)
  3379  			Expect(err).ShouldNot(HaveOccurred())
  3380  			Expect(depNew).ShouldNot(BeNil())
  3381  			err = waitForDeploymentToDelete(generatedNamespace.GetName(), strategyNew.DeploymentSpecs[0].Name, c)
  3382  			Expect(err).ShouldNot(HaveOccurred())
  3383  
  3384  			By("Should clean up the CSV")
  3385  			err = waitForCsvToDelete(generatedNamespace.GetName(), csvNew.Name, crc)
  3386  			Expect(err).ShouldNot(HaveOccurred())
  3387  		})
  3388  
  3389  		It("update modify deployment name", func() {
  3390  
  3391  			By("Create dependency first (CRD)")
  3392  			crdPlural := genName("ins2")
  3393  			crdName := crdPlural + ".cluster.com"
  3394  			cleanupCRD, err := createCRD(c, apiextensionsv1.CustomResourceDefinition{
  3395  				ObjectMeta: metav1.ObjectMeta{
  3396  					Name: crdName,
  3397  				},
  3398  				Spec: apiextensionsv1.CustomResourceDefinitionSpec{
  3399  					Group: "cluster.com",
  3400  					Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
  3401  						{
  3402  							Name:    "v1alpha1",
  3403  							Served:  true,
  3404  							Storage: true,
  3405  							Schema: &apiextensionsv1.CustomResourceValidation{
  3406  								OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
  3407  									Type:        "object",
  3408  									Description: "my crd schema",
  3409  								},
  3410  							},
  3411  						},
  3412  					},
  3413  					Names: apiextensionsv1.CustomResourceDefinitionNames{
  3414  						Plural:   crdPlural,
  3415  						Singular: crdPlural,
  3416  						Kind:     crdPlural,
  3417  						ListKind: "list" + crdPlural,
  3418  					},
  3419  					Scope: apiextensionsv1.NamespaceScoped,
  3420  				},
  3421  			})
  3422  			Expect(err).ShouldNot(HaveOccurred())
  3423  			defer cleanupCRD()
  3424  
  3425  			By("create current CSV")
  3426  			strategy := operatorsv1alpha1.StrategyDetailsDeployment{
  3427  				DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
  3428  					{
  3429  						Name: genName("dep-"),
  3430  						Spec: newNginxDeployment(genName("nginx-")),
  3431  					},
  3432  					{
  3433  						Name: "dep2-test",
  3434  						Spec: newNginxDeployment("nginx2"),
  3435  					},
  3436  				},
  3437  			}
  3438  
  3439  			Expect(err).ShouldNot(HaveOccurred())
  3440  
  3441  			csv := operatorsv1alpha1.ClusterServiceVersion{
  3442  				TypeMeta: metav1.TypeMeta{
  3443  					Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
  3444  					APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
  3445  				},
  3446  				ObjectMeta: metav1.ObjectMeta{
  3447  					Name: genName("csv"),
  3448  				},
  3449  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  3450  					InstallModes: []operatorsv1alpha1.InstallMode{
  3451  						{
  3452  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  3453  							Supported: true,
  3454  						},
  3455  						{
  3456  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  3457  							Supported: true,
  3458  						},
  3459  						{
  3460  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  3461  							Supported: true,
  3462  						},
  3463  						{
  3464  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  3465  							Supported: true,
  3466  						},
  3467  					},
  3468  					InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
  3469  						StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
  3470  						StrategySpec: strategy,
  3471  					},
  3472  					CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{
  3473  						Owned: []operatorsv1alpha1.CRDDescription{
  3474  							{
  3475  								Name:        crdName,
  3476  								Version:     "v1alpha1",
  3477  								Kind:        crdPlural,
  3478  								DisplayName: crdName,
  3479  								Description: "In the cluster2",
  3480  							},
  3481  						},
  3482  					},
  3483  				},
  3484  			}
  3485  
  3486  			cleanupCSV, err := createCSV(c, crc, csv, generatedNamespace.GetName(), true, false)
  3487  			Expect(err).ShouldNot(HaveOccurred())
  3488  			defer cleanupCSV()
  3489  
  3490  			By("Wait for current CSV to succeed")
  3491  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvSucceededChecker)
  3492  			Expect(err).ShouldNot(HaveOccurred())
  3493  
  3494  			By("Should have created deployments")
  3495  			dep, err := c.GetDeployment(generatedNamespace.GetName(), strategy.DeploymentSpecs[0].Name)
  3496  			Expect(err).ShouldNot(HaveOccurred())
  3497  			Expect(dep).ShouldNot(BeNil())
  3498  			dep2, err := c.GetDeployment(generatedNamespace.GetName(), strategy.DeploymentSpecs[1].Name)
  3499  			Expect(err).ShouldNot(HaveOccurred())
  3500  			Expect(dep2).ShouldNot(BeNil())
  3501  
  3502  			By("Create updated CSV")
  3503  			strategyNew := operatorsv1alpha1.StrategyDetailsDeployment{
  3504  				DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
  3505  					{
  3506  						Name: genName("dep3-"),
  3507  						Spec: newNginxDeployment(genName("nginx3-")),
  3508  					},
  3509  					{
  3510  						Name: "dep2-test",
  3511  						Spec: newNginxDeployment("nginx2"),
  3512  					},
  3513  				},
  3514  			}
  3515  
  3516  			Expect(err).ShouldNot(HaveOccurred())
  3517  
  3518  			By("Fetch the current csv")
  3519  			fetchedCSV, err := fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvSucceededChecker)
  3520  			Expect(err).ShouldNot(HaveOccurred())
  3521  
  3522  			By("Update csv with same strategy with different deployment's name")
  3523  			fetchedCSV.Spec.InstallStrategy.StrategySpec = strategyNew
  3524  
  3525  			By("Update the current csv with the new csv")
  3526  			_, err = crc.OperatorsV1alpha1().ClusterServiceVersions(generatedNamespace.GetName()).Update(context.TODO(), fetchedCSV, metav1.UpdateOptions{})
  3527  			Expect(err).ShouldNot(HaveOccurred())
  3528  
  3529  			By("Wait for new deployment to exist")
  3530  			_, err = waitForDeployment(generatedNamespace.GetName(), strategyNew.DeploymentSpecs[0].Name, c)
  3531  			Expect(err).ShouldNot(HaveOccurred())
  3532  
  3533  			By("Wait for updated CSV to succeed")
  3534  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvSucceededChecker)
  3535  			Expect(err).ShouldNot(HaveOccurred())
  3536  
  3537  			By("Should have created new deployment and deleted old")
  3538  			depNew, err := c.GetDeployment(generatedNamespace.GetName(), strategyNew.DeploymentSpecs[0].Name)
  3539  			Expect(err).ShouldNot(HaveOccurred())
  3540  			Expect(depNew).ShouldNot(BeNil())
  3541  
  3542  			By("Make sure the unchanged deployment still exists")
  3543  			depNew2, err := c.GetDeployment(generatedNamespace.GetName(), strategyNew.DeploymentSpecs[1].Name)
  3544  			Expect(err).ShouldNot(HaveOccurred())
  3545  			Expect(depNew2).ShouldNot(BeNil())
  3546  
  3547  			err = waitForDeploymentToDelete(generatedNamespace.GetName(), strategy.DeploymentSpecs[0].Name, c)
  3548  			Expect(err).ShouldNot(HaveOccurred())
  3549  		})
  3550  		It("update deployment spec in an existing CSV for a hotfix", func() {
  3551  
  3552  			c := newKubeClient()
  3553  			crc := newCRClient()
  3554  
  3555  			By("Creating dependency first (CRD)")
  3556  			crdPlural := genName("ins")
  3557  			crdName := crdPlural + ".cluster.com"
  3558  			cleanupCRD, err := createCRD(c, apiextensionsv1.CustomResourceDefinition{
  3559  				ObjectMeta: metav1.ObjectMeta{
  3560  					Name: crdName,
  3561  				},
  3562  				Spec: apiextensionsv1.CustomResourceDefinitionSpec{
  3563  					Group: "cluster.com",
  3564  					Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
  3565  						{
  3566  							Name:    "v1alpha1",
  3567  							Served:  true,
  3568  							Storage: true,
  3569  							Schema: &apiextensionsv1.CustomResourceValidation{
  3570  								OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
  3571  									Type:        "object",
  3572  									Description: "my crd schema",
  3573  								},
  3574  							},
  3575  						},
  3576  					},
  3577  					Names: apiextensionsv1.CustomResourceDefinitionNames{
  3578  						Plural:   crdPlural,
  3579  						Singular: crdPlural,
  3580  						Kind:     crdPlural,
  3581  						ListKind: "list" + crdPlural,
  3582  					},
  3583  					Scope: apiextensionsv1.NamespaceScoped,
  3584  				},
  3585  			})
  3586  			defer cleanupCRD()
  3587  			Expect(err).ShouldNot(HaveOccurred())
  3588  
  3589  			By("Creating 'current' CSV")
  3590  			nginxName := genName("nginx-")
  3591  			strategy := operatorsv1alpha1.StrategyDetailsDeployment{
  3592  				DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
  3593  					{
  3594  						Name: genName("dep-"),
  3595  						Spec: newNginxDeployment(nginxName),
  3596  					},
  3597  				},
  3598  			}
  3599  
  3600  			csv := operatorsv1alpha1.ClusterServiceVersion{
  3601  				TypeMeta: metav1.TypeMeta{
  3602  					Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
  3603  					APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
  3604  				},
  3605  				ObjectMeta: metav1.ObjectMeta{
  3606  					Name: genName("csv"),
  3607  				},
  3608  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  3609  					MinKubeVersion: "0.0.0",
  3610  					InstallModes: []operatorsv1alpha1.InstallMode{
  3611  						{
  3612  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  3613  							Supported: true,
  3614  						},
  3615  						{
  3616  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  3617  							Supported: true,
  3618  						},
  3619  						{
  3620  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  3621  							Supported: true,
  3622  						},
  3623  						{
  3624  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  3625  							Supported: true,
  3626  						},
  3627  					},
  3628  					InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
  3629  						StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
  3630  						StrategySpec: strategy,
  3631  					},
  3632  					CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{
  3633  						Owned: []operatorsv1alpha1.CRDDescription{
  3634  							{
  3635  								Name:        crdName,
  3636  								Version:     "v1alpha1",
  3637  								Kind:        crdPlural,
  3638  								DisplayName: crdName,
  3639  								Description: "In the cluster",
  3640  							},
  3641  						},
  3642  					},
  3643  				},
  3644  			}
  3645  
  3646  			cleanupCSV, err := createCSV(c, crc, csv, generatedNamespace.GetName(), true, false)
  3647  			Expect(err).ShouldNot(HaveOccurred())
  3648  			defer cleanupCSV()
  3649  
  3650  			By("Waiting for current CSV to succeed")
  3651  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvSucceededChecker)
  3652  			Expect(err).ShouldNot(HaveOccurred())
  3653  
  3654  			By("Waiting for deployment to be created")
  3655  			dep, err := waitForDeployment(generatedNamespace.GetName(), strategy.DeploymentSpecs[0].Name, c)
  3656  			Expect(err).ShouldNot(HaveOccurred())
  3657  			Expect(dep).ShouldNot(BeNil())
  3658  
  3659  			GinkgoT().Logf("Deployment container name: %v", dep.Spec.Template.Spec.Containers[0].Name)
  3660  
  3661  			By("Creating 'updated' CSV with the same name but a different spec")
  3662  			strategyNew := operatorsv1alpha1.StrategyDetailsDeployment{
  3663  				DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
  3664  					{
  3665  						Name: strategy.DeploymentSpecs[0].Name,
  3666  						Spec: newNginxDeployment(nginxName),
  3667  					},
  3668  				},
  3669  			}
  3670  
  3671  			By("Fetching the current csv")
  3672  			fetchedCSV, err := fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvSucceededChecker)
  3673  			Expect(err).ShouldNot(HaveOccurred())
  3674  
  3675  			By("Updating the CSV")
  3676  			fetchedCSV.Spec.InstallStrategy.StrategySpec = strategyNew
  3677  			Eventually(func() error {
  3678  				_, err = crc.OperatorsV1alpha1().ClusterServiceVersions(generatedNamespace.GetName()).Update(context.TODO(), fetchedCSV, metav1.UpdateOptions{})
  3679  				return err
  3680  			}).Should(Succeed())
  3681  
  3682  			By(fmt.Sprintf("Waiting for the updated CSV to succeed with deplpoyment container name: %s", strategyNew.DeploymentSpecs[0].Spec.Template.Spec.Containers[0].Name))
  3683  			nameMatchesPrinted := false
  3684  			Eventually(func() error {
  3685  				_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, func(csv *operatorsv1alpha1.ClusterServiceVersion) bool {
  3686  
  3687  					By("Should have updated existing deployment")
  3688  					depUpdated, err := c.GetDeployment(generatedNamespace.GetName(), strategyNew.DeploymentSpecs[0].Name)
  3689  					if err != nil {
  3690  						GinkgoT().Logf("error getting deployment %s/%s: %v", generatedNamespace.GetName(), strategyNew.DeploymentSpecs[0].Name, err)
  3691  						return false
  3692  					}
  3693  					if depUpdated == nil {
  3694  						return false
  3695  					}
  3696  
  3697  					By("container name has been updated and differs from initial CSV spec and updated CSV spec")
  3698  					if depUpdated.Spec.Template.Spec.Containers[0].Name != strategyNew.DeploymentSpecs[0].Spec.Template.Spec.Containers[0].Name {
  3699  						return false
  3700  					}
  3701  					if !nameMatchesPrinted {
  3702  						GinkgoT().Logf("deployments: dep container name matches: %v", strategyNew.DeploymentSpecs[0].Spec.Template.Spec.Containers[0].Name)
  3703  						nameMatchesPrinted = true
  3704  					}
  3705  
  3706  					By("Check for success")
  3707  					return csvSucceededChecker(csv)
  3708  				})
  3709  				return err
  3710  			}, pollDuration, pollInterval).Should(Succeed())
  3711  		})
  3712  		It("emits CSV requirement events", func() {
  3713  
  3714  			By("Require an API that we know won't exist under our domain")
  3715  			csv := &operatorsv1alpha1.ClusterServiceVersion{
  3716  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  3717  					MinKubeVersion: "0.0.0",
  3718  					InstallModes: []operatorsv1alpha1.InstallMode{
  3719  						{
  3720  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  3721  							Supported: true,
  3722  						},
  3723  						{
  3724  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  3725  							Supported: true,
  3726  						},
  3727  						{
  3728  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  3729  							Supported: true,
  3730  						},
  3731  						{
  3732  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  3733  							Supported: true,
  3734  						},
  3735  					},
  3736  					InstallStrategy: newNginxInstallStrategy(genName("dep-"), nil, nil),
  3737  					APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{
  3738  						Required: []operatorsv1alpha1.APIServiceDescription{
  3739  							{
  3740  								Group:   "bad.packages.operators.coreos.com",
  3741  								Version: "v1",
  3742  								Kind:    "PackageManifest",
  3743  							},
  3744  						},
  3745  					},
  3746  				},
  3747  			}
  3748  			csv.SetNamespace(generatedNamespace.GetName())
  3749  			csv.SetName(genName("csv-"))
  3750  
  3751  			clientCtx := context.Background()
  3752  			listOpts := metav1.ListOptions{
  3753  				FieldSelector: "involvedObject.kind=ClusterServiceVersion",
  3754  			}
  3755  			events, err := c.KubernetesInterface().CoreV1().Events(csv.GetNamespace()).List(clientCtx, listOpts)
  3756  			Expect(err).ToNot(HaveOccurred())
  3757  
  3758  			By("Watch latest events from test namespace for CSV")
  3759  			listOpts.ResourceVersion = events.ResourceVersion
  3760  			w, err := c.KubernetesInterface().CoreV1().Events(generatedNamespace.GetName()).Watch(context.Background(), listOpts)
  3761  			Expect(err).ToNot(HaveOccurred())
  3762  			defer w.Stop()
  3763  
  3764  			cleanupCSV, err := createCSV(c, crc, *csv, csv.GetNamespace(), false, false)
  3765  			Expect(err).ToNot(HaveOccurred())
  3766  			defer cleanupCSV()
  3767  
  3768  			By("emitting when requirements are not met")
  3769  			nextReason := func() string {
  3770  				if e := <-w.ResultChan(); e.Object != nil {
  3771  					return e.Object.(*corev1.Event).Reason
  3772  				}
  3773  				return ""
  3774  			}
  3775  			Eventually(nextReason).Should(Equal("RequirementsNotMet"))
  3776  
  3777  			By("Patch the CSV to require an API that we know exists")
  3778  			Eventually(ctx.Ctx().SSAClient().Apply(clientCtx, csv, func(c *operatorsv1alpha1.ClusterServiceVersion) error {
  3779  				c.Spec.APIServiceDefinitions.Required[0].Group = "packages.operators.coreos.com"
  3780  				return nil
  3781  			})).Should(Succeed())
  3782  
  3783  			By("emitting when requirements are met")
  3784  			Eventually(nextReason).Should(Equal("AllRequirementsMet"))
  3785  		})
  3786  
  3787  		// TODO: test behavior when replaces field doesn't point to existing CSV
  3788  		It("status invalid CSV", func() {
  3789  
  3790  			By("Create CRD")
  3791  			crdPlural := genName("ins")
  3792  			crdName := crdPlural + ".cluster.com"
  3793  			cleanupCRD, err := createCRD(c, apiextensionsv1.CustomResourceDefinition{
  3794  				ObjectMeta: metav1.ObjectMeta{
  3795  					Name: crdName,
  3796  				},
  3797  				Spec: apiextensionsv1.CustomResourceDefinitionSpec{
  3798  					Group: "cluster.com",
  3799  					Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
  3800  						{
  3801  							Name:    "v1alpha1",
  3802  							Served:  true,
  3803  							Storage: true,
  3804  							Schema: &apiextensionsv1.CustomResourceValidation{
  3805  								OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
  3806  									Type:        "object",
  3807  									Description: "my crd schema",
  3808  								},
  3809  							},
  3810  						},
  3811  					},
  3812  					Names: apiextensionsv1.CustomResourceDefinitionNames{
  3813  						Plural:   crdPlural,
  3814  						Singular: crdPlural,
  3815  						Kind:     crdPlural,
  3816  						ListKind: "list" + crdPlural,
  3817  					},
  3818  					Scope: apiextensionsv1.NamespaceScoped,
  3819  				},
  3820  			})
  3821  			Expect(err).ShouldNot(HaveOccurred())
  3822  			defer cleanupCRD()
  3823  
  3824  			By("create CSV")
  3825  			strategy := operatorsv1alpha1.StrategyDetailsDeployment{
  3826  				DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
  3827  					{
  3828  						Name: genName("dep-"),
  3829  						Spec: newNginxDeployment(genName("nginx-")),
  3830  					},
  3831  				},
  3832  			}
  3833  			Expect(err).ShouldNot(HaveOccurred())
  3834  
  3835  			csv := operatorsv1alpha1.ClusterServiceVersion{
  3836  				TypeMeta: metav1.TypeMeta{
  3837  					Kind:       operatorsv1alpha1.ClusterServiceVersionKind,
  3838  					APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion,
  3839  				},
  3840  				ObjectMeta: metav1.ObjectMeta{
  3841  					Name: genName("csv"),
  3842  				},
  3843  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  3844  					InstallModes: []operatorsv1alpha1.InstallMode{
  3845  						{
  3846  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  3847  							Supported: true,
  3848  						},
  3849  						{
  3850  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  3851  							Supported: true,
  3852  						},
  3853  						{
  3854  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  3855  							Supported: true,
  3856  						},
  3857  						{
  3858  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  3859  							Supported: true,
  3860  						},
  3861  					},
  3862  					InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
  3863  						StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
  3864  						StrategySpec: strategy,
  3865  					},
  3866  					CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{
  3867  						Owned: []operatorsv1alpha1.CRDDescription{
  3868  							{
  3869  								Name:        crdName,
  3870  								Version:     "apiextensions.k8s.io/v1alpha1", // purposely invalid, should be just v1alpha1 to match CRD
  3871  								Kind:        crdPlural,
  3872  								DisplayName: crdName,
  3873  								Description: "In the cluster2",
  3874  							},
  3875  						},
  3876  					},
  3877  				},
  3878  			}
  3879  
  3880  			cleanupCSV, err := createCSV(c, crc, csv, generatedNamespace.GetName(), true, false)
  3881  			Expect(err).ShouldNot(HaveOccurred())
  3882  			defer cleanupCSV()
  3883  
  3884  			notServedStatus := operatorsv1alpha1.RequirementStatus{
  3885  				Group:   "apiextensions.k8s.io",
  3886  				Version: "v1",
  3887  				Kind:    "CustomResourceDefinition",
  3888  				Name:    crdName,
  3889  				Status:  operatorsv1alpha1.RequirementStatusReasonNotPresent,
  3890  				Message: "CRD version not served",
  3891  			}
  3892  			csvCheckPhaseAndRequirementStatus := func(csv *operatorsv1alpha1.ClusterServiceVersion) bool {
  3893  				if csv.Status.Phase == operatorsv1alpha1.CSVPhasePending {
  3894  					for _, status := range csv.Status.RequirementStatus {
  3895  						if status.Message == notServedStatus.Message {
  3896  							return true
  3897  						}
  3898  					}
  3899  				}
  3900  				return false
  3901  			}
  3902  
  3903  			fetchedCSV, err := fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvCheckPhaseAndRequirementStatus)
  3904  			Expect(err).ShouldNot(HaveOccurred())
  3905  
  3906  			Expect(fetchedCSV.Status.RequirementStatus).Should(ContainElement(notServedStatus))
  3907  		})
  3908  
  3909  		It("api service resource migrated if adoptable", func() {
  3910  
  3911  			depName := genName("hat-server")
  3912  			mockGroup := fmt.Sprintf("hats.%s.redhat.com", genName(""))
  3913  			version := "v1alpha1"
  3914  			mockGroupVersion := strings.Join([]string{mockGroup, version}, "/")
  3915  			mockKinds := []string{"fedora"}
  3916  			depSpec := newMockExtServerDeployment(depName, []mockGroupVersionKind{{depName, mockGroupVersion, mockKinds, 5443}})
  3917  			apiServiceName := strings.Join([]string{version, mockGroup}, ".")
  3918  
  3919  			By("Create CSVs for the hat-server")
  3920  			strategy := operatorsv1alpha1.StrategyDetailsDeployment{
  3921  				DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
  3922  					{
  3923  						Name: depName,
  3924  						Spec: depSpec,
  3925  					},
  3926  				},
  3927  			}
  3928  
  3929  			owned := make([]operatorsv1alpha1.APIServiceDescription, len(mockKinds))
  3930  			for i, kind := range mockKinds {
  3931  				owned[i] = operatorsv1alpha1.APIServiceDescription{
  3932  					Name:           apiServiceName,
  3933  					Group:          mockGroup,
  3934  					Version:        version,
  3935  					Kind:           kind,
  3936  					DeploymentName: depName,
  3937  					ContainerPort:  int32(5443),
  3938  					DisplayName:    kind,
  3939  					Description:    fmt.Sprintf("A %s", kind),
  3940  				}
  3941  			}
  3942  
  3943  			csv := operatorsv1alpha1.ClusterServiceVersion{
  3944  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  3945  					MinKubeVersion: "0.0.0",
  3946  					InstallModes: []operatorsv1alpha1.InstallMode{
  3947  						{
  3948  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  3949  							Supported: true,
  3950  						},
  3951  						{
  3952  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  3953  							Supported: true,
  3954  						},
  3955  						{
  3956  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  3957  							Supported: true,
  3958  						},
  3959  						{
  3960  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  3961  							Supported: true,
  3962  						},
  3963  					},
  3964  					InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
  3965  						StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
  3966  						StrategySpec: strategy,
  3967  					},
  3968  					APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{
  3969  						Owned: owned,
  3970  					},
  3971  				},
  3972  			}
  3973  			csv.SetName("csv-hat-1")
  3974  			csv.SetNamespace(generatedNamespace.GetName())
  3975  
  3976  			createLegacyAPIResources(generatedNamespace.GetName(), &csv, owned[0], c)
  3977  
  3978  			By("Create the APIService CSV")
  3979  			cleanupCSV, err := createCSV(c, crc, csv, generatedNamespace.GetName(), false, false)
  3980  			Expect(err).ShouldNot(HaveOccurred())
  3981  			defer cleanupCSV()
  3982  
  3983  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvSucceededChecker)
  3984  			Expect(err).ShouldNot(HaveOccurred())
  3985  
  3986  			checkLegacyAPIResources(generatedNamespace.GetName(), owned[0], true, c)
  3987  		})
  3988  
  3989  		It("API service resource not migrated if not adoptable", func() {
  3990  
  3991  			depName := genName("hat-server")
  3992  			mockGroup := fmt.Sprintf("hats.%s.redhat.com", genName(""))
  3993  			version := "v1alpha1"
  3994  			mockGroupVersion := strings.Join([]string{mockGroup, version}, "/")
  3995  			mockKinds := []string{"fedora"}
  3996  			depSpec := newMockExtServerDeployment(depName, []mockGroupVersionKind{{depName, mockGroupVersion, mockKinds, 5443}})
  3997  			apiServiceName := strings.Join([]string{version, mockGroup}, ".")
  3998  
  3999  			By("Create CSVs for the hat-server")
  4000  			strategy := operatorsv1alpha1.StrategyDetailsDeployment{
  4001  				DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
  4002  					{
  4003  						Name: depName,
  4004  						Spec: depSpec,
  4005  					},
  4006  				},
  4007  			}
  4008  
  4009  			owned := make([]operatorsv1alpha1.APIServiceDescription, len(mockKinds))
  4010  			for i, kind := range mockKinds {
  4011  				owned[i] = operatorsv1alpha1.APIServiceDescription{
  4012  					Name:           apiServiceName,
  4013  					Group:          mockGroup,
  4014  					Version:        version,
  4015  					Kind:           kind,
  4016  					DeploymentName: depName,
  4017  					ContainerPort:  int32(5443),
  4018  					DisplayName:    kind,
  4019  					Description:    fmt.Sprintf("A %s", kind),
  4020  				}
  4021  			}
  4022  
  4023  			csv := operatorsv1alpha1.ClusterServiceVersion{
  4024  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  4025  					MinKubeVersion: "0.0.0",
  4026  					InstallModes: []operatorsv1alpha1.InstallMode{
  4027  						{
  4028  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  4029  							Supported: true,
  4030  						},
  4031  						{
  4032  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  4033  							Supported: true,
  4034  						},
  4035  						{
  4036  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  4037  							Supported: true,
  4038  						},
  4039  						{
  4040  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  4041  							Supported: true,
  4042  						},
  4043  					},
  4044  					InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
  4045  						StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
  4046  						StrategySpec: strategy,
  4047  					},
  4048  					APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{
  4049  						Owned: owned,
  4050  					},
  4051  				},
  4052  			}
  4053  			csv.SetName("csv-hat-1")
  4054  			csv.SetNamespace(generatedNamespace.GetName())
  4055  
  4056  			createLegacyAPIResources(generatedNamespace.GetName(), nil, owned[0], c)
  4057  
  4058  			By("Create the APIService CSV")
  4059  			cleanupCSV, err := createCSV(c, crc, csv, generatedNamespace.GetName(), false, false)
  4060  			Expect(err).ShouldNot(HaveOccurred())
  4061  			defer cleanupCSV()
  4062  
  4063  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvSucceededChecker)
  4064  			Expect(err).ShouldNot(HaveOccurred())
  4065  
  4066  			checkLegacyAPIResources(generatedNamespace.GetName(), owned[0], false, c)
  4067  
  4068  			By("Cleanup the resources created for this test that were not cleaned up.")
  4069  			deleteLegacyAPIResources(generatedNamespace.GetName(), owned[0], c)
  4070  		})
  4071  
  4072  		It("multiple API services on a single pod", func() {
  4073  
  4074  			By("Create the deployment that both APIServices will be deployed to.")
  4075  			depName := genName("hat-server")
  4076  
  4077  			By("Define the expected mock APIService settings.")
  4078  			version := "v1alpha1"
  4079  			apiService1Group := fmt.Sprintf("hats.%s.redhat.com", genName(""))
  4080  			apiService1GroupVersion := strings.Join([]string{apiService1Group, version}, "/")
  4081  			apiService1Kinds := []string{"fedora"}
  4082  			apiService1Name := strings.Join([]string{version, apiService1Group}, ".")
  4083  
  4084  			apiService2Group := fmt.Sprintf("hats.%s.redhat.com", genName(""))
  4085  			apiService2GroupVersion := strings.Join([]string{apiService2Group, version}, "/")
  4086  			apiService2Kinds := []string{"fez"}
  4087  			apiService2Name := strings.Join([]string{version, apiService2Group}, ".")
  4088  
  4089  			By("Create the deployment spec with the two APIServices.")
  4090  			mockGroupVersionKinds := []mockGroupVersionKind{
  4091  				{
  4092  					depName,
  4093  					apiService1GroupVersion,
  4094  					apiService1Kinds,
  4095  					5443,
  4096  				},
  4097  				{
  4098  					depName,
  4099  					apiService2GroupVersion,
  4100  					apiService2Kinds,
  4101  					5444,
  4102  				},
  4103  			}
  4104  			depSpec := newMockExtServerDeployment(depName, mockGroupVersionKinds)
  4105  
  4106  			By("Create the CSV.")
  4107  			strategy := operatorsv1alpha1.StrategyDetailsDeployment{
  4108  				DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{
  4109  					{
  4110  						Name: depName,
  4111  						Spec: depSpec,
  4112  					},
  4113  				},
  4114  			}
  4115  
  4116  			By("Update the owned APIServices two include the two APIServices.")
  4117  			owned := []operatorsv1alpha1.APIServiceDescription{
  4118  				{
  4119  					Name:           apiService1Name,
  4120  					Group:          apiService1Group,
  4121  					Version:        version,
  4122  					Kind:           apiService1Kinds[0],
  4123  					DeploymentName: depName,
  4124  					ContainerPort:  int32(5443),
  4125  					DisplayName:    apiService1Kinds[0],
  4126  					Description:    fmt.Sprintf("A %s", apiService1Kinds[0]),
  4127  				},
  4128  				{
  4129  					Name:           apiService2Name,
  4130  					Group:          apiService2Group,
  4131  					Version:        version,
  4132  					Kind:           apiService2Kinds[0],
  4133  					DeploymentName: depName,
  4134  					ContainerPort:  int32(5444),
  4135  					DisplayName:    apiService2Kinds[0],
  4136  					Description:    fmt.Sprintf("A %s", apiService2Kinds[0]),
  4137  				},
  4138  			}
  4139  
  4140  			csv := operatorsv1alpha1.ClusterServiceVersion{
  4141  				Spec: operatorsv1alpha1.ClusterServiceVersionSpec{
  4142  					MinKubeVersion: "0.0.0",
  4143  					InstallModes: []operatorsv1alpha1.InstallMode{
  4144  						{
  4145  							Type:      operatorsv1alpha1.InstallModeTypeOwnNamespace,
  4146  							Supported: true,
  4147  						},
  4148  						{
  4149  							Type:      operatorsv1alpha1.InstallModeTypeSingleNamespace,
  4150  							Supported: true,
  4151  						},
  4152  						{
  4153  							Type:      operatorsv1alpha1.InstallModeTypeMultiNamespace,
  4154  							Supported: true,
  4155  						},
  4156  						{
  4157  							Type:      operatorsv1alpha1.InstallModeTypeAllNamespaces,
  4158  							Supported: true,
  4159  						},
  4160  					},
  4161  					InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{
  4162  						StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment,
  4163  						StrategySpec: strategy,
  4164  					},
  4165  					APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{
  4166  						Owned: owned,
  4167  					},
  4168  				},
  4169  			}
  4170  			csv.SetName("csv-hat-1")
  4171  			csv.SetNamespace(generatedNamespace.GetName())
  4172  
  4173  			By("Create the APIService CSV")
  4174  			cleanupCSV, err := createCSV(c, crc, csv, generatedNamespace.GetName(), false, false)
  4175  			Expect(err).ShouldNot(HaveOccurred())
  4176  			defer cleanupCSV()
  4177  
  4178  			_, err = fetchCSV(crc, generatedNamespace.GetName(), csv.Name, csvSucceededChecker)
  4179  			Expect(err).ShouldNot(HaveOccurred())
  4180  
  4181  			By("Check that the APIService caBundles are equal")
  4182  			apiService1, err := c.GetAPIService(apiService1Name)
  4183  			Expect(err).ShouldNot(HaveOccurred())
  4184  
  4185  			apiService2, err := c.GetAPIService(apiService2Name)
  4186  			Expect(err).ShouldNot(HaveOccurred())
  4187  
  4188  			Expect(apiService2.Spec.CABundle).Should(Equal(apiService1.Spec.CABundle))
  4189  		})
  4190  	})
  4191  })
  4192  
  4193  var singleInstance = int32(1)
  4194  
  4195  var immediateDeleteGracePeriod int64 = 0
  4196  
  4197  func findLastEvent(events *corev1.EventList) (event corev1.Event) {
  4198  	var latestTime metav1.Time
  4199  	var latestInd int
  4200  	for i, item := range events.Items {
  4201  		if i != 0 {
  4202  			if latestTime.Before(&item.LastTimestamp) {
  4203  				latestTime = item.LastTimestamp
  4204  				latestInd = i
  4205  			}
  4206  		} else {
  4207  			latestTime = item.LastTimestamp
  4208  		}
  4209  	}
  4210  	return events.Items[latestInd]
  4211  }
  4212  
  4213  func buildCSVCleanupFunc(c operatorclient.ClientInterface, crc versioned.Interface, csv operatorsv1alpha1.ClusterServiceVersion, namespace string, deleteCRDs, deleteAPIServices bool) cleanupFunc {
  4214  	return func() {
  4215  		if env := os.Getenv("SKIP_CLEANUP"); env != "" {
  4216  			fmt.Printf("Skipping deletion of CSV %s/%s...\n", namespace, csv.Name)
  4217  			return
  4218  		}
  4219  
  4220  		err := crc.OperatorsV1alpha1().ClusterServiceVersions(namespace).Delete(context.TODO(), csv.GetName(), metav1.DeleteOptions{})
  4221  		if err != nil && apierrors.IsNotFound(err) {
  4222  			err = nil
  4223  		}
  4224  		Expect(err).ShouldNot(HaveOccurred())
  4225  
  4226  		if deleteCRDs {
  4227  			for _, crd := range csv.Spec.CustomResourceDefinitions.Owned {
  4228  				buildCRDCleanupFunc(c, crd.Name)()
  4229  			}
  4230  		}
  4231  
  4232  		if deleteAPIServices {
  4233  			for _, desc := range csv.GetOwnedAPIServiceDescriptions() {
  4234  				buildAPIServiceCleanupFunc(c, desc.Name)()
  4235  			}
  4236  		}
  4237  
  4238  		err = waitForDelete(func() error {
  4239  			_, err := crc.OperatorsV1alpha1().ClusterServiceVersions(namespace).Get(context.TODO(), csv.GetName(), metav1.GetOptions{})
  4240  			return err
  4241  		})
  4242  		Expect(err).ShouldNot(HaveOccurred())
  4243  	}
  4244  }
  4245  
  4246  func getPointer(b bool) *bool {
  4247  	return &b
  4248  }
  4249  
  4250  func createCSV(c operatorclient.ClientInterface, crc versioned.Interface, csv operatorsv1alpha1.ClusterServiceVersion, namespace string, cleanupCRDs, cleanupAPIServices bool) (cleanupFunc, error) {
  4251  	csv.Kind = operatorsv1alpha1.ClusterServiceVersionKind
  4252  	csv.APIVersion = operatorsv1alpha1.SchemeGroupVersion.String()
  4253  	Eventually(func() error {
  4254  		_, err := crc.OperatorsV1alpha1().ClusterServiceVersions(namespace).Create(context.TODO(), &csv, metav1.CreateOptions{})
  4255  		return err
  4256  	}).Should(Succeed())
  4257  
  4258  	return buildCSVCleanupFunc(c, crc, csv, namespace, cleanupCRDs, cleanupAPIServices), nil
  4259  }
  4260  
  4261  func buildCRDCleanupFunc(c operatorclient.ClientInterface, crdName string) cleanupFunc {
  4262  	return func() {
  4263  		if env := os.Getenv("SKIP_CLEANUP"); env != "" {
  4264  			fmt.Printf("Skipping deletion of CRD %s...\n", crdName)
  4265  			return
  4266  		}
  4267  
  4268  		err := c.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.TODO(), crdName, *metav1.NewDeleteOptions(immediateDeleteGracePeriod))
  4269  		if err != nil {
  4270  			fmt.Println(err)
  4271  		}
  4272  
  4273  		waitForDelete(func() error {
  4274  			_, err := c.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), crdName, metav1.GetOptions{})
  4275  			return err
  4276  		})
  4277  	}
  4278  }
  4279  
  4280  func buildAPIServiceCleanupFunc(c operatorclient.ClientInterface, apiServiceName string) cleanupFunc {
  4281  	return func() {
  4282  		if env := os.Getenv("SKIP_CLEANUP"); env != "" {
  4283  			fmt.Printf("Skipping deletion of APIService %s...\n", apiServiceName)
  4284  			return
  4285  		}
  4286  
  4287  		err := c.ApiregistrationV1Interface().ApiregistrationV1().APIServices().Delete(context.TODO(), apiServiceName, *metav1.NewDeleteOptions(immediateDeleteGracePeriod))
  4288  		if err != nil {
  4289  			fmt.Println(err)
  4290  		}
  4291  
  4292  		waitForDelete(func() error {
  4293  			_, err := c.ApiregistrationV1Interface().ApiregistrationV1().APIServices().Get(context.TODO(), apiServiceName, metav1.GetOptions{})
  4294  			return err
  4295  		})
  4296  	}
  4297  }
  4298  
  4299  func createCRD(c operatorclient.ClientInterface, crd apiextensionsv1.CustomResourceDefinition) (cleanupFunc, error) {
  4300  	_, err := c.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Create(context.TODO(), &crd, metav1.CreateOptions{})
  4301  	if err != nil {
  4302  		return nil, err
  4303  	}
  4304  
  4305  	return buildCRDCleanupFunc(c, crd.GetName()), nil
  4306  }
  4307  
  4308  func newNginxDeployment(name string) appsv1.DeploymentSpec {
  4309  	return appsv1.DeploymentSpec{
  4310  		Selector: &metav1.LabelSelector{
  4311  			MatchLabels: map[string]string{
  4312  				"app": name,
  4313  			},
  4314  		},
  4315  		Replicas: &singleInstance,
  4316  		Template: corev1.PodTemplateSpec{
  4317  			ObjectMeta: metav1.ObjectMeta{
  4318  				Labels: map[string]string{
  4319  					"app": name,
  4320  				},
  4321  			},
  4322  			Spec: corev1.PodSpec{
  4323  				Containers: []corev1.Container{
  4324  					{
  4325  						Name:  genName("nginx"),
  4326  						Image: *dummyImage,
  4327  						Ports: []corev1.ContainerPort{
  4328  							{
  4329  								ContainerPort: 80,
  4330  							},
  4331  						},
  4332  						ImagePullPolicy: corev1.PullIfNotPresent,
  4333  					},
  4334  				},
  4335  			},
  4336  		},
  4337  	}
  4338  }
  4339  
  4340  type mockGroupVersionKind struct {
  4341  	Name             string
  4342  	MockGroupVersion string
  4343  	MockKinds        []string
  4344  	Port             int
  4345  }
  4346  
  4347  func newMockExtServerDeployment(labelName string, mGVKs []mockGroupVersionKind) appsv1.DeploymentSpec {
  4348  	// Create the list of containers
  4349  	containers := []corev1.Container{}
  4350  	for _, mGVK := range mGVKs {
  4351  		containers = append(containers, corev1.Container{
  4352  			Name:    genName(mGVK.Name),
  4353  			Image:   "quay.io/operator-framework/mock-extension-apiserver:master",
  4354  			Command: []string{"/bin/mock-extension-apiserver"},
  4355  			Args: []string{
  4356  				"-v=4",
  4357  				"--mock-kinds",
  4358  				strings.Join(mGVK.MockKinds, ","),
  4359  				"--mock-group-version",
  4360  				mGVK.MockGroupVersion,
  4361  				"--secure-port",
  4362  				strconv.Itoa(mGVK.Port),
  4363  				"--debug",
  4364  			},
  4365  			Ports: []corev1.ContainerPort{
  4366  				{
  4367  					ContainerPort: int32(mGVK.Port),
  4368  				},
  4369  			},
  4370  			ImagePullPolicy: corev1.PullIfNotPresent,
  4371  		})
  4372  	}
  4373  	return appsv1.DeploymentSpec{
  4374  		Selector: &metav1.LabelSelector{
  4375  			MatchLabels: map[string]string{
  4376  				"app": labelName,
  4377  			},
  4378  		},
  4379  		Replicas: &singleInstance,
  4380  		Template: corev1.PodTemplateSpec{
  4381  			ObjectMeta: metav1.ObjectMeta{
  4382  				Labels: map[string]string{
  4383  					"app": labelName,
  4384  				},
  4385  			},
  4386  			Spec: corev1.PodSpec{
  4387  				Containers: containers,
  4388  			},
  4389  		},
  4390  	}
  4391  }
  4392  
  4393  type csvConditionChecker func(csv *operatorsv1alpha1.ClusterServiceVersion) bool
  4394  
  4395  func buildCSVConditionChecker(phases ...operatorsv1alpha1.ClusterServiceVersionPhase) csvConditionChecker {
  4396  	var lastPhase operatorsv1alpha1.ClusterServiceVersionPhase
  4397  	var lastReason operatorsv1alpha1.ConditionReason
  4398  	var lastMessage string
  4399  	lastTime := time.Now()
  4400  
  4401  	return func(csv *operatorsv1alpha1.ClusterServiceVersion) bool {
  4402  		conditionMet := false
  4403  		for _, phase := range phases {
  4404  			conditionMet = conditionMet || csv.Status.Phase == phase
  4405  		}
  4406  		phase, reason, message := csv.Status.Phase, csv.Status.Reason, csv.Status.Message
  4407  		if phase != lastPhase || reason != lastReason || message != lastMessage {
  4408  			ctx.Ctx().Logf("waited %s for CSV %s/%s: to be in phases %s, in phase %s (%s): %s", time.Since(lastTime), csv.Namespace, csv.Name, phases, phase, reason, message)
  4409  			lastPhase, lastReason, lastMessage = phase, reason, message
  4410  			lastTime = time.Now()
  4411  		}
  4412  		return conditionMet
  4413  	}
  4414  }
  4415  
  4416  func buildCSVReasonChecker(reasons ...operatorsv1alpha1.ConditionReason) csvConditionChecker {
  4417  	var lastPhase operatorsv1alpha1.ClusterServiceVersionPhase
  4418  	var lastReason operatorsv1alpha1.ConditionReason
  4419  	var lastMessage string
  4420  	lastTime := time.Now()
  4421  
  4422  	return func(csv *operatorsv1alpha1.ClusterServiceVersion) bool {
  4423  		conditionMet := false
  4424  		for _, reason := range reasons {
  4425  			conditionMet = conditionMet || csv.Status.Reason == reason
  4426  		}
  4427  		phase, reason, message := csv.Status.Phase, csv.Status.Reason, csv.Status.Message
  4428  		if phase != lastPhase || reason != lastReason || message != lastMessage {
  4429  			ctx.Ctx().Logf("waited %s for CSV %s/%s: to have reasons %s, in phase %s (%s): %s", time.Since(lastTime), csv.Namespace, csv.Name, reasons, phase, reason, message)
  4430  			lastPhase, lastReason, lastMessage = phase, reason, message
  4431  			lastTime = time.Now()
  4432  		}
  4433  		return conditionMet
  4434  	}
  4435  }
  4436  
  4437  var csvPendingChecker = buildCSVConditionChecker(operatorsv1alpha1.CSVPhasePending)
  4438  var csvSucceededChecker = buildCSVConditionChecker(operatorsv1alpha1.CSVPhaseSucceeded)
  4439  var csvReplacingChecker = buildCSVConditionChecker(operatorsv1alpha1.CSVPhaseReplacing, operatorsv1alpha1.CSVPhaseDeleting)
  4440  var csvFailedChecker = buildCSVConditionChecker(operatorsv1alpha1.CSVPhaseFailed)
  4441  var csvAnyChecker = buildCSVConditionChecker(operatorsv1alpha1.CSVPhasePending, operatorsv1alpha1.CSVPhaseSucceeded, operatorsv1alpha1.CSVPhaseReplacing, operatorsv1alpha1.CSVPhaseDeleting, operatorsv1alpha1.CSVPhaseFailed)
  4442  var csvCopiedChecker = buildCSVReasonChecker(operatorsv1alpha1.CSVReasonCopied)
  4443  
  4444  func fetchCSV(c versioned.Interface, namespace, name string, checker csvConditionChecker) (*operatorsv1alpha1.ClusterServiceVersion, error) {
  4445  	var lastPhase operatorsv1alpha1.ClusterServiceVersionPhase
  4446  	var lastReason operatorsv1alpha1.ConditionReason
  4447  	var lastMessage string
  4448  	var lastError string
  4449  	lastTime := time.Now()
  4450  	var csv *operatorsv1alpha1.ClusterServiceVersion
  4451  
  4452  	ctx.Ctx().Logf("waiting for CSV %s/%s to reach condition", namespace, name)
  4453  	err := wait.Poll(pollInterval, pollDuration, func() (bool, error) {
  4454  		var err error
  4455  		csv, err = c.OperatorsV1alpha1().ClusterServiceVersions(namespace).Get(context.TODO(), name, metav1.GetOptions{})
  4456  		if err != nil || csv == nil {
  4457  			if lastError != err.Error() {
  4458  				ctx.Ctx().Logf("error getting csv %s/%s: %v", namespace, name, err)
  4459  				lastError = err.Error()
  4460  			}
  4461  			return false, nil
  4462  		}
  4463  		phase, reason, message := csv.Status.Phase, csv.Status.Reason, csv.Status.Message
  4464  		if phase != lastPhase || reason != lastReason || message != lastMessage {
  4465  			ctx.Ctx().Logf("waited %s for csv %s/%s - %s (%s): %s", time.Since(lastTime), namespace, name, phase, reason, message)
  4466  			lastPhase, lastReason, lastMessage = phase, reason, message
  4467  			lastTime = time.Now()
  4468  		}
  4469  		return checker(csv), nil
  4470  	})
  4471  
  4472  	// Only want to return `csv` if there was no (timeout) error
  4473  	if err == nil {
  4474  		return csv, nil
  4475  	}
  4476  	return nil, err
  4477  }
  4478  
  4479  func waitForDeployment(namespace, name string, c operatorclient.ClientInterface) (*appsv1.Deployment, error) {
  4480  	var fetched *appsv1.Deployment
  4481  
  4482  	ctx.Ctx().Logf("waiting for deployment %s/%s to be created", namespace, name)
  4483  	err := wait.Poll(pollInterval, pollDuration, func() (bool, error) {
  4484  		var err error
  4485  		fetched, err = c.GetDeployment(namespace, name)
  4486  		if err != nil {
  4487  			ctx.Ctx().Logf("error getting deployment %s/%s: %v", namespace, name, err)
  4488  			return false, nil
  4489  		}
  4490  		return true, nil
  4491  	})
  4492  
  4493  	return fetched, err
  4494  }
  4495  
  4496  func waitForDeploymentToDelete(namespace, name string, c operatorclient.ClientInterface) error {
  4497  	var lastReplicas, lastUpdated, lastReady, lastAvailable, lastUnavailable int32
  4498  	lastTime := time.Now()
  4499  
  4500  	ctx.Ctx().Logf("waiting for deployment %s/%s to delete", namespace, name)
  4501  	err := wait.Poll(pollInterval, pollDuration, func() (bool, error) {
  4502  		dep, err := c.GetDeployment(namespace, name)
  4503  		if apierrors.IsNotFound(err) {
  4504  			ctx.Ctx().Logf("deployment %s/%s deleted", namespace, name)
  4505  			return true, nil
  4506  		}
  4507  		if err != nil {
  4508  			ctx.Ctx().Logf("error getting deployment %s/%s: %v", namespace, name, err)
  4509  		}
  4510  		if dep != nil {
  4511  			replicas, updated, ready, available, unavailable := dep.Status.Replicas, dep.Status.UpdatedReplicas, dep.Status.ReadyReplicas, dep.Status.AvailableReplicas, dep.Status.UnavailableReplicas
  4512  			if replicas != lastReplicas || updated != lastUpdated || ready != lastReady || available != lastAvailable || unavailable != lastUnavailable {
  4513  				ctx.Ctx().Logf("waited %s for deployment %s/%s status: rep: %v upd: %v rdy: %v ava: %v una: %v", time.Since(lastTime), replicas, updated, ready, available, unavailable)
  4514  				lastReplicas, lastUpdated, lastReady, lastAvailable, lastUnavailable = replicas, updated, ready, available, unavailable
  4515  				lastTime = time.Now()
  4516  			}
  4517  		}
  4518  		return false, nil
  4519  	})
  4520  
  4521  	return err
  4522  }
  4523  
  4524  func waitForCsvToDelete(namespace, name string, c versioned.Interface) error {
  4525  	var lastPhase operatorsv1alpha1.ClusterServiceVersionPhase
  4526  	var lastReason operatorsv1alpha1.ConditionReason
  4527  	var lastMessage string
  4528  	lastTime := time.Now()
  4529  
  4530  	ctx.Ctx().Logf("waiting for csv %s/%s to delete", namespace, name)
  4531  	err := wait.Poll(pollInterval, pollDuration, func() (bool, error) {
  4532  		csv, err := c.OperatorsV1alpha1().ClusterServiceVersions(namespace).Get(context.TODO(), name, metav1.GetOptions{})
  4533  		if apierrors.IsNotFound(err) {
  4534  			ctx.Ctx().Logf("csv %s/%s deleted", namespace, name)
  4535  			return true, nil
  4536  		}
  4537  		if err != nil {
  4538  			ctx.Ctx().Logf("error getting csv %s/%s: %v", namespace, name, err)
  4539  		}
  4540  		if csv != nil {
  4541  			phase, reason, message := csv.Status.Phase, csv.Status.Reason, csv.Status.Message
  4542  			if phase != lastPhase || reason != lastReason || message != lastMessage {
  4543  				ctx.Ctx().Logf("waited %s for csv %s/%s status: %s (%s): %s", time.Since(lastTime), namespace, name, phase, reason, message)
  4544  				lastPhase, lastReason, lastMessage = phase, reason, message
  4545  				lastTime = time.Now()
  4546  			}
  4547  		}
  4548  		return false, nil
  4549  	})
  4550  
  4551  	return err
  4552  }
  4553  
  4554  func deleteLegacyAPIResources(namespace string, desc operatorsv1alpha1.APIServiceDescription, c operatorclient.ClientInterface) {
  4555  	apiServiceName := fmt.Sprintf("%s.%s", desc.Version, desc.Group)
  4556  
  4557  	err := c.DeleteService(namespace, strings.Replace(apiServiceName, ".", "-", -1), &metav1.DeleteOptions{})
  4558  	Expect(err).ShouldNot(HaveOccurred())
  4559  
  4560  	err = c.DeleteSecret(namespace, apiServiceName+"-cert", &metav1.DeleteOptions{})
  4561  	Expect(err).ShouldNot(HaveOccurred())
  4562  
  4563  	err = c.DeleteRole(namespace, apiServiceName+"-cert", &metav1.DeleteOptions{})
  4564  	Expect(err).ShouldNot(HaveOccurred())
  4565  
  4566  	err = c.DeleteRoleBinding(namespace, apiServiceName+"-cert", &metav1.DeleteOptions{})
  4567  	Expect(err).ShouldNot(HaveOccurred())
  4568  
  4569  	err = c.DeleteClusterRoleBinding(apiServiceName+"-system:auth-delegator", &metav1.DeleteOptions{})
  4570  	Expect(err).ShouldNot(HaveOccurred())
  4571  
  4572  	err = c.DeleteRoleBinding("kube-system", apiServiceName+"-auth-reader", &metav1.DeleteOptions{})
  4573  	Expect(err).ShouldNot(HaveOccurred())
  4574  }
  4575  
  4576  func createLegacyAPIResources(namespace string, csv *operatorsv1alpha1.ClusterServiceVersion, desc operatorsv1alpha1.APIServiceDescription, c operatorclient.ClientInterface) {
  4577  
  4578  	apiServiceName := fmt.Sprintf("%s.%s", desc.Version, desc.Group)
  4579  
  4580  	// Attempt to create the legacy service
  4581  	service := corev1.Service{}
  4582  	service.SetName(strings.Replace(apiServiceName, ".", "-", -1))
  4583  	service.SetNamespace(namespace)
  4584  	if csv != nil {
  4585  		err := ownerutil.AddOwnerLabels(&service, csv)
  4586  		Expect(err).ShouldNot(HaveOccurred())
  4587  	}
  4588  
  4589  	service.Spec.Ports = []corev1.ServicePort{{Port: 433, TargetPort: intstr.FromInt(443)}}
  4590  	_, err := c.CreateService(&service)
  4591  	Expect(err).ShouldNot(HaveOccurred())
  4592  
  4593  	// Attempt to create the legacy secret
  4594  	secret := corev1.Secret{}
  4595  	secret.SetName(apiServiceName + "-cert")
  4596  	secret.SetNamespace(namespace)
  4597  	if csv != nil {
  4598  		err = ownerutil.AddOwnerLabels(&secret, csv)
  4599  		Expect(err).ShouldNot(HaveOccurred())
  4600  	}
  4601  
  4602  	_, err = c.CreateSecret(&secret)
  4603  	if err != nil && !apierrors.IsAlreadyExists(err) {
  4604  		Expect(err).ShouldNot(HaveOccurred())
  4605  	}
  4606  
  4607  	// Attempt to create the legacy secret role
  4608  	role := rbacv1.Role{}
  4609  	role.SetName(apiServiceName + "-cert")
  4610  	role.SetNamespace(namespace)
  4611  	if csv != nil {
  4612  		err = ownerutil.AddOwnerLabels(&role, csv)
  4613  		Expect(err).ShouldNot(HaveOccurred())
  4614  	}
  4615  	_, err = c.CreateRole(&role)
  4616  	Expect(err).ShouldNot(HaveOccurred())
  4617  
  4618  	// Attempt to create the legacy secret role binding
  4619  	roleBinding := rbacv1.RoleBinding{}
  4620  	roleBinding.SetName(apiServiceName + "-cert")
  4621  	roleBinding.SetNamespace(namespace)
  4622  	roleBinding.RoleRef = rbacv1.RoleRef{
  4623  		APIGroup: "rbac.authorization.k8s.io",
  4624  		Kind:     "Role",
  4625  		Name:     role.GetName(),
  4626  	}
  4627  	if csv != nil {
  4628  		err = ownerutil.AddOwnerLabels(&roleBinding, csv)
  4629  		Expect(err).ShouldNot(HaveOccurred())
  4630  	}
  4631  
  4632  	_, err = c.CreateRoleBinding(&roleBinding)
  4633  	Expect(err).ShouldNot(HaveOccurred())
  4634  
  4635  	// Attempt to create the legacy authDelegatorClusterRoleBinding
  4636  	clusterRoleBinding := rbacv1.ClusterRoleBinding{}
  4637  	clusterRoleBinding.SetName(apiServiceName + "-system:auth-delegator")
  4638  	clusterRoleBinding.RoleRef = rbacv1.RoleRef{
  4639  		APIGroup: "rbac.authorization.k8s.io",
  4640  		Kind:     "ClusterRole",
  4641  		Name:     "system:auth-delegator",
  4642  	}
  4643  	if csv != nil {
  4644  		err = ownerutil.AddOwnerLabels(&clusterRoleBinding, csv)
  4645  		Expect(err).ShouldNot(HaveOccurred())
  4646  	}
  4647  	_, err = c.CreateClusterRoleBinding(&clusterRoleBinding)
  4648  	Expect(err).ShouldNot(HaveOccurred())
  4649  
  4650  	// Attempt to create the legacy authReadingRoleBinding
  4651  	roleBinding.SetName(apiServiceName + "-auth-reader")
  4652  	roleBinding.SetNamespace("kube-system")
  4653  	roleBinding.RoleRef = rbacv1.RoleRef{
  4654  		APIGroup: "rbac.authorization.k8s.io",
  4655  		Kind:     "Role",
  4656  		Name:     "extension-apiserver-authentication-reader",
  4657  	}
  4658  	_, err = c.CreateRoleBinding(&roleBinding)
  4659  	Expect(err).ShouldNot(HaveOccurred())
  4660  }
  4661  
  4662  func checkLegacyAPIResources(namespace string, desc operatorsv1alpha1.APIServiceDescription, expectedIsNotFound bool, c operatorclient.ClientInterface) {
  4663  	apiServiceName := fmt.Sprintf("%s.%s", desc.Version, desc.Group)
  4664  
  4665  	// Attempt to create the legacy service
  4666  	_, err := c.GetService(namespace, strings.Replace(apiServiceName, ".", "-", -1))
  4667  	Expect(apierrors.IsNotFound(err)).Should(Equal(expectedIsNotFound))
  4668  
  4669  	// Attempt to create the legacy secret
  4670  	_, err = c.GetSecret(namespace, apiServiceName+"-cert")
  4671  	Expect(apierrors.IsNotFound(err)).Should(Equal(expectedIsNotFound))
  4672  
  4673  	// Attempt to create the legacy secret role
  4674  	_, err = c.GetRole(namespace, apiServiceName+"-cert")
  4675  	Expect(apierrors.IsNotFound(err)).Should(Equal(expectedIsNotFound))
  4676  
  4677  	// Attempt to create the legacy secret role binding
  4678  	_, err = c.GetRoleBinding(namespace, apiServiceName+"-cert")
  4679  	Expect(apierrors.IsNotFound(err)).Should(Equal(expectedIsNotFound))
  4680  
  4681  	// Attempt to create the legacy authDelegatorClusterRoleBinding
  4682  	_, err = c.GetClusterRoleBinding(apiServiceName + "-system:auth-delegator")
  4683  	Expect(apierrors.IsNotFound(err)).Should(Equal(expectedIsNotFound))
  4684  
  4685  	// Attempt to create the legacy authReadingRoleBinding
  4686  	_, err = c.GetRoleBinding("kube-system", apiServiceName+"-auth-reader")
  4687  	Expect(apierrors.IsNotFound(err)).Should(Equal(expectedIsNotFound))
  4688  }